diff options
author | Robert Gardner <bob.hn.gardner@gmail.com> | 2017-12-11 00:14:35 -0800 |
---|---|---|
committer | Bob Gardner <bob.hn.gardner@gmail.com> | 2019-01-13 11:56:22 -0800 |
commit | 6bff42166472c929a3871e3f7f2a7bc4d9b77e6a (patch) | |
tree | db8c7422a3e68b735a2828220158914d8a79afe9 /src | |
parent | 7f2ac636e9cf68d6836941b35ba0c4e9d43ae82f (diff) | |
download | nix-6bff42166472c929a3871e3f7f2a7bc4d9b77e6a.zip |
Implement nix wrapper for libc::signal
Closes #476
Diffstat (limited to 'src')
-rw-r--r-- | src/errno.rs | 4 | ||||
-rw-r--r-- | src/sys/signal.rs | 73 |
2 files changed, 77 insertions, 0 deletions
diff --git a/src/errno.rs b/src/errno.rs index 2f07a104..977ea0b6 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 7135b733..79a3ca10 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -542,6 +542,79 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi Errno::result(res).map(|_| SigAction { sigaction: oldact }) } +/// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) +/// +/// Installs `handler` for the given `signal`, returning the previous signal +/// handler. `signal` should only be used following another call to `signal` or +/// if the current handler is the default. The return value of `signal` is +/// undefined after setting the handler with [`sigaction`][SigActionFn]. +/// +/// # Safety +/// +/// If the pointer to the previous signal handler is invalid, undefined +/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct]. +/// +/// # Examples +/// +/// Ignore `SIGINT`: +/// +/// ```no_run +/// # use nix::sys::signal::{self, Signal, SigHandler}; +/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); +/// ``` +/// +/// Use a signal handler to set a flag variable: +/// +/// ```no_run +/// # #[macro_use] extern crate lazy_static; +/// # extern crate libc; +/// # extern crate nix; +/// # use std::sync::atomic::{AtomicBool, Ordering}; +/// # use nix::sys::signal::{self, Signal, SigHandler}; +/// lazy_static! { +/// static ref SIGNALED: AtomicBool = AtomicBool::new(false); +/// } +/// +/// extern fn handle_sigint(signal: libc::c_int) { +/// let signal = Signal::from_c_int(signal).unwrap(); +/// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); +/// } +/// +/// fn main() { +/// let handler = SigHandler::Handler(handle_sigint); +/// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap(); +/// } +/// ``` +/// +/// # Errors +/// +/// Returns [`Error::UnsupportedOperation`] if `handler` is +/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead. +/// +/// `signal` also returns any error from `libc::signal`, such as when an attempt +/// is made to catch a signal that cannot be caught or to ignore a signal that +/// cannot be ignored. +/// +/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation +/// [SigActionStruct]: struct.SigAction.html +/// [sigactionFn]: fn.sigaction.html +pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> { + 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. |