use std::io;
use std::mem::size_of;
use std::os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle};
use std::ptr;
pub(crate) const KILL_EXIT_CODE: u32 = 1;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::System::JobObjects::{
CreateJobObjectW, JobObjectExtendedLimitInformation, SetInformationJobObject,
TerminateJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
};
#[derive(Debug)]
pub(super) struct Job(OwnedHandle);
impl Job {
pub(super) fn create(kill_on_close: bool) -> io::Result<Self> {
let handle = unsafe { CreateJobObjectW(ptr::null(), ptr::null()) };
if handle.is_null() {
return Err(io::Error::last_os_error());
}
let job = Self(unsafe { OwnedHandle::from_raw_handle(handle) });
let mut limits = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default();
if kill_on_close {
limits.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
}
let ok = unsafe {
SetInformationJobObject(
job.raw_handle(),
JobObjectExtendedLimitInformation,
ptr::addr_of!(limits).cast(),
u32::try_from(size_of::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>())
.unwrap_or(u32::MAX),
)
};
if ok == 0 {
return Err(io::Error::last_os_error());
}
Ok(job)
}
pub(super) fn raw_handle(&self) -> HANDLE {
self.0.as_raw_handle()
}
pub(super) fn terminate(&self, exit_code: u32) -> io::Result<()> {
let ok = unsafe { TerminateJobObject(self.raw_handle(), exit_code) };
if ok == 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
#[cfg(test)]
#[path = "job_tests.rs"]
mod tests;