use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
use std::sync::Mutex;
use crate::execution_store::{ExecutionRecord, ExecutionStore};
static SIGNAL_RECEIVED: AtomicBool = AtomicBool::new(false);
static SIGNAL_EXIT_CODE: AtomicI32 = AtomicI32::new(0);
static CURRENT_EXECUTION: Mutex<Option<(ExecutionRecord, ExecutionStore)>> = Mutex::new(None);
#[allow(dead_code)]
pub fn was_signal_received() -> bool {
SIGNAL_RECEIVED.load(Ordering::SeqCst)
}
#[allow(dead_code)]
pub fn get_signal_exit_code() -> i32 {
SIGNAL_EXIT_CODE.load(Ordering::SeqCst)
}
#[cfg(unix)]
pub fn setup_signal_handlers() {
use std::sync::Once;
static INIT: Once = Once::new();
INIT.call_once(|| {
unsafe {
libc::signal(libc::SIGINT, signal_handler as *const () as usize);
libc::signal(libc::SIGTERM, signal_handler as *const () as usize);
libc::signal(libc::SIGHUP, signal_handler as *const () as usize);
}
});
}
#[cfg(not(unix))]
pub fn setup_signal_handlers() {
}
#[cfg(unix)]
extern "C" fn signal_handler(sig: i32) {
let exit_code = 128 + sig;
SIGNAL_EXIT_CODE.store(exit_code, Ordering::SeqCst);
SIGNAL_RECEIVED.store(true, Ordering::SeqCst);
cleanup_execution_on_signal(sig, exit_code);
std::process::exit(exit_code);
}
#[cfg(unix)]
fn cleanup_execution_on_signal(signal: i32, exit_code: i32) {
if let Ok(mut guard) = CURRENT_EXECUTION.lock() {
if let Some((ref mut record, ref store)) = *guard {
record.complete(exit_code);
if let Err(e) = store.save(record) {
eprintln!(
"\n[Tracking] Warning: Could not save execution record on signal {}: {}",
signal, e
);
}
*guard = None;
}
}
}
pub fn set_current_execution(record: ExecutionRecord, store: ExecutionStore) {
if let Ok(mut guard) = CURRENT_EXECUTION.lock() {
*guard = Some((record, store));
}
}
pub fn clear_current_execution() {
if let Ok(mut guard) = CURRENT_EXECUTION.lock() {
*guard = None;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_signal_received_initially_false() {
}
#[test]
fn test_set_and_clear_current_execution() {
clear_current_execution();
}
}