use std::sync::Mutex;
static TRACKED: Mutex<Vec<u32>> = Mutex::new(Vec::new());
#[must_use = "dropping the guard immediately unregisters the child"]
pub fn track(pid: u32) -> TrackGuard {
if let Ok(mut g) = TRACKED.lock() {
g.push(pid);
}
TrackGuard { pid }
}
pub struct TrackGuard {
pid: u32,
}
impl Drop for TrackGuard {
fn drop(&mut self) {
if let Ok(mut g) = TRACKED.lock() {
if let Some(i) = g.iter().position(|&p| p == self.pid) {
g.swap_remove(i);
}
}
}
}
pub fn kill_all() {
let pids: Vec<u32> = TRACKED.lock().map(|g| g.clone()).unwrap_or_default();
for pid in pids {
unsafe {
libc::kill(pid as libc::pid_t, libc::SIGTERM);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn guard_registers_then_unregisters() {
let snapshot_len = TRACKED.lock().unwrap().len();
{
let _g = track(999_999_001);
assert!(TRACKED.lock().unwrap().contains(&999_999_001));
}
assert_eq!(TRACKED.lock().unwrap().len(), snapshot_len);
assert!(!TRACKED.lock().unwrap().contains(&999_999_001));
}
#[test]
fn kill_all_tolerates_stale_pid() {
let g = track(999_999_002);
std::mem::forget(g);
kill_all(); if let Ok(mut t) = TRACKED.lock() {
t.retain(|&p| p != 999_999_002);
}
}
}