From 63509e75ce127fdb05c07a464e975687e8ef2977 Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Sat, 29 Jun 2024 14:01:38 +0200
Subject: [PATCH] Use new signal ABI where 'actions' are in shmem.

---
 redox-rt/src/arch/x86_64.rs |   4 +-
 redox-rt/src/signal.rs      | 163 ++++++++++++++++++++----------------
 src/header/signal/redox.rs  |  14 ++--
 3 files changed, 99 insertions(+), 82 deletions(-)

diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs
index b597928f..689b1ff8 100644
--- a/redox-rt/src/arch/x86_64.rs
+++ b/redox-rt/src/arch/x86_64.rs
@@ -317,9 +317,7 @@ __relibc_internal_sigentry_crit_second:
     tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch),
     tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
     supports_xsave = sym SUPPORTS_XSAVE,
-    SIGW0_PENDING_MASK = const !(
-        SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | SIGW0_NOCLDSTOP_BIT | SIGW0_UNUSED1 | SIGW0_UNUSED2
-    ),
+    SIGW0_PENDING_MASK = const !0,
     SIGW1_PENDING_MASK = const !0,
     REDZONE_SIZE = const 128,
     STACK_ALIGN = const 64, // if xsave is used
diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs
index 7c93c8a7..0e9eb427 100644
--- a/redox-rt/src/signal.rs
+++ b/redox-rt/src/signal.rs
@@ -1,8 +1,9 @@
 use core::cell::{Cell, UnsafeCell};
 use core::ffi::c_int;
-use core::sync::atomic::Ordering;
+use core::sync::atomic::{AtomicUsize, Ordering};
 
-use syscall::{Error, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_NOCLDSTOP_BIT, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH, data::AtomicU64};
+use syscall::{RawAction, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ};
+use syscall::{Error, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH, data::AtomicU64};
 
 use crate::{arch::*, Tcb};
 use crate::sync::Mutex;
@@ -57,11 +58,16 @@ unsafe fn inner(stack: &mut SigStack) {
     arch_pre(stack, &mut *os.arch.get());
 
     let sigaction = {
-        let mut guard = SIGACTIONS.lock();
-        let action = guard[stack.sig_num];
+        let mut guard = SIGACTIONS_LOCK.lock();
+        let action = convert_old(&PROC_CONTROL_STRUCT.actions[stack.sig_num - 1]);
         if action.flags.contains(SigactionFlags::RESETHAND) {
             // TODO: other things that must be set
-            guard[stack.sig_num].kind = SigactionKind::Default;
+            drop(guard);
+            sigaction(stack.sig_num as u8, Some(&Sigaction {
+                kind: SigactionKind::Default,
+                mask: 0,
+                flags: SigactionFlags::empty(),
+            }), None);
         }
         action
     };
@@ -191,6 +197,44 @@ pub struct Sigaction {
     pub mask: u64,
     pub flags: SigactionFlags,
 }
+impl Sigaction {
+    fn ip(&self) -> usize {
+        unsafe {
+            match self.kind {
+                SigactionKind::Handled { handler } => if self.flags.contains(SigactionFlags::SIGINFO) {
+                    handler.sigaction.map_or(0, |a| a as usize)
+                } else {
+                    handler.handler.map_or(0, |a| a as usize)
+                }
+                _ => 0,
+            }
+        }
+    }
+}
+
+const MASK_DONTCARE: u64 = !0;
+
+fn convert_old(action: &RawAction) -> Sigaction {
+    let old_first = action.first.load(Ordering::Relaxed);
+    let old_mask = action.user_data.load(Ordering::Relaxed);
+
+    let handler = (old_first & !(u64::from(STORED_FLAGS) << 32)) as usize;
+    let flags = SigactionFlags::from_bits_retain(((old_first >> 32) as u32) & STORED_FLAGS);
+
+    let kind = if handler == default_handler as usize {
+        SigactionKind::Default
+    } else if flags.contains(SigactionFlags::IGNORED) {
+        SigactionKind::Ignore
+    } else {
+        SigactionKind::Handled { handler: unsafe { core::mem::transmute(handler as usize) } }
+    };
+
+    Sigaction {
+        mask: old_mask,
+        flags,
+        kind,
+    }
+}
 
 pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction>) -> Result<()> {
     if matches!(usize::from(signal), 0 | 32 | SIGKILL | SIGSTOP | 65..) {
@@ -199,62 +243,46 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction
 
     let _sigguard = tmp_disable_signals();
     let ctl = current_sigctl();
-    let mut guard = SIGACTIONS.lock();
-    let old_ignmask = IGNMASK.load(Ordering::Relaxed);
+
+    let action = &PROC_CONTROL_STRUCT.actions[usize::from(signal) - 1];
 
     if let Some(old) = old {
-        *old = guard[usize::from(signal)];
+        *old = convert_old(action);
     }
 
     let Some(new) = new else {
         return Ok(());
     };
-    guard[usize::from(signal)] = *new;
 
-    let sig_group = usize::from(signal) / 32;
-    let sig_bit32 = 1 << ((signal - 1) % 32);
+    let explicit_handler = new.ip();
 
-    match (usize::from(signal), new.kind) {
+    let (mask, flags, handler) = match (usize::from(signal), new.kind) {
         (_, SigactionKind::Ignore) | (SIGURG | SIGWINCH, SigactionKind::Default) => {
-            IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed);
-
-            // mark the signal as masked
-            ctl.word[sig_group].fetch_and(!(sig_bit32 << 32), Ordering::Relaxed);
-
-            // POSIX specifies that pending signals shall be discarded if set to SIG_IGN by
+            // TODO: POSIX specifies that pending signals shall be discarded if set to SIG_IGN by
             // sigaction.
             // TODO: handle tmp_disable_signals
+            (MASK_DONTCARE, SigactionFlags::IGNORED, if matches!(new.kind, SigactionKind::Default) {
+                default_handler as usize
+            } else {
+                0
+            })
         }
         // TODO: Handle pending signals before these flags are set.
-        (SIGTSTP, SigactionKind::Default) => {
-            PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TSTP_IS_STOP_BIT, Ordering::SeqCst);
-        }
-        (SIGTTIN, SigactionKind::Default) => {
-            PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTIN_IS_STOP_BIT, Ordering::SeqCst);
-        }
-        (SIGTTOU, SigactionKind::Default) => {
-            PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_TTOU_IS_STOP_BIT, Ordering::SeqCst);
-        }
+        (SIGTSTP | SIGTTOU | SIGTTIN, SigactionKind::Default) => (MASK_DONTCARE, SigactionFlags::SIG_SPECIFIC, default_handler as usize),
         (SIGCHLD, SigactionKind::Default) => {
-            if new.flags.contains(SigactionFlags::NOCLDSTOP) {
-                PROC_CONTROL_STRUCT.word[0].fetch_or(SIGW0_NOCLDSTOP_BIT, Ordering::SeqCst);
-            } else {
-                PROC_CONTROL_STRUCT.word[0].fetch_and(!SIGW0_NOCLDSTOP_BIT, Ordering::SeqCst);
-            }
-            IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed);
-
-            // mark the signal as masked
-            ctl.word[sig_group].fetch_or(sig_bit32, Ordering::Relaxed);
+            let nocldstop_bit = new.flags & SigactionFlags::SIG_SPECIFIC;
+            (MASK_DONTCARE, SigactionFlags::IGNORED | nocldstop_bit, default_handler as usize)
         }
 
         (_, SigactionKind::Default) => {
-            IGNMASK.store(old_ignmask & !sig_bit(signal.into()), Ordering::Relaxed);
-
-            // TODO: update mask
-            //ctl.word[usize::from(signal)].fetch_or();
+            (new.mask, new.flags, default_handler as usize)
         },
-        (_, SigactionKind::Handled { .. }) => (),
-    }
+        (_, SigactionKind::Handled { .. }) => {
+            (new.mask, new.flags, explicit_handler)
+        }
+    };
+    action.first.store((handler as u64) | (u64::from(flags.bits() & STORED_FLAGS) << 32), Ordering::Relaxed);
+    action.user_data.store(mask, Ordering::Relaxed);
 
     Ok(())
 }
@@ -296,26 +324,23 @@ bitflags::bitflags! {
     // Some flags are ignored by the rt, but they match relibc's 1:1 to simplify conversion.
     #[derive(Clone, Copy, Default)]
     pub struct SigactionFlags: u32 {
-        const NOCLDSTOP = 1;
         const NOCLDWAIT = 2;
-        const SIGINFO = 4;
-        const RESTORER = 0x0400_0000;
-        const ONSTACK = 0x0800_0000;
-        const RESTART = 0x1000_0000;
-        const NODEFER = 0x4000_0000;
-        const RESETHAND = 0x8000_0000;
+        const RESTORER = 4;
+        const SIGINFO = 0x0200_0000;
+        const ONSTACK = 0x0400_0000;
+        const RESTART = 0x0800_0000;
+        const NODEFER = 0x1000_0000;
+        const RESETHAND = 0x2000_0000;
+        const SIG_SPECIFIC = 0x4000_0000;
+        const IGNORED = 0x8000_0000;
     }
 }
-fn default_term_handler(sig: c_int) {
-    syscall::exit((sig as usize) << 8);
-}
-fn default_core_handler(sig: c_int) {
+
+const STORED_FLAGS: u32 = 0xfe00_0000;
+
+fn default_handler(sig: c_int) {
     syscall::exit((sig as usize) << 8);
 }
-fn default_ign_handler(_: c_int) {
-}
-fn stop_handler_sentinel(_: c_int) {
-}
 
 #[derive(Clone, Copy)]
 pub union SignalHandler {
@@ -323,22 +348,16 @@ pub union SignalHandler {
     pub sigaction: Option<unsafe extern "C" fn(c_int, *const (), *mut ())>,
 }
 
-struct TheDefault {
-    actions: [Sigaction; 64],
-    ignmask: u64,
-}
-
-// indexed directly by signal number
-static SIGACTIONS: Mutex<[Sigaction; 64]> = Mutex::new([Sigaction { flags: SigactionFlags::empty(), mask: 0, kind: SigactionKind::Default }; 64]);
-
-static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH));
+static SIGACTIONS_LOCK: Mutex<()> = Mutex::new(());
 
 static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl {
-    word: [
-        //AtomicU64::new(SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | 0xffff_ffff_0000_0000),
-        AtomicU64::new(0xffff_ffff_0000_0000), // "allow all, no pending"
-        AtomicU64::new(0xffff_ffff_0000_0000), // "allow all, no pending"
-    ],
+    pending: AtomicU64::new(0),
+    actions: [const {
+        RawAction {
+            first: AtomicU64::new(0),
+            user_data: AtomicU64::new(0),
+        }
+    }; 64],
 };
 
 fn combine_allowset([lo, hi]: [u64; 2]) -> u64 {
@@ -353,7 +372,7 @@ const fn sig_bit(sig: usize) -> u64 {
 
 pub fn setup_sighandler(area: &RtSigarea) {
     {
-        let mut sigactions = SIGACTIONS.lock();
+        let mut sigactions = SIGACTIONS_LOCK.lock();
     }
     let arch = unsafe { &mut *area.arch.get() };
     {
diff --git a/src/header/signal/redox.rs b/src/header/signal/redox.rs
index 8e878dda..689b9da3 100644
--- a/src/header/signal/redox.rs
+++ b/src/header/signal/redox.rs
@@ -36,14 +36,14 @@ pub const NSIG: usize = 32;
 pub const SIGRTMIN: usize = 35;
 pub const SIGRTMAX: usize = 64;
 
-pub const SA_NOCLDSTOP: usize = 0x0000_0001;
 pub const SA_NOCLDWAIT: usize = 0x0000_0002;
-pub const SA_SIGINFO: usize = 0x0000_0004;
-pub const SA_RESTORER: usize = 0x0400_0000;
-pub const SA_ONSTACK: usize = 0x0800_0000;
-pub const SA_RESTART: usize = 0x1000_0000;
-pub const SA_NODEFER: usize = 0x4000_0000;
-pub const SA_RESETHAND: usize = 0x8000_0000;
+pub const SA_RESTORER: usize = 0x0000_0004; // TODO: remove
+pub const SA_SIGINFO: usize = 0x0200_0000;
+pub const SA_ONSTACK: usize = 0x0400_0000;
+pub const SA_RESTART: usize = 0x0800_0000;
+pub const SA_NODEFER: usize = 0x1000_0000;
+pub const SA_RESETHAND: usize = 0x2000_0000;
+pub const SA_NOCLDSTOP: usize = 0x4000_0000;
 
 pub const SS_ONSTACK: usize = 0x00000001;
 pub const SS_DISABLE: usize = 0x00000002;
-- 
GitLab