start_command/
signal_handler.rs1use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
7use std::sync::Mutex;
8
9use crate::execution_store::{ExecutionRecord, ExecutionStore};
10
11static SIGNAL_RECEIVED: AtomicBool = AtomicBool::new(false);
14static SIGNAL_EXIT_CODE: AtomicI32 = AtomicI32::new(0);
15static CURRENT_EXECUTION: Mutex<Option<(ExecutionRecord, ExecutionStore)>> = Mutex::new(None);
16static DEFERRED: AtomicBool = AtomicBool::new(false);
20
21pub fn set_deferred_signals(deferred: bool) {
23 DEFERRED.store(deferred, Ordering::SeqCst);
24}
25
26#[allow(dead_code)]
28pub fn was_signal_received() -> bool {
29 SIGNAL_RECEIVED.load(Ordering::SeqCst)
30}
31
32#[allow(dead_code)]
34pub fn get_signal_exit_code() -> i32 {
35 SIGNAL_EXIT_CODE.load(Ordering::SeqCst)
36}
37
38#[cfg(unix)]
40pub fn setup_signal_handlers() {
41 use std::sync::Once;
42 static INIT: Once = Once::new();
43
44 INIT.call_once(|| {
45 unsafe {
46 libc::signal(libc::SIGINT, signal_handler as *const () as usize);
48 libc::signal(libc::SIGTERM, signal_handler as *const () as usize);
50 libc::signal(libc::SIGHUP, signal_handler as *const () as usize);
52 }
53 });
54}
55
56#[cfg(not(unix))]
57pub fn setup_signal_handlers() {
58 }
60
61#[cfg(unix)]
63extern "C" fn signal_handler(sig: i32) {
64 let exit_code = 128 + sig;
66 SIGNAL_EXIT_CODE.store(exit_code, Ordering::SeqCst);
67 SIGNAL_RECEIVED.store(true, Ordering::SeqCst);
68 if DEFERRED.load(Ordering::SeqCst) {
69 return;
70 }
71
72 cleanup_execution_on_signal(sig, exit_code);
74
75 std::process::exit(exit_code);
77}
78
79#[cfg(unix)]
81fn cleanup_execution_on_signal(signal: i32, exit_code: i32) {
82 if let Ok(mut guard) = CURRENT_EXECUTION.lock() {
83 if let Some((ref mut record, ref store)) = *guard {
84 record.complete(exit_code);
86 if let Err(e) = store.save(record) {
87 eprintln!(
89 "\n[Tracking] Warning: Could not save execution record on signal {}: {}",
90 signal, e
91 );
92 }
93 *guard = None;
95 }
96 }
97}
98
99pub fn set_current_execution(record: ExecutionRecord, store: ExecutionStore) {
101 if let Ok(mut guard) = CURRENT_EXECUTION.lock() {
102 *guard = Some((record, store));
103 }
104}
105
106pub fn clear_current_execution() {
108 if let Ok(mut guard) = CURRENT_EXECUTION.lock() {
109 *guard = None;
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_signal_received_initially_false() {
119 }
123
124 #[test]
125 fn test_set_and_clear_current_execution() {
126 clear_current_execution();
128 }
129}