use std::io;
use std::mem::{size_of, zeroed};
use std::os::windows::io::RawHandle;
use std::ptr;
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,
};
pub(crate) struct JobObject {
handle: HANDLE,
}
unsafe impl Send for JobObject {}
unsafe impl Sync for JobObject {}
impl JobObject {
pub(crate) fn new() -> io::Result<Self> {
let handle = unsafe { CreateJobObjectW(ptr::null(), ptr::null()) };
if handle.is_null() {
return Err(io::Error::last_os_error());
}
let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { zeroed() };
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
let ok = unsafe {
SetInformationJobObject(
handle,
JobObjectExtendedLimitInformation,
&info as *const _ as *const _,
size_of::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>() as u32,
)
};
if ok == 0 {
let err = io::Error::last_os_error();
unsafe { CloseHandle(handle) };
return Err(err);
}
Ok(Self { handle })
}
pub(crate) fn assign(&self, process: RawHandle) -> io::Result<()> {
let ok = unsafe { AssignProcessToJobObject(self.handle, process as HANDLE) };
if ok == 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
impl Drop for JobObject {
fn drop(&mut self) {
unsafe { CloseHandle(self.handle) };
}
}