#[cfg(test)]
mod tests;
use signal_hook::{
consts::{SIGINT, SIGTERM},
flag,
};
use std::{
io,
sync::{
Arc, Mutex, MutexGuard, OnceLock,
atomic::{AtomicBool, Ordering},
},
};
static SERIAL: Mutex<()> = Mutex::new(());
static SIGNALS: OnceLock<io::Result<Signals>> = OnceLock::new();
struct Signals {
use_default: Arc<AtomicBool>,
cancelled: Arc<AtomicBool>,
}
pub(super) struct Cancellation {
signals: &'static Signals,
_serial: MutexGuard<'static, ()>,
}
impl Cancellation {
pub(super) fn start() -> io::Result<Self> {
let serial = SERIAL
.lock()
.map_err(|_| io::Error::other("lock cancellation guard poisoned"))?;
let signals = SIGNALS
.get_or_init(|| {
let use_default = Arc::new(AtomicBool::new(true));
let cancelled = Arc::new(AtomicBool::new(false));
for signal in [SIGINT, SIGTERM] {
flag::register_conditional_default(signal, Arc::clone(&use_default))?;
flag::register(signal, Arc::clone(&cancelled))?;
}
Ok(Signals {
use_default,
cancelled,
})
})
.as_ref()
.map_err(|error| io::Error::other(error.to_string()))?;
signals.cancelled.store(false, Ordering::SeqCst);
signals.use_default.store(false, Ordering::SeqCst);
Ok(Self {
signals,
_serial: serial,
})
}
pub(super) fn check(&self) -> io::Result<()> {
if self.signals.cancelled.load(Ordering::SeqCst) {
Err(io::Error::new(
io::ErrorKind::Interrupted,
"build lock wait cancelled",
))
} else {
Ok(())
}
}
}
impl Drop for Cancellation {
fn drop(&mut self) {
self.signals.use_default.store(true, Ordering::SeqCst);
}
}