Expand description

Module for actions setting flags.

This contains helper functions to set flags whenever a signal happens. The flags are atomic bools or numbers and the library manipulates them with the SeqCst ordering, in case someone cares about relative order to some other atomic variables. If you don’t care about the relative order, you are free to use Ordering::Relaxed when reading and resetting the flags.

When to use

The flags in this module allow for polling if a signal arrived since the previous poll. The do not allow blocking until something arrives.

Therefore, the natural way to use them is in applications that have some kind of iterative work with both some upper and lower time limit on one iteration. If one iteration could block for arbitrary time, the handling of the signal would be postponed for a long time. If the iteration didn’t block at all, the checking for the signal would turn into a busy-loop.

If what you need is blocking until a signal comes, you might find better tools in the pipe and iterator modules.

Examples

Doing something until terminated. This also knows by which signal it was terminated. In case multiple termination signals arrive before it is handled, it recognizes the last one.

use std::io::Error;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

use signal_hook::consts::signal::*;
use signal_hook::flag as signal_flag;

fn main() -> Result<(), Error> {
    let term = Arc::new(AtomicUsize::new(0));
    const SIGTERM_U: usize = SIGTERM as usize;
    const SIGINT_U: usize = SIGINT as usize;
    const SIGQUIT_U: usize = SIGQUIT as usize;
    signal_flag::register_usize(SIGTERM, Arc::clone(&term), SIGTERM_U)?;
    signal_flag::register_usize(SIGINT, Arc::clone(&term), SIGINT_U)?;
    signal_flag::register_usize(SIGQUIT, Arc::clone(&term), SIGQUIT_U)?;

    loop {
        match term.load(Ordering::Relaxed) {
            0 => {
                // Do some useful stuff here
            }
            SIGTERM_U => {
                eprintln!("Terminating on the TERM signal");
                break;
            }
            SIGINT_U => {
                eprintln!("Terminating on the INT signal");
                break;
            }
            SIGQUIT_U => {
                eprintln!("Terminating on the QUIT signal");
                break;
            }
            _ => unreachable!(),
        }
    }

    Ok(())
}

Sending a signal to self and seeing it arrived (not of a practical usage on itself):

use std::io::Error;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;

use signal_hook::consts::signal::*;
use signal_hook::low_level::raise;

fn main() -> Result<(), Error> {
    let got = Arc::new(AtomicBool::new(false));
    signal_hook::flag::register(SIGUSR1, Arc::clone(&got))?;
    raise(SIGUSR1).unwrap();
    // A sleep here, because it could run the signal handler in another thread and we may not
    // see the flag right away. This is still a hack and not guaranteed to work, it is just an
    // example!
    thread::sleep(Duration::from_secs(1));
    assert!(got.load(Ordering::Relaxed));
    Ok(())
}

Reloading a configuration on SIGHUP (which is a common behaviour of many UNIX daemons, together with reopening the log file).

use std::io::Error;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

use signal_hook::consts::signal::*;
use signal_hook::flag as signal_flag;

fn main() -> Result<(), Error> {
    // We start with true, to load the configuration in the very first iteration too.
    let reload = Arc::new(AtomicBool::new(true));
    let term = Arc::new(AtomicBool::new(false));
    signal_flag::register(SIGHUP, Arc::clone(&reload))?;
    signal_flag::register(SIGINT, Arc::clone(&term))?;
    signal_flag::register(SIGTERM, Arc::clone(&term))?;
    signal_flag::register(SIGQUIT, Arc::clone(&term))?;
    while !term.load(Ordering::Relaxed) {
        // Using swap here, not load, to reset it back to false once it is reloaded.
        if reload.swap(false, Ordering::Relaxed) {
            // Reload the config here
        }
        // Serve one request
    }
    Ok(())
}

Functions

Registers an action to set the flag to true whenever the given signal arrives.

Conditionally runs an emulation of the default action on the given signal.

Terminate the application on a signal if the given condition is true.

Registers an action to set the flag to the given value whenever the signal arrives.