use std::sync::Mutex;
#[cfg(unix)]
use std::sync::OnceLock;
static CHILDREN: Mutex<Vec<u32>> = Mutex::new(Vec::new());
pub fn register_child(pid: u32) {
if let Ok(mut c) = CHILDREN.lock() {
c.push(pid);
}
}
pub fn kill_all() {
let pids = CHILDREN
.lock()
.map(|mut c| std::mem::take(&mut *c))
.unwrap_or_default();
for pid in pids {
kill_one(pid);
}
}
#[cfg(unix)]
fn kill_one(pid: u32) {
unsafe {
libc::kill(pid as i32, libc::SIGTERM);
}
}
#[cfg(not(unix))]
fn kill_one(pid: u32) {
let _ = std::process::Command::new("taskkill")
.args(["/T", "/F", "/PID", &pid.to_string()])
.status();
}
#[cfg(unix)]
static WAKE_WRITE_FD: OnceLock<i32> = OnceLock::new();
#[cfg(unix)]
pub fn install() {
static DONE: OnceLock<()> = OnceLock::new();
if DONE.set(()).is_err() {
return;
}
let mut fds = [0i32; 2];
if unsafe { libc::pipe(fds.as_mut_ptr()) } != 0 {
return;
}
let (read_fd, write_fd) = (fds[0], fds[1]);
let _ = WAKE_WRITE_FD.set(write_fd);
let handler = handle_signal as *const () as usize;
unsafe {
libc::signal(libc::SIGINT, handler);
libc::signal(libc::SIGTERM, handler);
}
std::thread::spawn(move || {
let mut buf = [0u8; 1];
let _ = unsafe { libc::read(read_fd, buf.as_mut_ptr() as *mut _, 1) };
kill_all();
std::process::exit(130); });
}
#[cfg(not(unix))]
pub fn install() {}
#[cfg(unix)]
extern "C" fn handle_signal(_sig: i32) {
if let Some(&fd) = WAKE_WRITE_FD.get() {
let byte = [1u8];
unsafe {
libc::write(fd, byte.as_ptr() as *const _, 1);
}
}
}