use std::io;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::platform::process::ShutdownRequest;
static REQUESTED: AtomicBool = AtomicBool::new(false);
extern "C" fn record_shutdown_request(_signal: libc::c_int) {
REQUESTED.store(true, Ordering::Relaxed);
}
pub fn install_shutdown_request_handler() -> io::Result<ShutdownRequest> {
REQUESTED.store(false, Ordering::Relaxed);
for signal in [libc::SIGTERM, libc::SIGINT] {
let previous = unsafe {
libc::signal(
signal,
record_shutdown_request as *const () as libc::sighandler_t,
)
};
if previous == libc::SIG_ERR {
return Err(io::Error::last_os_error());
}
}
Ok(ShutdownRequest::watching(&REQUESTED))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_delivered_signal_is_observed() {
let request = install_shutdown_request_handler().expect("install");
assert!(!request.requested(), "nothing has asked yet");
assert_eq!(unsafe { libc::raise(libc::SIGTERM) }, 0);
assert!(request.requested(), "a delivered SIGTERM must be observed");
}
#[test]
fn the_request_latches() {
let request = install_shutdown_request_handler().expect("install");
assert_eq!(unsafe { libc::raise(libc::SIGINT) }, 0);
assert!(request.requested());
assert!(request.requested(), "and stays asked");
}
}