use crate::process::Pid;
use crate::{backend, io};
use bitflags::bitflags;
#[cfg(target_os = "linux")]
use crate::fd::BorrowedFd;
#[cfg(linux_raw)]
use crate::backend::process::wait::SiginfoExt;
bitflags! {
pub struct WaitOptions: u32 {
const NOHANG = backend::process::wait::WNOHANG as _;
const UNTRACED = backend::process::wait::WUNTRACED as _;
const CONTINUED = backend::process::wait::WCONTINUED as _;
}
}
#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))]
bitflags! {
pub struct WaitidOptions: u32 {
const NOHANG = backend::process::wait::WNOHANG as _;
const CONTINUED = backend::process::wait::WCONTINUED as _;
const EXITED = backend::process::wait::WEXITED as _;
const NOWAIT = backend::process::wait::WNOWAIT as _;
const STOPPED = backend::process::wait::WSTOPPED as _;
}
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct WaitStatus(u32);
impl WaitStatus {
#[inline]
pub(crate) fn new(status: u32) -> Self {
Self(status)
}
#[inline]
pub const fn as_raw(self) -> u32 {
self.0
}
#[inline]
pub fn stopped(self) -> bool {
backend::process::wait::WIFSTOPPED(self.0 as _)
}
#[inline]
pub fn exited(self) -> bool {
backend::process::wait::WIFEXITED(self.0 as _)
}
#[inline]
pub fn signaled(self) -> bool {
backend::process::wait::WIFSIGNALED(self.0 as _)
}
#[inline]
pub fn continued(self) -> bool {
backend::process::wait::WIFCONTINUED(self.0 as _)
}
#[inline]
pub fn stopping_signal(self) -> Option<u32> {
if self.stopped() {
Some(backend::process::wait::WSTOPSIG(self.0 as _) as _)
} else {
None
}
}
#[inline]
pub fn exit_status(self) -> Option<u32> {
if self.exited() {
Some(backend::process::wait::WEXITSTATUS(self.0 as _) as _)
} else {
None
}
}
#[inline]
pub fn terminating_signal(self) -> Option<u32> {
if self.signaled() {
Some(backend::process::wait::WTERMSIG(self.0 as _) as _)
} else {
None
}
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))]
pub struct WaitidStatus(pub(crate) backend::c::siginfo_t);
#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))]
impl WaitidStatus {
#[inline]
pub fn stopped(&self) -> bool {
self.si_code() == backend::c::CLD_STOPPED
}
#[inline]
pub fn trapped(&self) -> bool {
self.si_code() == backend::c::CLD_TRAPPED
}
#[inline]
pub fn exited(&self) -> bool {
self.si_code() == backend::c::CLD_EXITED
}
#[inline]
pub fn killed(&self) -> bool {
self.si_code() == backend::c::CLD_KILLED
}
#[inline]
pub fn dumped(&self) -> bool {
self.si_code() == backend::c::CLD_DUMPED
}
#[inline]
pub fn continued(&self) -> bool {
self.si_code() == backend::c::CLD_CONTINUED
}
#[inline]
#[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))]
pub fn stopping_signal(&self) -> Option<u32> {
if self.stopped() {
Some(self.si_status() as _)
} else {
None
}
}
#[inline]
#[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))]
pub fn trapping_signal(&self) -> Option<u32> {
if self.trapped() {
Some(self.si_status() as _)
} else {
None
}
}
#[inline]
#[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))]
pub fn exit_status(&self) -> Option<u32> {
if self.exited() {
Some(self.si_status() as _)
} else {
None
}
}
#[inline]
#[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))]
pub fn terminating_signal(&self) -> Option<u32> {
if self.killed() || self.dumped() {
Some(self.si_status() as _)
} else {
None
}
}
#[inline]
pub const fn as_raw(&self) -> &backend::c::siginfo_t {
&self.0
}
#[cfg(linux_raw)]
fn si_code(&self) -> u32 {
self.0.si_code() as u32 }
#[cfg(not(linux_raw))]
fn si_code(&self) -> backend::c::c_int {
self.0.si_code
}
#[cfg(not(any(target_os = "netbsd", target_os = "fuchsia", target_os = "emscripten")))]
#[allow(unsafe_code)]
fn si_status(&self) -> backend::c::c_int {
unsafe { self.0.si_status() }
}
}
#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))]
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum WaitId<'a> {
All,
Pid(Pid),
#[cfg(target_os = "linux")]
PidFd(BorrowedFd<'a>),
#[doc(hidden)]
#[cfg(not(target_os = "linux"))]
__EatLifetime(core::marker::PhantomData<&'a ()>),
}
#[cfg(not(target_os = "wasi"))]
#[inline]
pub fn waitpid(pid: Option<Pid>, waitopts: WaitOptions) -> io::Result<Option<WaitStatus>> {
Ok(backend::process::syscalls::waitpid(pid, waitopts)?.map(|(_, status)| status))
}
#[cfg(not(target_os = "wasi"))]
#[inline]
pub fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
backend::process::syscalls::wait(waitopts)
}
#[cfg(not(any(target_os = "wasi", target_os = "redox", target_os = "openbsd")))]
#[inline]
pub fn waitid<'a>(
id: impl Into<WaitId<'a>>,
options: WaitidOptions,
) -> io::Result<Option<WaitidStatus>> {
backend::process::syscalls::waitid(id.into(), options)
}