Skip to content

Commit

Permalink
Documentation for sigaction function and related structs. Solves nix-…
Browse files Browse the repository at this point in the history
  • Loading branch information
serejkus committed Jan 20, 2018
1 parent 5f321db commit 827c645
Showing 1 changed file with 123 additions and 0 deletions.
123 changes: 123 additions & 0 deletions src/sys/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,15 +350,38 @@ impl AsRef<libc::sigset_t> for SigSet {
}
}

/// Enum holding signal action for [`sigaction`](fn.sigaction.html) function.
///
/// Signal can be ignored, may have a custom handler or default one.
///
///
/// Custom signal handlers should follow some [rules](https://wiki.sei.cmu.edu/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers)
/// for being asynchronous-safe.
///
/// For more information see the [`sigaction` man
/// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html) and this
/// crate's [`sigaction` docs](./fn.sigaction.html).
#[allow(unknown_lints)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SigHandler {
/// Signal action should be set to a default one.
SigDfl,
/// Signal should be ignored.
SigIgn,
/// Custom action for signal, the only parameter is the signal number.
Handler(extern fn(libc::c_int)),
/// Custom action for signal. It has some extra info of signal handling context.
SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
}

/// Struct holding data for [`sigaction`](fn.sigaction.html) function.
///
/// `SigAction` holds the signal action itself (which can be ignoring, custom handler or a default
/// handler), flags for modifying the behavior of the signal and a mask of signals which should be
/// blocked during execution of the signal handler.
///
/// For more information see the [`sigaction` man
/// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html).
pub struct SigAction {
sigaction: libc::sigaction
}
Expand Down Expand Up @@ -402,6 +425,106 @@ impl SigAction {
}
}

/// Examine and change a signal action.
///
/// This function sets a signal action and returns the previous one. Parameters are:
///
/// * `signal` - signal number for which the `sigaction` is specified.
/// * `sigaction` - description of new signal action. It is possible to ignore signal, set default
/// or some custom handler, specifying options for handling and signal mask.
///
/// Some signals are cannot be handled - it is `SIGKILL` and `SIGSTOP`.
///
/// Custom signal handlers should call only
/// [signal-safe](https://wiki.sei.cmu.edu/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers)
/// functions. Here is the [list](http://man7.org/linux/man-pages/man7/signal-safety.7.html) of
/// signal-safe functions for Linux. Great care should be taken if the signal handler needs access
/// to global state. Global state used in signal handler must not be protected with
/// [`Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html), it is better to stick to
/// [`atomic`](https://doc.rust-lang.org/std/sync/atomic/index.html) module or to use
/// platform-specific tools which `nix` provides (like [pipe](../../unistd/pipe.v.html)).
///
/// For more information see the [`sigaction` man
/// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html).
///
/// # Safety
///
/// This function is unsafe because it changes the global state of a program (signal handler
/// itself). Custom signal handlers should follow the [rules for signal
/// handlers](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152469).
///
/// # Examples
///
/// Here is an example of building asynchronous-safe signal handler. We're building a function that
/// waits until `SIGINT` arrives and reports it. The problem is that reporting right from the
/// signal handler may be unsafe if reporting code calls allocator or locking functions. This might
/// be a problem if you're using `println!` or `sdtdout()` because there is a `lock` inside of
/// them. So, one of the possible solutions is decoupling signal reporting and signal reaction.
/// Signal handler should report to a signal reaction handler via write to a pipe.
///
/// ```no_run
/// #[macro_use] extern crate lazy_static;
/// extern crate libc;
/// extern crate nix;
///
/// use libc::c_int;
/// use std::os::unix::io::RawFd;
///
/// // The global state to be used in signal handler and function which will implement signal
/// // reaction logic.
/// static mut SIGNAL_FD: RawFd = -1;
/// // We're not using Mutex<RawFd>, because calling lock/unlock in signal handler
/// // is an unsafe operation, but we need a lock to set up SIGNAL_FD.
/// lazy_static! {
/// static ref SIGNAL_SET_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
/// }
///
/// // The signal handler itself: it uses write() system call, which is signal-safe in Linux.
/// extern "C" fn sighandler(_: c_int) {
/// let buf: [u8; 1] = [0];
/// unsafe {
/// // throw-away write since it is subject to race conditions with close
/// // or it may run into filled pipe's buffer.
/// let _ = nix::unistd::write(SIGNAL_FD, &buf);
/// }
/// }
///
/// fn setup_signal_handler() -> Result<RawFd, Box<std::error::Error>> {
/// use nix::sys::signal;
/// // creating a pipe.
/// let (reader, writer) = nix::unistd::pipe()?;
/// // setting a global SIGNAL_FD pipe end.
/// unsafe {
/// let _ = SIGNAL_SET_LOCK.lock();
/// if SIGNAL_FD > 0 {
/// nix::unistd::close(SIGNAL_FD)?;
/// }
/// SIGNAL_FD = writer;
/// }
/// // creating sigaction params.
/// let reaction = signal::SigAction::new(
/// signal::SigHandler::Handler(sighandler),
/// signal::SaFlags::empty(),
/// signal::SigSet::empty(),
/// );
/// // setting sigaction handler, throwing away previous handler (for this example it is
/// // useless).
/// unsafe {
/// let _prev_reaction = signal::sigaction(signal::SIGINT, &reaction)?;
/// };
/// Ok(reader)
/// }
///
/// fn main() {
/// let reader = setup_signal_handler().expect("failed to setup signal handler");
/// println!("succesfully set up signal handler, now waiting for signal to arrive");
/// let mut buf: [u8; 1] = [0];
/// // waiting for signal.
/// let _ = nix::unistd::read(reader, &mut buf);
/// // is is safe to report with println! since we're out of signal handling context.
/// println!("got signal, exiting");
/// }
/// ```
pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
let mut oldact = mem::uninitialized::<libc::sigaction>();

Expand Down

0 comments on commit 827c645

Please sign in to comment.