From 8e5ddbd6547d44e4fdde5a50fb92b693f9dd16e0 Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Sun, 4 Aug 2024 18:31:24 +0200
Subject: [PATCH] Implement sigsuspend.

---
 redox-rt/src/signal.rs       | 27 +++++++++++++++++++++++----
 src/header/signal/mod.rs     |  2 +-
 src/platform/linux/signal.rs |  6 ++++--
 src/platform/pal/signal.rs   |  2 +-
 src/platform/redox/signal.rs | 19 +++++--------------
 5 files changed, 34 insertions(+), 22 deletions(-)

diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs
index 73e26ba02..ce2a4344d 100644
--- a/redox-rt/src/signal.rs
+++ b/redox-rt/src/signal.rs
@@ -657,11 +657,30 @@ pub unsafe fn sigaltstack(
 
 pub const MIN_SIGALTSTACK_SIZE: usize = 8192;
 
-pub fn currently_pending() -> u64 {
+pub fn currently_pending_blocked() -> u64 {
     let control = &unsafe { Tcb::current().unwrap() }.os_specific.control;
     let w0 = control.word[0].load(Ordering::Relaxed);
     let w1 = control.word[1].load(Ordering::Relaxed);
-    let pending_blocked_lo = w0 & !(w0 >> 32);
-    let pending_unblocked_hi = w1 & !(w0 >> 32);
-    pending_blocked_lo | (pending_unblocked_hi << 32)
+    let allow = (w0 >> 32) | ((w1 >> 32) << 32);
+    let thread_pending = (w0 & 0xffff_ffff) | ((w1 >> 32) & 0xffff_ffff);
+    let proc_pending = PROC_CONTROL_STRUCT.pending.load(Ordering::Relaxed);
+
+    core::sync::atomic::fence(Ordering::Acquire); // TODO: Correct ordering?
+
+    (thread_pending | proc_pending) & !allow
+}
+pub enum Unreachable {}
+pub fn wait_with_mask(mask: u64) -> Result<Unreachable, Error> {
+    let mut old = 0;
+    set_sigmask(Some(mask), Some(&mut old))?;
+    let res = syscall::nanosleep(
+        &syscall::TimeSpec {
+            tv_sec: i64::MAX,
+            tv_nsec: 0,
+        },
+        &mut syscall::TimeSpec::default(),
+    );
+    set_sigmask(Some(old), None)?;
+    res?;
+    unreachable!()
 }
diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs
index 6fe93ed26..5a4e4f252 100644
--- a/src/header/signal/mod.rs
+++ b/src/header/signal/mod.rs
@@ -359,7 +359,7 @@ pub unsafe extern "C" fn sigset(
 
 #[no_mangle]
 pub unsafe extern "C" fn sigsuspend(sigmask: *const sigset_t) -> c_int {
-    Sys::sigsuspend(&*sigmask)
+    Err(Sys::sigsuspend(&*sigmask)).or_minus_one_errno()
 }
 
 #[no_mangle]
diff --git a/src/platform/linux/signal.rs b/src/platform/linux/signal.rs
index a6ec22fb3..7d0f4990a 100644
--- a/src/platform/linux/signal.rs
+++ b/src/platform/linux/signal.rs
@@ -155,8 +155,10 @@ impl PalSignal for Sys {
         .map(|_| ())
     }
 
-    fn sigsuspend(set: &sigset_t) -> c_int {
-        unsafe { e(syscall!(RT_SIGSUSPEND, set as *const sigset_t, NSIG / 8)) as c_int }
+    fn sigsuspend(set: &sigset_t) -> Errno {
+        unsafe {
+            e_raw(syscall!(RT_SIGSUSPEND, set as *const sigset_t, NSIG / 8)).expect_err("must fail")
+        }
     }
 
     unsafe fn sigtimedwait(
diff --git a/src/platform/pal/signal.rs b/src/platform/pal/signal.rs
index b00525a83..690ecdf38 100644
--- a/src/platform/pal/signal.rs
+++ b/src/platform/pal/signal.rs
@@ -37,7 +37,7 @@ pub trait PalSignal: Pal {
         oset: Option<&mut sigset_t>,
     ) -> Result<(), Errno>;
 
-    fn sigsuspend(set: &sigset_t) -> c_int;
+    fn sigsuspend(set: &sigset_t) -> Errno; // always fails
 
     unsafe fn sigtimedwait(set: *const sigset_t, sig: *mut siginfo_t, tp: *const timespec)
         -> c_int;
diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs
index de89f5845..fab3e5641 100644
--- a/src/platform/redox/signal.rs
+++ b/src/platform/redox/signal.rs
@@ -246,7 +246,7 @@ impl PalSignal for Sys {
     }
 
     fn sigpending(set: &mut sigset_t) -> Result<(), Errno> {
-        *set = redox_rt::signal::currently_pending();
+        *set = redox_rt::signal::currently_pending_blocked();
         Ok(())
     }
 
@@ -264,20 +264,11 @@ impl PalSignal for Sys {
         })
     }
 
-    fn sigsuspend(set: &sigset_t) -> c_int {
-        //TODO: correct implementation
-        let mut oset = sigset_t::default();
-        if let Err(err) = redox_rt::signal::set_sigmask(Some(*set), Some(&mut oset)) {
-            Errno::from(err).sync();
-            return -1;
-        }
-        //TODO: wait for signal
-        Self::sched_yield();
-        if let Err(err) = redox_rt::signal::set_sigmask(Some(oset), None) {
-            Errno::from(err).sync();
-            return -1;
+    fn sigsuspend(set: &sigset_t) -> Errno {
+        match redox_rt::signal::wait_with_mask(*set) {
+            Ok(_) => unreachable!(),
+            Err(err) => err.into(),
         }
-        0
     }
 
     unsafe fn sigtimedwait(
-- 
GitLab