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);
16
17#[allow(dead_code)]
19pub fn was_signal_received() -> bool {
20 SIGNAL_RECEIVED.load(Ordering::SeqCst)
21}
22
23#[allow(dead_code)]
25pub fn get_signal_exit_code() -> i32 {
26 SIGNAL_EXIT_CODE.load(Ordering::SeqCst)
27}
28
29#[cfg(unix)]
31pub fn setup_signal_handlers() {
32 use std::sync::Once;
33 static INIT: Once = Once::new();
34
35 INIT.call_once(|| {
36 unsafe {
37 libc::signal(libc::SIGINT, signal_handler as *const () as usize);
39 libc::signal(libc::SIGTERM, signal_handler as *const () as usize);
41 libc::signal(libc::SIGHUP, signal_handler as *const () as usize);
43 }
44 });
45}
46
47#[cfg(not(unix))]
48pub fn setup_signal_handlers() {
49 }
51
52#[cfg(unix)]
54extern "C" fn signal_handler(sig: i32) {
55 let exit_code = 128 + sig;
57 SIGNAL_EXIT_CODE.store(exit_code, Ordering::SeqCst);
58 SIGNAL_RECEIVED.store(true, Ordering::SeqCst);
59
60 cleanup_execution_on_signal(sig, exit_code);
62
63 std::process::exit(exit_code);
65}
66
67#[cfg(unix)]
69fn cleanup_execution_on_signal(signal: i32, exit_code: i32) {
70 if let Ok(mut guard) = CURRENT_EXECUTION.lock() {
71 if let Some((ref mut record, ref store)) = *guard {
72 record.complete(exit_code);
74 if let Err(e) = store.save(record) {
75 eprintln!(
77 "\n[Tracking] Warning: Could not save execution record on signal {}: {}",
78 signal, e
79 );
80 }
81 *guard = None;
83 }
84 }
85}
86
87pub fn set_current_execution(record: ExecutionRecord, store: ExecutionStore) {
89 if let Ok(mut guard) = CURRENT_EXECUTION.lock() {
90 *guard = Some((record, store));
91 }
92}
93
94pub fn clear_current_execution() {
96 if let Ok(mut guard) = CURRENT_EXECUTION.lock() {
97 *guard = None;
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_signal_received_initially_false() {
107 }
111
112 #[test]
113 fn test_set_and_clear_current_execution() {
114 clear_current_execution();
116 }
117}