signal-hook 0.1.13

Unix signal handling
Documentation
#![cfg(not(windows))]

extern crate signal_hook;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{self, RecvTimeoutError};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use signal_hook::iterator::Signals;
use signal_hook::{SIGUSR1, SIGUSR2};

#[test]
fn signals_close_forever() {
    // The cloned instances are connected to each other. Closing one closes all.
    // Closing it terminates the forever that waits for stuff. Well, it terminates all of them.
    let signals = Signals::new(&[SIGUSR1]).unwrap();
    // Detect early terminations.
    let stopped = Arc::new(AtomicBool::new(false));
    let threads = (0..5).map(|_| {
        let signals_bg = signals.clone();
        let stopped_bg = Arc::clone(&stopped);
        thread::spawn(move || {
            // Eat all the signals there are (might come from a concurrent test, in theory).
            // Would wait forever, but it should be terminated by the close below.
            for _sig in &signals_bg {}

            stopped_bg.store(true, Ordering::SeqCst);
        })
    });

    // Wait a bit… if some thread terminates by itself.
    thread::sleep(Duration::from_millis(100));
    assert!(!stopped.load(Ordering::SeqCst));

    signals.close();

    // If they don't terminate correctly, the test just keeps running. Not the best way to do
    // tests, but whatever…
    for thread in threads {
        thread.join().unwrap();
    }
}

// A reproducer for #16: if we had the mio-support enabled (which is enabled also by the
// tokio-support feature), blocking no longer works. The .wait() would return immediately (an empty
// iterator, possibly), .forever() would do a busy loop.
// flag)
#[test]
fn signals_block_wait() {
    let signals = Signals::new(&[SIGUSR2]).unwrap();
    let (s, r) = mpsc::channel();
    thread::spawn(move || {
        // Technically, it may spuriously return early. But it shouldn't be doing it too much, so
        // we just try to wait multiple times ‒ if they *all* return right away, it is broken.
        for _ in 0..10 {
            for _ in signals.wait() {
                panic!("Someone really did send us SIGUSR2, which breaks the test");
            }
        }
        let _ = s.send(());
    });

    let err = r
        .recv_timeout(Duration::from_millis(100))
        .expect_err("Wait didn't wait properly");
    assert_eq!(err, RecvTimeoutError::Timeout);
}