use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use signal_hook::flag as signal_flag;
use std::io;
pub use signal_hook::consts::signal;
pub use signal_hook::consts::TERM_SIGNALS;
pub struct Uninterruptible {
terminate: Arc<AtomicUsize>,
signals: Vec<i32>,
}
impl Uninterruptible {
pub fn terminate() -> Result<Uninterruptible, io::Error> {
Uninterruptible::signals(TERM_SIGNALS.iter().map(|s| *s).collect())
}
pub fn hup() -> Result<Uninterruptible, io::Error> {
Uninterruptible::signals(vec![signal::SIGHUP])
}
pub fn terminate_hup() -> Result<Uninterruptible, io::Error> {
Uninterruptible::signals(TERM_SIGNALS.iter().map(|s| *s).chain(std::iter::once(signal::SIGHUP)).collect())
}
pub fn signals(signals: Vec<i32>) -> Result<Uninterruptible, io::Error> {
let terminate = Arc::new(AtomicUsize::new(0));
for signal in &signals {
signal_flag::register_usize(*signal, Arc::clone(&terminate), *signal as usize)?;
}
Ok(Uninterruptible {
terminate,
signals,
})
}
pub fn checkpoint(&self) -> Result<(), io::Error> {
match self.terminate.load(Ordering::Relaxed) {
0 => Ok(()),
signal => {
self.terminate.store(0, Ordering::Relaxed);
Err(io::Error::new(io::ErrorKind::Interrupted, format!("Interrupted by the signal {}", signal)))
}
}
}
}
impl Drop for Uninterruptible {
fn drop(&mut self) {
for signal in self.signals.drain(..) {
signal_hook::flag::register_conditional_default(signal, Arc::new(AtomicBool::new(true))).unwrap();
}
}
}