use anyhow::{Context, Error};
use signal_hook::consts::signal;
use signal_hook::flag::register;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
#[cfg(unix)]
const STOP_SIGNALS: &[i32] = &[
signal::SIGINT,
signal::SIGTERM,
signal::SIGQUIT,
signal::SIGHUP,
signal::SIGUSR1,
signal::SIGUSR2,
];
#[cfg(not(unix))]
const STOP_SIGNALS: &[i32] = &[signal::SIGTERM, signal::SIGINT];
pub fn setup_interrupt_handler(
shutdown: &Arc<AtomicBool>,
) -> Result<(), Error> {
for sig in STOP_SIGNALS {
let name =
signal_hook::low_level::signal_name(*sig).unwrap_or_default();
register(*sig, Arc::clone(shutdown)).with_context(|| {
format!("Unable to register signal handler for {name}/{sig}")
})?;
}
Ok(())
}
#[cfg(unix)]
pub fn reset_sigpipe() {
unsafe {
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
}
}
#[cfg(not(unix))]
pub fn reset_sigpipe() {}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
#[test]
fn test_setup_interrupt_handler_returns_ok() {
let shutdown = Arc::new(AtomicBool::new(false));
assert!(setup_interrupt_handler(&shutdown).is_ok());
}
#[test]
fn test_setup_interrupt_handler_multiple_calls() {
let s1 = Arc::new(AtomicBool::new(false));
let s2 = Arc::new(AtomicBool::new(false));
assert!(setup_interrupt_handler(&s1).is_ok());
assert!(setup_interrupt_handler(&s2).is_ok());
}
#[test]
fn test_reset_sigpipe_no_panic() {
reset_sigpipe();
}
}