use anyhow::Result;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, OnceLock};
static FLAG_CANCELAMENTO: OnceLock<Arc<AtomicBool>> = OnceLock::new();
pub fn registrar_handler() -> Result<()> {
let flag = obter_flag();
let flag_clone = Arc::clone(&flag);
ctrlc::set_handler(move || {
flag_clone.store(true, Ordering::SeqCst);
tracing::debug!("sinal de cancelamento recebido via Ctrl+C");
})?;
tracing::debug!("handler de Ctrl+C registrado com sucesso");
#[cfg(unix)]
{
let flag_term = obter_flag_sigterm();
signal_hook::flag::register(signal_hook::consts::SIGTERM, flag_term)?;
tracing::debug!("handler SIGTERM registrado");
}
#[cfg(not(unix))]
{
let _ = obter_flag_sigterm(); }
Ok(())
}
#[must_use]
pub fn cancelado() -> bool {
FLAG_CANCELAMENTO
.get()
.map(|f| f.load(Ordering::SeqCst))
.unwrap_or(false)
}
#[must_use]
pub fn obter_flag() -> Arc<AtomicBool> {
Arc::clone(FLAG_CANCELAMENTO.get_or_init(|| Arc::new(AtomicBool::new(false))))
}
static FLAG_SIGTERM: OnceLock<Arc<AtomicBool>> = OnceLock::new();
#[must_use]
pub fn terminado() -> bool {
FLAG_SIGTERM
.get()
.map(|f| f.load(Ordering::SeqCst))
.unwrap_or(false)
}
#[must_use]
pub fn obter_flag_sigterm() -> Arc<AtomicBool> {
Arc::clone(FLAG_SIGTERM.get_or_init(|| Arc::new(AtomicBool::new(false))))
}
#[cfg(test)]
mod testes {
use super::*;
#[test]
fn cancelado_retorna_false_antes_de_sinal() {
let _ = cancelado();
}
#[test]
fn obter_flag_retorna_mesmo_arc() {
let flag_a = obter_flag();
let flag_b = obter_flag();
assert!(Arc::ptr_eq(&flag_a, &flag_b));
}
#[test]
fn flag_pode_ser_marcada_e_lida() {
let flag = obter_flag();
let valor_anterior = flag.load(Ordering::SeqCst);
flag.store(valor_anterior, Ordering::SeqCst);
assert_eq!(flag.load(Ordering::SeqCst), valor_anterior);
}
#[test]
fn terminado_false_por_padrao() {
let flag = obter_flag_sigterm();
flag.store(false, Ordering::SeqCst);
assert!(!terminado());
}
#[test]
fn obter_flag_sigterm_retorna_mesmo_arc() {
let a = obter_flag_sigterm();
let b = obter_flag_sigterm();
assert!(Arc::ptr_eq(&a, &b));
}
#[test]
fn terminado_verdadeiro_apos_set() {
let flag = obter_flag_sigterm();
flag.store(true, Ordering::SeqCst);
assert!(terminado());
flag.store(false, Ordering::SeqCst); }
#[test]
fn cancelado_false_apos_reset() {
let flag = obter_flag();
flag.store(true, Ordering::SeqCst);
assert!(cancelado());
flag.store(false, Ordering::SeqCst);
assert!(!cancelado());
}
}