use std::time::Duration;
#[cfg(unix)]
pub fn configure_command_for_process_group(command: &mut tokio::process::Command) {
unsafe {
command.pre_exec(|| {
if libc::setpgid(0, 0) != 0 {
return Err(std::io::Error::last_os_error());
}
Ok(())
});
}
}
#[cfg(not(unix))]
pub fn configure_command_for_process_group(command: &mut tokio::process::Command) {
let _ = command;
}
#[cfg(unix)]
fn send_signal_to_process_group_or_pid(pid: u32, signal: i32) -> bool {
if pid == 0 {
return false;
}
let raw_pid = pid as libc::pid_t;
let group_ok = unsafe { libc::kill(-raw_pid, signal) == 0 };
if group_ok {
return true;
}
unsafe { libc::kill(raw_pid, signal) == 0 }
}
#[cfg(not(unix))]
fn send_signal_to_process_group_or_pid(_pid: u32, _signal: i32) -> bool {
false
}
pub fn send_sigterm(pid: u32) -> bool {
send_signal_to_process_group_or_pid(pid, libc::SIGTERM)
}
pub fn send_sigkill(pid: u32) -> bool {
send_signal_to_process_group_or_pid(pid, libc::SIGKILL)
}
pub async fn terminate_process_tree(pid: u32, child: &mut tokio::process::Child, grace: Duration) {
#[cfg(unix)]
{
if !send_sigterm(pid) {
let _ = child.start_kill();
}
let exited = tokio::time::timeout(grace, child.wait()).await;
if exited.is_err() {
let _ = send_sigkill(pid);
let _ = tokio::time::timeout(Duration::from_secs(1), child.wait()).await;
}
}
#[cfg(not(unix))]
{
let _ = pid;
let _ = child.start_kill();
let _ = tokio::time::timeout(grace, child.wait()).await;
}
}