Skip to content

Commit ca70cd7

Browse files
refactor: use impl_hook! for write and implement special facade in write.rs
Move the stdout/stderr bypass logic from a custom hook in hook/src/syscall/unix.rs to a specialized facade in core/src/syscall/unix/write.rs per maintainer feedback. - hook/src/syscall/unix.rs: Use standard impl_hook!(WRITE, write(...)) macro - core/src/syscall/unix/write.rs: Replace generic impl_facade! with a custom WriteSyscallFacade that bypasses state transitions and logging for: - stdout(fd=1)/stderr(fd=2) writes (triggered by logging framework) - writes during in_facade() re-entrancy (prevents recursive facade entry) Agent-Logs-Url: https://github.com/acl-dev/open-coroutine/sessions/6a64e463-d9fb-4d2f-9e86-284f579ee741 Co-authored-by: loongs-zhang <38336731+loongs-zhang@users.noreply.github.com>
1 parent 4675117 commit ca70cd7

2 files changed

Lines changed: 58 additions & 38 deletions

File tree

core/src/syscall/unix/write.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,62 @@ 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内部的info!()会再次
20+
//触发write导致stdout RefCell重复借用(无限递归)。
21+
// The write facade needs special handling: writes to stdout/stderr are
22+
// triggered by the logging framework (tracing). They must skip state
23+
// transitions and logging, going directly to the inner layer. Otherwise
24+
// the facade's info!() would re-trigger write, causing stdout's RefCell
25+
// to be double-borrowed (infinite recursion).
26+
#[repr(C)]
27+
#[derive(Debug, Default)]
28+
struct WriteSyscallFacade<I: WriteSyscall> {
29+
inner: I,
30+
}
31+
32+
impl<I: WriteSyscall> WriteSyscall for WriteSyscallFacade<I> {
33+
extern "C" fn write(
34+
&self,
35+
fn_ptr: Option<&extern "C" fn(c_int, *const c_void, size_t) -> ssize_t>,
36+
fd: c_int,
37+
buf: *const c_void,
38+
len: size_t,
39+
) -> ssize_t {
40+
// stdout(1)/stderr(2)由日志框架触发,或已在facade内部(防重入),
41+
// 直接调用内层跳过状态转换和日志记录
42+
// Bypass state transitions for stdout/stderr (logging fds) and
43+
// when already inside a facade (re-entrancy guard)
44+
if fd == libc::STDOUT_FILENO
45+
|| fd == libc::STDERR_FILENO
46+
|| crate::syscall::in_facade()
47+
{
48+
return self.inner.write(fn_ptr, fd, buf, len);
49+
}
50+
let syscall = crate::common::constants::SyscallName::write;
51+
crate::syscall::set_in_facade(true);
52+
crate::info!("enter syscall {}", syscall);
53+
if let Some(co) = crate::scheduler::SchedulableCoroutine::current() {
54+
let new_state = crate::common::constants::SyscallState::Executing;
55+
if co.syscall((), syscall, new_state).is_err() {
56+
crate::error!("{} change to syscall {} {} failed !",
57+
co.name(), syscall, new_state
58+
);
59+
}
60+
}
61+
crate::syscall::set_in_facade(false);
62+
let r = self.inner.write(fn_ptr, fd, buf, len);
63+
crate::syscall::set_in_facade(true);
64+
if let Some(co) = crate::scheduler::SchedulableCoroutine::current() {
65+
if co.running().is_err() {
66+
crate::error!("{} change to running state failed !", co.name());
67+
}
68+
}
69+
crate::info!("exit syscall {} {:?} {}", syscall, r, std::io::Error::last_os_error());
70+
crate::syscall::set_in_facade(false);
71+
r
72+
}
73+
}
2174

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

hook/src/syscall/unix.rs

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -82,41 +82,8 @@ impl_hook!(RENAMEAT2, renameat2(olddirfd: c_int, oldpath: *const c_char, newdirf
8282
// NOTE: unhook poll due to mio's poller
8383
// impl_hook!(POLL, poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int);
8484

85-
// NOTE: unhook write/pthread_mutex_lock/pthread_mutex_unlock due to stack overflow or bug
85+
// NOTE: unhook pthread_mutex_lock/pthread_mutex_unlock due to bug
8686
// impl_hook!(PTHREAD_MUTEX_LOCK, pthread_mutex_lock(lock: *mut pthread_mutex_t) -> c_int);
8787
// impl_hook!(PTHREAD_MUTEX_UNLOCK, pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> c_int);
8888

89-
//write需要特殊的hook实现:stdout/stderr的write由日志框架触发,
90-
//必须绕过facade直接调用原始write,否则facade内部的info!()会再次
91-
//触发write导致stdout RefCell重复借用。其他fd正常走facade。
92-
// write needs a custom hook: writes to stdout/stderr are triggered by
93-
// the logging framework. They must bypass the facade and call raw write
94-
// directly; otherwise the facade's info!() would re-trigger write,
95-
// causing stdout's RefCell to be double-borrowed. Other fds go through
96-
// the facade normally.
97-
#[no_mangle]
98-
pub extern "C" fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t {
99-
static WRITE: once_cell::sync::Lazy<extern "C" fn(c_int, *const c_void, size_t) -> ssize_t> =
100-
once_cell::sync::Lazy::new(|| unsafe {
101-
let symbol = std::ffi::CString::new("write")
102-
.unwrap_or_else(|_| panic!("can not transfer \"write\" to CString"));
103-
let ptr = libc::dlsym(libc::RTLD_NEXT, symbol.as_ptr());
104-
assert!(!ptr.is_null(), "syscall \"write\" not found !");
105-
std::mem::transmute(ptr)
106-
});
107-
let fn_ptr = once_cell::sync::Lazy::force(&WRITE);
108-
// stdout(1)/stderr(2)的write由日志框架触发,必须绕过facade
109-
// Bypass facade for stdout/stderr — these are logging fds
110-
if fd == libc::STDOUT_FILENO || fd == libc::STDERR_FILENO
111-
|| open_coroutine_core::syscall::in_facade()
112-
{
113-
return (fn_ptr)(fd, buf, count);
114-
}
115-
if crate::hook()
116-
|| open_coroutine_core::scheduler::SchedulableCoroutine::current().is_some()
117-
|| cfg!(feature = "ci")
118-
{
119-
return open_coroutine_core::syscall::write(Some(fn_ptr), fd, buf, count);
120-
}
121-
(fn_ptr)(fd, buf, count)
122-
}
89+
impl_hook!(WRITE, write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t);

0 commit comments

Comments
 (0)