use std::io;
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
use windows_sys::Win32::System::JobObjects::{
AssignProcessToJobObject, CreateJobObjectW, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
JOBOBJECT_EXTENDED_LIMIT_INFORMATION, JobObjectExtendedLimitInformation,
SetInformationJobObject, TerminateJobObject,
};
pub struct JobObject {
handle: HANDLE,
}
impl JobObject {
pub fn new() -> io::Result<Self> {
unsafe {
let handle = CreateJobObjectW(std::ptr::null(), std::ptr::null());
if handle.is_null() {
return Err(io::Error::last_os_error());
}
let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = std::mem::zeroed();
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
let ok = SetInformationJobObject(
handle,
JobObjectExtendedLimitInformation,
&info as *const _ as *const core::ffi::c_void,
std::mem::size_of::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>() as u32,
);
if ok == 0 {
let err = io::Error::last_os_error();
CloseHandle(handle);
return Err(err);
}
Ok(Self { handle })
}
}
pub unsafe fn assign(&self, process: HANDLE) -> io::Result<()> {
let ok = unsafe { AssignProcessToJobObject(self.handle, process) };
if ok == 0 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
}
pub fn terminate(&self, exit_code: u32) -> io::Result<()> {
let ok = unsafe { TerminateJobObject(self.handle, exit_code) };
if ok == 0 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
}
}
unsafe impl Send for JobObject {}
unsafe impl Sync for JobObject {}
impl Drop for JobObject {
fn drop(&mut self) {
unsafe {
let _ = CloseHandle(self.handle);
}
}
}