pub use self::imp::Setup;
pub fn setup() -> Option<Setup> {
unsafe { imp::setup() }
}
#[cfg(unix)]
mod imp {
use std::env;
pub type Setup = ();
pub unsafe fn setup() -> Option<()> {
if env::var("__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE").is_ok() {
libc::setsid();
}
Some(())
}
}
#[cfg(windows)]
mod imp {
use std::io;
use std::mem;
use std::ptr;
use log::info;
use winapi::shared::minwindef::*;
use winapi::um::handleapi::*;
use winapi::um::jobapi2::*;
use winapi::um::processthreadsapi::*;
use winapi::um::winnt::HANDLE;
use winapi::um::winnt::*;
pub struct Setup {
job: Handle,
}
pub struct Handle {
inner: HANDLE,
}
fn last_err() -> io::Error {
io::Error::last_os_error()
}
pub unsafe fn setup() -> Option<Setup> {
let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
if job.is_null() {
return None;
}
let job = Handle { inner: job };
let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
info = mem::zeroed();
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
let r = SetInformationJobObject(
job.inner,
JobObjectExtendedLimitInformation,
&mut info as *mut _ as LPVOID,
mem::size_of_val(&info) as DWORD,
);
if r == 0 {
return None;
}
let me = GetCurrentProcess();
let r = AssignProcessToJobObject(job.inner, me);
if r == 0 {
return None;
}
Some(Setup { job })
}
impl Drop for Setup {
fn drop(&mut self) {
unsafe {
let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
info = mem::zeroed();
let r = SetInformationJobObject(
self.job.inner,
JobObjectExtendedLimitInformation,
&mut info as *mut _ as LPVOID,
mem::size_of_val(&info) as DWORD,
);
if r == 0 {
info!("failed to configure job object to defaults: {}", last_err());
}
}
}
}
impl Drop for Handle {
fn drop(&mut self) {
unsafe {
CloseHandle(self.inner);
}
}
}
}