use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
static CLEANUP_REQUESTED: AtomicBool = AtomicBool::new(false);
pub fn is_cleanup_requested() -> bool {
CLEANUP_REQUESTED.load(Ordering::SeqCst)
}
pub fn request_cleanup() {
CLEANUP_REQUESTED.store(true, Ordering::SeqCst);
}
pub fn register_signal_handlers() -> anyhow::Result<()> {
ctrlc::set_handler(move || {
eprintln!("\nReceived interrupt signal, cleaning up...");
request_cleanup();
std::process::exit(5); })
.map_err(|e| anyhow::anyhow!("Failed to set Ctrl+C handler: {}", e))?;
#[cfg(unix)]
{
use signal_hook::consts::signal::*;
use signal_hook::flag;
let cleanup_flag = Arc::new(AtomicBool::new(false));
flag::register(SIGTERM, Arc::clone(&cleanup_flag))
.map_err(|e| anyhow::anyhow!("Failed to register SIGTERM handler: {}", e))?;
flag::register(SIGHUP, Arc::clone(&cleanup_flag))
.map_err(|e| anyhow::anyhow!("Failed to register SIGHUP handler: {}", e))?;
std::thread::spawn(move || loop {
if cleanup_flag.load(Ordering::Relaxed) {
eprintln!("\nReceived termination signal, cleaning up...");
request_cleanup();
std::process::exit(5);
}
std::thread::sleep(std::time::Duration::from_millis(100));
});
}
Ok(())
}
pub struct CleanupGuard {
cleanup_fn: Option<Box<dyn FnOnce() + Send>>,
}
impl CleanupGuard {
pub fn new<F>(cleanup_fn: F) -> Self
where
F: FnOnce() + Send + 'static,
{
Self {
cleanup_fn: Some(Box::new(cleanup_fn)),
}
}
pub fn cleanup(mut self) {
if let Some(cleanup_fn) = self.cleanup_fn.take() {
cleanup_fn();
}
}
}
impl Drop for CleanupGuard {
fn drop(&mut self) {
if let Some(cleanup_fn) = self.cleanup_fn.take() {
cleanup_fn();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cleanup_flag() {
assert!(!is_cleanup_requested());
request_cleanup();
assert!(is_cleanup_requested());
}
#[test]
fn test_cleanup_guard() {
use std::sync::Arc;
let cleaned = Arc::new(AtomicBool::new(false));
let cleaned_clone = Arc::clone(&cleaned);
{
let _guard = CleanupGuard::new(move || {
cleaned_clone.store(true, Ordering::SeqCst);
});
assert!(!cleaned.load(Ordering::SeqCst));
}
assert!(cleaned.load(Ordering::SeqCst));
}
}