#![cfg(target_os = "linux")]
use nix::sys::signal::*;
use nix::sys::wait::*;
use nix::unistd::Pid;
use nix::unistd::{fork, ForkResult};
use cargo_spellcheck::{signal_handler, TinHat};
#[test]
fn signal_handler_works() -> Result<(), Box<dyn std::error::Error + 'static>> {
let _ = env_logger::Builder::new()
.filter_level(log::LevelFilter::Trace)
.is_test(true)
.try_init();
println!("Signal handler check");
const QUIT: Signal = Signal::SIGQUIT;
let sigs = {
let mut sigs = SigSet::empty();
sigs.add(QUIT);
sigs
};
let _ = sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&sigs), None);
let _ = pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(&sigs), None);
if let Ok(ForkResult::Parent { child, .. }) = unsafe { fork() } {
println!("[parent] Wait for child");
loop {
let options = WaitPidFlag::WNOHANG;
match nix::sys::wait::waitpid(child, Some(options)) {
Ok(WaitStatus::StillAlive) => {
std::thread::sleep(std::time::Duration::from_millis(50));
continue;
}
Ok(WaitStatus::Signaled(_pid, signal, _core_dump)) => {
assert_eq!(signal, QUIT);
unreachable!("Should exit via exit. qed")
}
Ok(WaitStatus::Exited(_pid, _exit_code)) => {
return Ok(());
}
Ok(ws) => unreachable!("Unexpected wait status: {ws:?}"),
Err(errno) => unreachable!("Did not expect an error: {errno:?}"),
}
}
} else {
signal_handler(|| {});
{
let hat = TinHat::on();
println!("[child] Raise signal");
kill(Pid::this(), QUIT).unwrap();
std::thread::sleep(std::time::Duration::from_millis(1));
drop(hat);
}
std::thread::sleep(std::time::Duration::from_secs(10_000));
unreachable!("[child] Signal handler exits before panic.");
}
}