1use anyhow::Result;
9use std::sync::atomic::{AtomicBool, Ordering};
10use std::sync::{Arc, OnceLock};
11
12static CANCEL_FLAG: OnceLock<Arc<AtomicBool>> = OnceLock::new();
14
15pub fn register_handler() -> Result<()> {
20 let flag = cancellation_flag();
21 let flag_clone = Arc::clone(&flag);
22
23 ctrlc::set_handler(move || {
24 flag_clone.store(true, Ordering::SeqCst);
25 tracing::debug!("cancellation signal received via Ctrl+C");
26 })?;
27
28 tracing::debug!("Ctrl+C handler registered successfully");
29
30 #[cfg(unix)]
31 {
32 let flag_term = sigterm_flag();
33 signal_hook::flag::register(signal_hook::consts::SIGTERM, flag_term)?;
34 tracing::debug!("handler SIGTERM registrado");
35 }
36
37 #[cfg(not(unix))]
38 {
39 let _ = sigterm_flag(); }
43
44 Ok(())
45}
46
47#[must_use]
61pub fn is_cancelled() -> bool {
62 CANCEL_FLAG
63 .get()
64 .map(|f| f.load(Ordering::SeqCst))
65 .unwrap_or(false)
66}
67
68#[must_use]
73pub fn cancellation_flag() -> Arc<AtomicBool> {
74 Arc::clone(CANCEL_FLAG.get_or_init(|| Arc::new(AtomicBool::new(false))))
75}
76
77static FLAG_SIGTERM: OnceLock<Arc<AtomicBool>> = OnceLock::new();
79
80#[must_use]
82pub fn is_terminated() -> bool {
83 FLAG_SIGTERM
84 .get()
85 .map(|f| f.load(Ordering::SeqCst))
86 .unwrap_or(false)
87}
88
89#[must_use]
91pub fn sigterm_flag() -> Arc<AtomicBool> {
92 Arc::clone(FLAG_SIGTERM.get_or_init(|| Arc::new(AtomicBool::new(false))))
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use serial_test::serial;
99
100 #[test]
101 #[serial]
102 fn is_cancelled_false_before_signal() {
103 let _ = is_cancelled();
107 }
108
109 #[test]
110 #[serial]
111 fn cancellation_flag_returns_same_arc() {
112 let flag_a = cancellation_flag();
113 let flag_b = cancellation_flag();
114 assert!(Arc::ptr_eq(&flag_a, &flag_b));
116 }
117
118 #[test]
119 #[serial]
120 fn flag_can_be_set_and_read() {
121 let flag = cancellation_flag();
122 let previous_value = flag.load(Ordering::SeqCst);
124 flag.store(previous_value, Ordering::SeqCst);
125 assert_eq!(flag.load(Ordering::SeqCst), previous_value);
126 }
127
128 #[test]
129 #[serial]
130 fn is_terminated_false_by_default() {
131 let flag = sigterm_flag();
133 flag.store(false, Ordering::SeqCst);
134 assert!(!is_terminated());
135 }
136
137 #[test]
138 #[serial]
139 fn sigterm_flag_returns_same_arc() {
140 let a = sigterm_flag();
141 let b = sigterm_flag();
142 assert!(Arc::ptr_eq(&a, &b));
143 }
144
145 #[test]
146 #[serial]
147 fn is_terminated_true_after_set() {
148 let flag = sigterm_flag();
149 flag.store(true, Ordering::SeqCst);
150 assert!(is_terminated());
151 flag.store(false, Ordering::SeqCst); }
153
154 #[test]
155 #[serial]
156 fn is_cancelled_false_after_reset() {
157 let flag = cancellation_flag();
158 flag.store(true, Ordering::SeqCst);
159 assert!(is_cancelled());
160 flag.store(false, Ordering::SeqCst);
161 assert!(!is_cancelled());
162 }
163}