1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
//! A simple crate to catch signals and set a boolean flag for later use. //! //! This crate doesn't create threads behind the scene. //! //! [![Crates.io Version](https://img.shields.io/crates/v/signalbool.svg)](https://crates.io/crates/signalbool) //! [![GitHub stars](https://img.shields.io/github/stars/lilydjwg/signalbool.svg?style=social&label=Star)](https://github.com/lilydjwg/signalbool) //! //! # Example //! //! Here is a program that sleeps until it receives three `SIGINT` signals. //! //! ``` //! extern crate signalbool; //! extern crate nix; //! //! use nix::unistd::sleep; //! //! fn main() { //! let mut sb = signalbool::SignalBool::new( //! &[signalbool::Signal::SIGINT], signalbool::Flag::Interrupt, //! ).unwrap(); //! let mut count = 0; //! //! loop { //! sleep(10); //! if sb.caught() { //! println!("Caught SIGINT."); //! count += 1; //! sb.reset(); //! if count == 3 { //! break; //! } //! } //! } //! } //! ``` extern crate nix; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::os::raw::c_int; use std::mem::transmute; use nix::Result; use nix::sys::signal::*; pub use nix::sys::signal::Signal; /// A struct that catches specified signals and sets its internal flag to `true`. /// /// Note: any previously-registered signal handlers will be lost. #[derive(Clone)] pub struct SignalBool(Arc<AtomicBool>); /// flag controlling the restarting behavior. /// /// Note that most functions in `std` ignore `EINTR` and continue their operations. /// /// See manpage [`signal(7)`](http://man7.org/linux/man-pages/man7/signal.7.html) for details. pub enum Flag { /// Blocking syscalls will be interrupted. Interrupt, /// Use SA_RESTART so that syscalls don't get interrupted. Restart, } const SIGNUM: usize = 32; static mut SIGNALS: [usize; SIGNUM] = [0; SIGNUM]; extern "C" fn os_handler(sig: c_int) { let sb: Arc<AtomicBool> = unsafe { transmute(SIGNALS[sig as usize]) }; sb.store(true, Ordering::Relaxed); } impl SignalBool { /// Register an array of signals to set the internal flag to true when received. pub fn new(signals: &[Signal], flag: Flag) -> Result<Self> { let flags = match flag { Flag::Restart => SA_RESTART, Flag::Interrupt => SaFlags::empty(), }; let handler = SigHandler::Handler(os_handler); let sa = SigAction::new(handler, flags, SigSet::empty()); let sb = SignalBool(Arc::new(AtomicBool::new(false))); for signal in signals { unsafe { sigaction(*signal, &sa)?; SIGNALS[*signal as usize] = transmute(sb.clone()); } } Ok(sb) } /// Reset the internal flag to false. pub fn reset(&mut self) { self.0.store(false, Ordering::Relaxed); } /// Check whether we've caught a registered signal. pub fn caught(&self) -> bool { self.0.load(Ordering::Relaxed) } }