From 2b7a1ea94bf8431b084c0056eb2e7e2dfce9f9a2 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 4 Aug 2024 23:02:04 +0200 Subject: [PATCH] Fix sigsuspend and add it to the sigqueue test. --- redox-rt/src/signal.rs | 34 +++++++++++++++++++++++++++------- src/header/signal/mod.rs | 11 +++++++++-- src/platform/linux/signal.rs | 6 +++--- src/platform/pal/signal.rs | 2 +- src/platform/redox/signal.rs | 8 ++++---- tests/sigqueue.c | 32 +++++++++++++++++++++++++------- 6 files changed, 69 insertions(+), 24 deletions(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index e041bfd3d7..345232cad2 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -673,10 +673,13 @@ pub fn currently_pending_blocked() -> u64 { } pub enum Unreachable {} -pub fn await_signal_async(set: u64) -> Result { - let mut old = 0; - set_sigmask(Some(!set), Some(&mut old))?; - // TODO: RAII guard +pub fn await_signal_async(inner_allowset: u64) -> Result { + let _guard = tmp_disable_signals(); + let control = &unsafe { Tcb::current().unwrap() }.os_specific.control; + + let old_allowset = get_allowset_raw(&control.word); + set_allowset_raw(&control.word, old_allowset, inner_allowset); + let res = syscall::nanosleep( &TimeSpec { tv_sec: i64::MAX, @@ -684,12 +687,19 @@ pub fn await_signal_async(set: u64) -> Result { }, &mut TimeSpec::default(), ); - set_sigmask(Some(old), None)?; + set_allowset_raw(&control.word, inner_allowset, old_allowset); + + if res == Err(Error::new(EINTR)) { + unsafe { + manually_enter_trampoline(); + } + } + res?; unreachable!() } // TODO: deadline-based API -pub fn await_signal_sync(inner_allowset: u64, timeout: &TimeSpec) -> Result { +pub fn await_signal_sync(inner_allowset: u64, timeout: Option<&TimeSpec>) -> Result { let _guard = tmp_disable_signals(); let control = &unsafe { Tcb::current().unwrap() }.os_specific.control; @@ -704,7 +714,17 @@ pub fn await_signal_sync(inner_allowset: u64, timeout: &TimeSpec) -> Result syscall::nanosleep(&t, &mut TimeSpec::default()), + None => syscall::nanosleep( + &TimeSpec { + tv_sec: i64::MAX, + tv_nsec: 0, + }, + &mut TimeSpec::default(), + ), + }; + let thread_pending = set_allowset_raw(&control.word, inner_allowset, old_allowset); let proc_pending = PROC_CONTROL_STRUCT.pending.load(Ordering::Acquire); diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs index 930e66b6e7..dbd6d69ced 100644 --- a/src/header/signal/mod.rs +++ b/src/header/signal/mod.rs @@ -380,13 +380,20 @@ pub unsafe extern "C" fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int #[no_mangle] pub unsafe extern "C" fn sigtimedwait( set: *const sigset_t, - sig: *mut siginfo, // https://github.com/mozilla/cbindgen/issues/621 + // s/siginfo_t/siginfo due to https://github.com/mozilla/cbindgen/issues/621 + sig: *mut siginfo, + // POSIX leaves behavior unspecified if this is NULL, but on both Linux and Redox, NULL is used + // to differentiate between sigtimedwait and sigwaitinfo internally tp: *const timespec, ) -> c_int { - Sys::sigtimedwait(&*set, sig.as_mut(), &*tp) + Sys::sigtimedwait(&*set, sig.as_mut(), tp.as_ref()) .map(|()| 0) .or_minus_one_errno() } +#[no_mangle] +pub unsafe extern "C" fn sigwaitinfo(set: *const sigset_t, sig: *mut siginfo_t) -> c_int { + sigtimedwait(set, sig, core::ptr::null()) +} pub const _signal_strings: [&str; 32] = [ "Unknown signal\0", diff --git a/src/platform/linux/signal.rs b/src/platform/linux/signal.rs index f772988a02..7a379e06af 100644 --- a/src/platform/linux/signal.rs +++ b/src/platform/linux/signal.rs @@ -165,14 +165,14 @@ impl PalSignal for Sys { fn sigtimedwait( set: &sigset_t, sig: Option<&mut siginfo_t>, - tp: ×pec, + tp: Option<×pec>, ) -> Result<(), Errno> { unsafe { e_raw(syscall!( RT_SIGTIMEDWAIT, set as *const _, - sig.map_or_else(core::ptr::null_mut, |s| s as *mut _) as usize, - tp as *const _, + sig.map_or_else(core::ptr::null_mut, |s| s as *mut _), + tp.map_or_else(core::ptr::null, |t| t as *const _), NSIG / 8 )) .map(|_| ()) diff --git a/src/platform/pal/signal.rs b/src/platform/pal/signal.rs index 4d2dbb6ff3..7a01780ac1 100644 --- a/src/platform/pal/signal.rs +++ b/src/platform/pal/signal.rs @@ -42,6 +42,6 @@ pub trait PalSignal: Pal { fn sigtimedwait( set: &sigset_t, sig: Option<&mut siginfo_t>, - tp: ×pec, + tp: Option<×pec>, ) -> Result<(), Errno>; } diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index a5f0c10509..0ae511bbec 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -274,14 +274,14 @@ impl PalSignal for Sys { fn sigtimedwait( set: &sigset_t, info_out: Option<&mut siginfo_t>, - timeout: ×pec, + timeout: Option<×pec>, ) -> Result<(), Errno> { // TODO: deadline-based API - let timeout = syscall::TimeSpec { + let timeout = timeout.map(|timeout| syscall::TimeSpec { tv_sec: timeout.tv_sec, tv_nsec: timeout.tv_nsec as _, - }; - let info = redox_rt::signal::await_signal_sync(*set, &timeout)?.into(); + }); + let info = redox_rt::signal::await_signal_sync(*set, timeout.as_ref())?.into(); if let Some(out) = info_out { *out = info; } diff --git a/tests/sigqueue.c b/tests/sigqueue.c index 78e4eeffd5..d4afe0a862 100644 --- a/tests/sigqueue.c +++ b/tests/sigqueue.c @@ -24,11 +24,11 @@ void validate(int sig, const siginfo_t *info) { } void action(int sig, siginfo_t *info, void *context) { - num++; (void)context; assert(context != NULL); validate(sig, info); write(1, "action\n", 7); + num++; } int main(void) { @@ -40,12 +40,6 @@ int main(void) { parent = getpid(); assert(parent != 0); - int child = fork(); - ERROR_IF(fork, child, == -1); - - status = close(fds[child == 0 ? 0 : 1]); - ERROR_IF(close, status, == -1); - sigset_t set, mask; status = sigfillset(&mask); ERROR_IF(sigfillset, status, == -1); @@ -67,6 +61,16 @@ int main(void) { status = sigaddset(&set, THE_SIG); ERROR_IF(sigaddset, status, == -1); + sigset_t empty_set; + status = sigemptyset(&empty_set); + ERROR_IF(sigemptyset, status, == -1); + + int child = fork(); + ERROR_IF(fork, child, == -1); + + status = close(fds[child == 0 ? 0 : 1]); + ERROR_IF(close, status, == -1); + struct sigaction sa; memcpy(&sa.sa_mask, &set, sizeof (sigset_t)); sa.sa_flags = SA_SIGINFO; @@ -84,6 +88,20 @@ int main(void) { validate(THE_SIG, &info); assert(num == 0); // ensure no signal handler ran + num++; + + // TODO: check status + status = sigsuspend(&empty_set); + if (status == -1) { + perror("error in sigsuspend"); + puts("[EINTR] is usually expected"); + } + + assert(num == 2); // ensure signal handler ran + + status = sigprocmask(SIG_SETMASK, &empty_set, NULL); + ERROR_IF(sigprocmask, status, == -1); + while (num < 31) {} status = write(fds[1], "A", 1);