#[cfg(windows)]
mod imp {
use std::ffi::c_void;
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
use windows_sys::Win32::System::JobObjects::{
AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation,
SetInformationJobObject, TerminateJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
};
pub struct ProcessGroup {
job: HANDLE,
}
impl ProcessGroup {
pub fn configure(_cmd: &mut tokio::process::Command) {
}
pub fn assign(child: &tokio::process::Child) -> Option<Self> {
unsafe {
let job = CreateJobObjectW(std::ptr::null(), std::ptr::null());
if job.is_null() {
return None;
}
let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = std::mem::zeroed();
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
let ok = SetInformationJobObject(
job,
JobObjectExtendedLimitInformation,
&info as *const _ as *const c_void,
std::mem::size_of::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>() as u32,
);
if ok == 0 {
CloseHandle(job);
return None;
}
let proc_handle: HANDLE = match child.raw_handle() {
Some(h) => h as HANDLE,
None => {
CloseHandle(job);
return None;
}
};
let ok = AssignProcessToJobObject(job, proc_handle);
if ok == 0 {
CloseHandle(job);
return None;
}
Some(ProcessGroup { job })
}
}
pub fn terminate(&self) {
self.kill();
}
pub fn kill(&self) {
unsafe {
TerminateJobObject(self.job, 1);
}
}
}
impl Drop for ProcessGroup {
fn drop(&mut self) {
unsafe {
CloseHandle(self.job);
}
}
}
unsafe impl Send for ProcessGroup {}
unsafe impl Sync for ProcessGroup {}
}
#[cfg(unix)]
mod imp {
pub struct ProcessGroup {
pgid: i32,
}
impl ProcessGroup {
pub fn configure(cmd: &mut tokio::process::Command) {
cmd.process_group(0);
}
pub fn assign(child: &tokio::process::Child) -> Option<Self> {
let pid = child.id()? as i32;
Some(ProcessGroup { pgid: pid })
}
pub fn terminate(&self) {
unsafe {
libc::killpg(self.pgid, libc::SIGTERM);
}
}
pub fn kill(&self) {
unsafe {
libc::killpg(self.pgid, libc::SIGKILL);
}
}
}
}
pub use imp::ProcessGroup;