use anyhow::Result;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, OnceLock};
static CANCEL_FLAG: OnceLock<Arc<AtomicBool>> = OnceLock::new();
pub fn register_handler() -> Result<()> {
let flag = cancellation_flag();
let flag_clone = Arc::clone(&flag);
ctrlc::set_handler(move || {
flag_clone.store(true, Ordering::SeqCst);
tracing::debug!("cancellation signal received via Ctrl+C");
})?;
tracing::debug!("Ctrl+C handler registered successfully");
#[cfg(unix)]
{
let flag_term = sigterm_flag();
signal_hook::flag::register(signal_hook::consts::SIGTERM, flag_term)?;
tracing::debug!("handler SIGTERM registrado");
}
#[cfg(not(unix))]
{
let _ = sigterm_flag(); }
Ok(())
}
#[must_use]
pub fn is_cancelled() -> bool {
CANCEL_FLAG
.get()
.map(|f| f.load(Ordering::SeqCst))
.unwrap_or(false)
}
#[must_use]
pub fn cancellation_flag() -> Arc<AtomicBool> {
Arc::clone(CANCEL_FLAG.get_or_init(|| Arc::new(AtomicBool::new(false))))
}
static FLAG_SIGTERM: OnceLock<Arc<AtomicBool>> = OnceLock::new();
#[must_use]
pub fn is_terminated() -> bool {
FLAG_SIGTERM
.get()
.map(|f| f.load(Ordering::SeqCst))
.unwrap_or(false)
}
#[must_use]
pub fn sigterm_flag() -> Arc<AtomicBool> {
Arc::clone(FLAG_SIGTERM.get_or_init(|| Arc::new(AtomicBool::new(false))))
}
#[cfg(test)]
mod tests {
use super::*;
use serial_test::serial;
#[test]
#[serial]
fn is_cancelled_false_before_signal() {
let _ = is_cancelled();
}
#[test]
#[serial]
fn cancellation_flag_returns_same_arc() {
let flag_a = cancellation_flag();
let flag_b = cancellation_flag();
assert!(Arc::ptr_eq(&flag_a, &flag_b));
}
#[test]
#[serial]
fn flag_can_be_set_and_read() {
let flag = cancellation_flag();
let previous_value = flag.load(Ordering::SeqCst);
flag.store(previous_value, Ordering::SeqCst);
assert_eq!(flag.load(Ordering::SeqCst), previous_value);
}
#[test]
#[serial]
fn is_terminated_false_by_default() {
let flag = sigterm_flag();
flag.store(false, Ordering::SeqCst);
assert!(!is_terminated());
}
#[test]
#[serial]
fn sigterm_flag_returns_same_arc() {
let a = sigterm_flag();
let b = sigterm_flag();
assert!(Arc::ptr_eq(&a, &b));
}
#[test]
#[serial]
fn is_terminated_true_after_set() {
let flag = sigterm_flag();
flag.store(true, Ordering::SeqCst);
assert!(is_terminated());
flag.store(false, Ordering::SeqCst); }
#[test]
#[serial]
fn is_cancelled_false_after_reset() {
let flag = cancellation_flag();
flag.store(true, Ordering::SeqCst);
assert!(is_cancelled());
flag.store(false, Ordering::SeqCst);
assert!(!is_cancelled());
}
}