From 6bff42166472c929a3871e3f7f2a7bc4d9b77e6a Mon Sep 17 00:00:00 2001 From: Robert Gardner Date: Mon, 11 Dec 2017 00:14:35 -0800 Subject: [PATCH] Implement nix wrapper for libc::signal Closes #476 --- CHANGELOG.md | 2 ++ src/errno.rs | 4 +++ src/sys/signal.rs | 73 +++++++++++++++++++++++++++++++++++++++++ test/sys/test_signal.rs | 38 ++++++++++++++++++++- 4 files changed, 116 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4031b26f1..fda5b6905b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#997](https://github.com/nix-rust/nix/pull/997)) - Added `ptrace::{getregs, setregs}`. ([#1010](https://github.com/nix-rust/nix/pull/1010)) +- Added `nix::sys::signal::signal`. + ([#817](https://github.com/nix-rust/nix/pull/817)) ### Changed ### Fixed diff --git a/src/errno.rs b/src/errno.rs index 2f07a104f7..977ea0b64d 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -107,6 +107,10 @@ impl ErrnoSentinel for *mut c_void { fn sentinel() -> Self { (-1 as isize) as *mut c_void } } +impl ErrnoSentinel for libc::sighandler_t { + fn sentinel() -> Self { libc::SIG_ERR } +} + impl error::Error for Errno { fn description(&self) -> &str { self.desc() diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 7135b7334f..79a3ca1086 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -542,6 +542,79 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result Result { + let signal = signal as libc::c_int; + let res = match handler { + SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL), + SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN), + SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t), + SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation), + }; + Errno::result(res).map(|oldhandler| { + match oldhandler { + libc::SIG_DFL => SigHandler::SigDfl, + libc::SIG_IGN => SigHandler::SigIgn, + f => SigHandler::Handler(mem::transmute(f)), + } + }) +} + /// Manages the signal mask (set of blocked signals) for the calling thread. /// /// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set. diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs index c8dd977680..f5e4dfd9eb 100644 --- a/test/sys/test_signal.rs +++ b/test/sys/test_signal.rs @@ -1,5 +1,8 @@ -use nix::unistd::*; +use libc; +use nix::Error; use nix::sys::signal::*; +use nix::unistd::*; +use std::sync::atomic::{AtomicBool, Ordering}; #[test] fn test_kill_none() { @@ -60,3 +63,36 @@ fn test_sigprocmask() { sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None) .expect("expect to be able to block signals"); } + +lazy_static! { + static ref SIGNALED: AtomicBool = AtomicBool::new(false); +} + +extern fn test_sigaction_handler(signal: libc::c_int) { + let signal = Signal::from_c_int(signal).unwrap(); + SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); +} + +extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) { +} + +#[test] +fn test_signal() { + let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); + + unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); + raise(Signal::SIGINT).unwrap(); + assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigIgn); + + let handler = SigHandler::Handler(test_sigaction_handler); + assert_eq!(unsafe { signal(Signal::SIGINT, handler) }.unwrap(), SigHandler::SigDfl); + raise(Signal::SIGINT).unwrap(); + assert!(SIGNALED.load(Ordering::Relaxed)); + assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler); + + let action_handler = SigHandler::SigAction(test_sigaction_action); + assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation); + + // Restore default signal handler + unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); +}