From 7d562920c2fbf1341ed1ac0459ff69474c56d726 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 20 Jun 2024 14:21:11 +0200 Subject: [PATCH] Add sigaction boilerplate. --- redox-rt/src/signal.rs | 84 ++++++++++++++++++++++++++++-------- src/header/signal/redox.rs | 16 +++---- src/platform/redox/signal.rs | 58 +++++++++++++++++++++++-- 3 files changed, 128 insertions(+), 30 deletions(-) diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 0d628506..676f839b 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::Cell; use core::ffi::c_int; use core::sync::atomic::{AtomicU64, Ordering}; -use syscall::{Result, Sigcontrol, SIGCHLD, SIGCONT, SIGURG, SIGWINCH}; +use syscall::{Error, Result, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH}; use crate::arch::*; use crate::sync::Mutex; @@ -101,6 +101,54 @@ fn modify_sigmask(old: Option<&mut u64>, op: Option<impl FnMut(u32, bool) -> u32 Ok(()) } +#[derive(Clone, Copy)] +pub enum Sigaction { + Default, + Ignore, + Handled { + handler: SignalHandler, + mask: u64, + flags: SigactionFlags, + }, +} +pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction>) -> Result<()> { + if matches!(usize::from(signal), 0 | 32 | SIGKILL | SIGSTOP | 65..) { + return Err(Error::new(EINVAL)); + } + + let _sigguard = tmp_disable_signals(); + let ctl = current_sigctl(); + let guard = SIGACTIONS.lock(); + let old_ignmask = IGNMASK.load(Ordering::Relaxed); + + if let Some(old) = old { + } + + let Some(new) = new else { + return Ok(()); + }; + + match (usize::from(signal), new) { + (_, Sigaction::Ignore) | (SIGCHLD | SIGURG | SIGWINCH, Sigaction::Default) => { + IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed); + + // mark the signal as masked + ctl.word[usize::from(signal) / 32].fetch_or(1 << ((signal - 1) % 32), Ordering::Relaxed); + + // POSIX specifies that pending signals shall be discarded if set to SIG_IGN by + // sigaction. + // TODO: handle tmp_disable_signals + } + (SIGTSTP, Sigaction::Default) => (), // stop + (SIGTTIN, Sigaction::Default) => (), // stop + (SIGTTOU, Sigaction::Default) => (), // stop + (_, Sigaction::Default) => (), + (_, Sigaction::Handled { .. }) => (), + } + + todo!() +} + extern "C" { pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol; } @@ -137,16 +185,18 @@ impl Drop for TmpDisableSignalsGuard { } } -#[derive(Clone, Copy)] -struct SignalAction { - handler: SignalHandler, - flags: SigactionFlags, - mask: u64, -} bitflags::bitflags! { + // Some flags are ignored by the rt, but they match relibc's 1:1 to simplify conversion. #[derive(Clone, Copy)] - struct SigactionFlags: u32 { - const SA_RESETHAND = 1; + 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; } } fn default_term_handler(sig: c_int) { @@ -161,22 +211,18 @@ fn stop_handler_sentinel(_: c_int) { } #[derive(Clone, Copy)] -union SignalHandler { - sa_handler: Option<extern "C" fn(c_int)>, - sa_sigaction: Option<unsafe extern "C" fn(c_int, *const (), *mut ())>, +pub union SignalHandler { + pub handler: Option<extern "C" fn(c_int)>, + pub sigaction: Option<unsafe extern "C" fn(c_int, *const (), *mut ())>, } struct TheDefault { - actions: [SignalAction; 64], + actions: [Sigaction; 64], ignmask: u64, } -static SIGACTIONS: Mutex<[SignalAction; 64]> = Mutex::new([SignalAction { - handler: SignalHandler { sa_handler: None }, - flags: SigactionFlags::empty(), - mask: 0, -}; 64]); -static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH) | sig_bit(SIGCONT)); +static SIGACTIONS: Mutex<[Sigaction; 64]> = Mutex::new([Sigaction::Default; 64]); +static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH)); fn expand_mask(mask: u64) -> [u64; 2] { [mask & 0xffff_ffff, mask >> 32] diff --git a/src/header/signal/redox.rs b/src/header/signal/redox.rs index f146dcda..f21c168e 100644 --- a/src/header/signal/redox.rs +++ b/src/header/signal/redox.rs @@ -69,14 +69,14 @@ pub const NSIG: usize = 32; pub const SIGRTMIN: usize = 35; pub const SIGRTMAX: usize = 64; -pub const SA_NOCLDSTOP: usize = 0x00000001; -pub const SA_NOCLDWAIT: usize = 0x00000002; -pub const SA_SIGINFO: usize = 0x00000004; -pub const SA_RESTORER: usize = 0x04000000; -pub const SA_ONSTACK: usize = 0x08000000; -pub const SA_RESTART: usize = 0x10000000; -pub const SA_NODEFER: usize = 0x40000000; -pub const SA_RESETHAND: usize = 0x80000000; +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 SS_ONSTACK: usize = 0x00000001; pub const SS_DISABLE: usize = 0x00000002; diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index f8f82a8d..625ac730 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -1,4 +1,5 @@ use core::mem; +use redox_rt::signal::{Sigaction, SigactionFlags, SignalHandler}; use syscall::{self, Result}; use super::{ @@ -8,7 +9,7 @@ use super::{ use crate::{ header::{ errno::{EINVAL, ENOSYS}, - signal::{sigaction, siginfo_t, sigset_t, stack_t, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK}, + signal::{sigaction, siginfo_t, sigset_t, stack_t, SA_SIGINFO, SIG_BLOCK, SIG_DFL, SIG_IGN, SIG_SETMASK, SIG_UNBLOCK}, sys_time::{itimerval, ITIMER_REAL}, time::timespec, }, @@ -104,8 +105,59 @@ impl PalSignal for Sys { 0 } - fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> Result<(), Errno> { - todo!() + fn sigaction(sig: c_int, c_act: Option<&sigaction>, c_oact: Option<&mut sigaction>) -> Result<(), Errno> { + let sig = u8::try_from(sig).map_err(|_| syscall::Error::new(syscall::EINVAL))?; + + let new_action = c_act.map(|c_act| { + let handler = c_act.sa_handler.map_or(0, |f| f as usize); + + if handler == SIG_DFL { + Sigaction::Default + } else if handler == SIG_IGN { + Sigaction::Ignore + } else { + Sigaction::Handled { + handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as u64 != 0 { + SignalHandler { sigaction: unsafe { core::mem::transmute(c_act.sa_handler) } } + } else { + SignalHandler { handler: c_act.sa_handler } + }, + mask: c_act.sa_mask, + flags: SigactionFlags::from_bits_retain(c_act.sa_flags as u32), + } + } + }); + let mut old_action = c_oact.as_ref().map(|_| Sigaction::Default); + + redox_rt::signal::sigaction(sig, new_action.as_ref(), old_action.as_mut())?; + + if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) { + *c_oact = match old_action { + Sigaction::Ignore => sigaction { + sa_handler: unsafe { core::mem::transmute(SIG_IGN) }, + sa_flags: 0, + sa_restorer: None, + sa_mask: 0, + }, + Sigaction::Default => sigaction { + sa_handler: unsafe { core::mem::transmute(SIG_DFL) }, + sa_flags: 0, + sa_restorer: None, + sa_mask: 0, + }, + Sigaction::Handled { handler, mask, flags } => sigaction { + sa_handler: if flags.contains(SigactionFlags::SIGINFO) { + unsafe { core::mem::transmute(handler.sigaction) } + } else { + unsafe { handler.handler } + }, + sa_restorer: None, + sa_flags: flags.bits().into(), + sa_mask: mask, + }, + }; + } + Ok(()) } unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { -- GitLab