Skip to content

Commit b5b85a0

Browse files
committed
hook write
1 parent 095427b commit b5b85a0

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

core/src/syscall/unix/write.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,52 @@ impl_syscall!(WriteSyscallFacade, IoUringWriteSyscall, NioWriteSyscall, RawWrite
1515
write(fd: c_int, buf: *const c_void, len: size_t) -> ssize_t
1616
);
1717

18-
impl_facade!(WriteSyscallFacade, WriteSyscall,
19-
write(fd: c_int, buf: *const c_void, len: size_t) -> ssize_t
20-
);
18+
//write的facade需要特殊处理:stdout/stderr的write由日志框架(tracing)触发,
19+
//必须跳过所有中间层(facade/io_uring/NIO)直接调用原始系统调用,否则:
20+
//1. facade内部的info!()会再次触发write导致stdout RefCell重复借用(无限递归)
21+
//2. io_uring层会提交写操作并阻塞在condvar等待完成,导致死锁
22+
// The write facade needs special handling: writes to stdout/stderr are
23+
// triggered by the logging framework (tracing). They must bypass ALL layers
24+
// (facade, io_uring, NIO) and call the raw syscall directly. Otherwise:
25+
// 1. The facade's info!() re-triggers write → stdout RefCell double-borrow
26+
// 2. The io_uring layer submits the write and blocks on condvar → deadlock
27+
#[repr(C)]
28+
#[derive(Debug, Default)]
29+
struct WriteSyscallFacade<I: WriteSyscall> {
30+
inner: I,
31+
}
32+
33+
impl<I: WriteSyscall> WriteSyscall for WriteSyscallFacade<I> {
34+
extern "C" fn write(
35+
&self,
36+
fn_ptr: Option<&extern "C" fn(c_int, *const c_void, size_t) -> ssize_t>,
37+
fd: c_int,
38+
buf: *const c_void,
39+
len: size_t,
40+
) -> ssize_t {
41+
let syscall = crate::common::constants::SyscallName::write;
42+
if let Some(co) = crate::scheduler::SchedulableCoroutine::current() {
43+
let new_state = crate::common::constants::SyscallState::Executing;
44+
if co.syscall((), syscall, new_state).is_err() {
45+
crate::error!("{} change to syscall {} {} failed !",
46+
co.name(), syscall, new_state
47+
);
48+
}
49+
}
50+
if fd == libc::STDOUT_FILENO || fd == libc::STDERR_FILENO {
51+
return RawWriteSyscall::default().write(fn_ptr, fd, buf, len);
52+
}
53+
crate::info!("enter syscall {}", syscall);
54+
let r = self.inner.write(fn_ptr, fd, buf, len);
55+
if let Some(co) = crate::scheduler::SchedulableCoroutine::current() {
56+
if co.running().is_err() {
57+
crate::error!("{} change to running state failed !", co.name());
58+
}
59+
}
60+
crate::info!("exit syscall {} {:?} {}", syscall, r, std::io::Error::last_os_error());
61+
r
62+
}
63+
}
2164

2265
impl_io_uring_write!(IoUringWriteSyscall, WriteSyscall,
2366
write(fd: c_int, buf: *const c_void, len: size_t) -> ssize_t

hook/src/syscall/unix.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ impl_hook!(PREADV, preadv(fd: c_int, iov: *const iovec, iovcnt: c_int, offset: o
6262
impl_hook!(RECVMSG, recvmsg(fd: c_int, msg: *mut msghdr, flags: c_int) -> ssize_t);
6363
impl_hook!(SEND, send(fd: c_int, buf: *const c_void, len: size_t, flags: c_int) -> ssize_t);
6464
impl_hook!(SENDTO, sendto(fd: c_int, buf: *const c_void, len: size_t, flags: c_int, addr: *const sockaddr, addrlen: socklen_t) -> ssize_t);
65+
impl_hook!(WRITE, write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t);
6566
impl_hook!(PWRITE, pwrite(fd: c_int, buf: *const c_void, count: size_t, offset: off_t) -> ssize_t);
6667
impl_hook!(WRITEV, writev(fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t);
6768
impl_hook!(PWRITEV, pwritev(fd: c_int, iov: *const iovec, iovcnt: c_int, offset: off_t) -> ssize_t);
@@ -82,7 +83,6 @@ impl_hook!(RENAMEAT2, renameat2(olddirfd: c_int, oldpath: *const c_char, newdirf
8283
// NOTE: unhook poll due to mio's poller
8384
// impl_hook!(POLL, poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int);
8485

85-
// NOTE: unhook write/pthread_mutex_lock/pthread_mutex_unlock due to stack overflow or bug
86-
// impl_hook!(WRITE, write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t);
86+
// NOTE: unhook pthread_mutex_lock/pthread_mutex_unlock due to stack overflow or bug
8787
// impl_hook!(PTHREAD_MUTEX_LOCK, pthread_mutex_lock(lock: *mut pthread_mutex_t) -> c_int);
8888
// impl_hook!(PTHREAD_MUTEX_UNLOCK, pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> c_int);

0 commit comments

Comments
 (0)