use std::{io, thread::JoinHandle};
use signal_hook::{
consts::{SIGHUP, SIGINT, SIGTERM},
iterator::{Handle, Signals},
};
const FORWARDED: [i32; 3] = [SIGINT, SIGTERM, SIGHUP];
pub struct SignalForwarder {
handle: Handle,
thread: Option<JoinHandle<()>>,
}
impl SignalForwarder {
pub fn install(child_pgid: i32) -> io::Result<Self> {
let mut signals = Signals::new(FORWARDED)?;
let handle = signals.handle();
let thread =
std::thread::Builder::new().name("tricord-signals".into()).spawn(move || {
for sig in &mut signals {
forward_to_group(child_pgid, sig);
}
})?;
Ok(Self { handle, thread: Some(thread) })
}
}
impl Drop for SignalForwarder {
fn drop(&mut self) {
self.handle.close();
if let Some(t) = self.thread.take() {
let _ = t.join();
}
}
}
fn forward_to_group(pgid: i32, sig: i32) {
unsafe {
libc::kill(-pgid, sig);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn forwarder_installs_and_drops_cleanly() {
let pid = std::process::id();
#[allow(clippy::cast_possible_wrap)]
let forwarder = SignalForwarder::install(pid as i32).expect("install");
drop(forwarder);
}
}