use std::sync::atomic::{AtomicBool, AtomicU16, Ordering};
#[cfg(not(target_os = "windows"))]
use signal_hook::{
consts::signal::{SIGINT, SIGQUIT, SIGTERM},
iterator,
};
static WRITE_IN_PROGRESS: AtomicU16 = AtomicU16::new(0);
static SIGNAL_HANDLER_AT_WORK: AtomicBool = AtomicBool::new(false);
#[cfg(not(target_os = "windows"))]
pub fn signal_handler<F>(fx: F)
where
F: FnOnce() + Send + 'static,
{
let mut signals =
iterator::Signals::new([SIGTERM, SIGINT, SIGQUIT]).expect("Failed to create Signals");
std::thread::spawn(move || {
for s in signals.forever() {
match s {
SIGTERM | SIGINT | SIGQUIT => {
SIGNAL_HANDLER_AT_WORK.store(true, Ordering::SeqCst);
while WRITE_IN_PROGRESS.load(Ordering::Acquire) > 0 {
std::hint::spin_loop();
std::thread::yield_now();
}
fx();
signal_hook::low_level::exit(130);
}
sig => log::warn!("Received unhandled signal {sig}, ignoring"),
}
}
});
}
pub struct TinHat;
impl TinHat {
pub fn on() -> Self {
while SIGNAL_HANDLER_AT_WORK.load(Ordering::Acquire) {
std::hint::spin_loop();
std::thread::yield_now();
}
let _ = WRITE_IN_PROGRESS.fetch_add(1, Ordering::Release);
Self
}
}
impl Drop for TinHat {
fn drop(&mut self) {
let _ = WRITE_IN_PROGRESS.fetch_sub(1, Ordering::Release);
}
}