diff --git a/src/data.rs b/src/data.rs index ee75c0593f..b6b261f21c 100644 --- a/src/data.rs +++ b/src/data.rs @@ -107,22 +107,21 @@ impl DerefMut for Packet { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default, PartialEq)] #[repr(C)] pub struct SigAction { - pub sa_handler: extern "C" fn(usize), + pub sa_handler: Option, pub sa_mask: [u64; 2], pub sa_flags: usize, } -impl Default for SigAction { - fn default() -> Self { - Self { - sa_handler: unsafe { mem::transmute(0usize) }, - sa_mask: [0; 2], - sa_flags: 0, - } - } +#[allow(dead_code)] +unsafe fn _assert_size_of_function_is_sane() { + // Transmuting will complain *at compile time* if sizes differ. + // Rust forbids a fn-pointer from being 0 so to allow SIG_DFL to + // exist, we use Option which will mean 0 + // becomes None + let _ = mem::transmute::, usize>(None); } #[derive(Copy, Clone, Debug, Default, PartialEq)] diff --git a/src/tests.rs b/src/tests.rs index 03273d436c..e2a79058ee 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -409,3 +409,62 @@ fn unlink() { fn sched_yield() { assert_eq!(dbg!(crate::sched_yield()), Ok(0)); } + +#[test] +fn sigaction() { + use std::{ + mem, + sync::atomic::{AtomicBool, Ordering} + }; + + let child = unsafe { dbg!(crate::clone(0)).unwrap() }; + + if child == 0 { + static SA_HANDLER_WAS_RAN: AtomicBool = AtomicBool::new(false); + + let pid = dbg!(crate::getpid()).unwrap(); + + extern "C" fn hello_im_a_signal_handler(signal: usize) { + assert_eq!(dbg!(signal), crate::SIGUSR1); + SA_HANDLER_WAS_RAN.store(true, Ordering::SeqCst); + } + + let my_signal_handler = crate::SigAction { + sa_handler: Some(hello_im_a_signal_handler), + ..Default::default() + }; + dbg!(crate::sigaction(crate::SIGUSR1, Some(&my_signal_handler), None)).unwrap(); + + dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // calls handler + + let mut old_signal_handler = crate::SigAction::default(); + dbg!(crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_IGN) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + )).unwrap(); + assert_eq!(my_signal_handler, old_signal_handler); + + dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // does nothing + + dbg!(crate::sigaction( + crate::SIGUSR1, + Some(&crate::SigAction { + sa_handler: unsafe { mem::transmute::>(crate::SIG_DFL) }, + ..Default::default() + }), + Some(&mut old_signal_handler) + )).unwrap(); + + dbg!(crate::kill(pid, crate::SIGUSR1)).unwrap(); // actually exits + } else { + let mut status = 0; + dbg!(crate::waitpid(child, &mut status, 0)).unwrap(); + + assert!(crate::wifsignaled(status)); + assert_eq!(crate::wtermsig(status), crate::SIGUSR1); + } +}