use std::io;
use std::mem::MaybeUninit;
use std::process::Child;
#[cfg(feature = "timeout")]
use std::time::Instant;
#[derive(Copy, Clone)]
pub struct Handle(u32);
pub fn get_handle(child: &Child) -> Handle {
Handle(child.id())
}
pub fn wait_noreap(handle: Handle) -> io::Result<()> {
loop {
let mut siginfo = MaybeUninit::zeroed();
let ret = unsafe {
libc::waitid(
libc::P_PID,
handle.0 as libc::id_t,
siginfo.as_mut_ptr(),
libc::WEXITED | libc::WNOWAIT,
)
};
if ret == 0 {
return Ok(());
}
let error = io::Error::last_os_error();
if error.kind() != io::ErrorKind::Interrupted {
return Err(error);
}
}
}
pub fn try_wait_noreap(handle: Handle) -> io::Result<bool> {
let mut siginfo: libc::siginfo_t;
let ret = unsafe {
siginfo = std::mem::zeroed();
libc::waitid(
libc::P_PID,
handle.0 as libc::id_t,
&mut siginfo,
libc::WEXITED | libc::WNOWAIT | libc::WNOHANG,
)
};
if ret != 0 {
Err(io::Error::last_os_error())
} else if siginfo.si_signo == libc::SIGCHLD {
Ok(true)
} else if siginfo.si_signo == 0 {
Ok(false)
} else {
Err(io::Error::other(format!(
"unexpected si_signo from waitid: {}",
siginfo.si_signo
)))
}
}
#[cfg(feature = "timeout")]
pub fn wait_deadline_noreap(handle: Handle, deadline: Instant) -> io::Result<bool> {
let mut sigchld_waiter = sigchld::Waiter::new()?;
loop {
if try_wait_noreap(handle)? {
return Ok(true);
}
if deadline < Instant::now() {
return Ok(false);
}
sigchld_waiter.wait_deadline(deadline)?;
}
}