use std::{
process::Child,
thread,
time::{Duration, Instant},
};
#[cfg(unix)]
use libc::{SIGKILL, SIGTERM, kill};
pub struct ChildManager {
children: Vec<Child>,
shut_down: bool,
}
impl ChildManager {
pub fn new() -> Self {
Self { children: Vec::new(), shut_down: false }
}
pub fn push(&mut self, child: Child) {
self.children.push(child);
}
pub fn shutdown_all(&mut self, timeout: Duration) {
if self.shut_down {
return;
}
self.shut_down = true;
for _child in &mut self.children {
#[cfg(unix)]
#[allow(unsafe_code)]
unsafe {
let _ = kill(-(_child.id() as i32), SIGTERM);
}
#[cfg(windows)]
{
}
}
let start = Instant::now();
while start.elapsed() < timeout {
if self.children.iter_mut().all(|c| matches!(c.try_wait(), Ok(Some(_)))) {
break;
}
thread::sleep(Duration::from_millis(150));
}
for child in &mut self.children {
let still_running = matches!(child.try_wait(), Ok(None));
#[cfg(unix)]
if still_running {
#[allow(unsafe_code)]
unsafe {
let _ = kill(-(child.id() as i32), SIGKILL);
}
}
#[cfg(windows)]
if still_running {
let _ = child.kill();
}
}
for child in &mut self.children {
let _ = child.wait(); }
}
}
impl Drop for ChildManager {
fn drop(&mut self) {
self.shutdown_all(Duration::from_secs(30));
}
}