//! Wait for processes to change state. //! //! # Safety //! //! This code needs to implement `Send` and `Sync` for `WaitIdStatus` because //! the linux-raw-sys bindings generate a type that doesn't do so //! automatically. #![allow(unsafe_code)] usecrate::process::Pid; usecrate::{backend, io}; use bitflags::bitflags; use core::fmt;
#[cfg(linux_raw)] usecrate::backend::process::wait::SiginfoExt as _;
bitflags! { /// Options for modifying the behavior of [`wait`]/[`waitpid`]. #[repr(transparent)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pubstruct WaitOptions: u32 { /// Return immediately if no child has exited. const NOHANG = bitcast!(backend::process::wait::WNOHANG); /// Return if a child has stopped (but not traced via [`ptrace`]). /// /// [`ptrace`]: https://man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(not(target_os = "horizon"))] const UNTRACED = bitcast!(backend::process::wait::WUNTRACED); /// Return if a stopped child has been resumed by delivery of /// [`Signal::Cont`]. /// /// [`Signal::Cont`]: crate::process::Signal::Cont #[cfg(not(target_os = "horizon"))] const CONTINUED = bitcast!(backend::process::wait::WCONTINUED);
/// The status of a child process after calling [`wait`]/[`waitpid`]. #[derive(Clone, Copy)] #[repr(transparent)] pubstruct WaitStatus(i32);
impl WaitStatus { /// Creates a `WaitStatus` out of an integer. #[inline] pub(crate) fn new(status: i32) -> Self { Self(status)
}
/// Converts a `WaitStatus` into its raw representation as an integer. #[inline] pubconstfn as_raw(self) -> i32 { self.0
}
/// Returns whether the process is currently stopped. #[inline] #[doc(alias = "WIFSTOPPED")] pubfn stopped(self) -> bool {
backend::process::wait::WIFSTOPPED(self.0)
}
/// Returns whether the process has exited normally. #[inline] #[doc(alias = "WIFEXITED")] pubfn exited(self) -> bool {
backend::process::wait::WIFEXITED(self.0)
}
/// Returns whether the process was terminated by a signal. #[inline] #[doc(alias = "WIFSIGNALED")] pubfn signaled(self) -> bool {
backend::process::wait::WIFSIGNALED(self.0)
}
/// Returns whether the process has continued from a job control stop. #[inline] #[doc(alias = "WIFCONTINUED")] pubfn continued(self) -> bool {
backend::process::wait::WIFCONTINUED(self.0)
}
/// Returns the number of the signal that stopped the process, if the /// process was stopped by a signal. #[inline] #[doc(alias = "WSTOPSIG")] pubfn stopping_signal(self) -> Option<i32> { ifself.stopped() {
Some(backend::process::wait::WSTOPSIG(self.0))
} else {
None
}
}
/// Returns the exit status number returned by the process, if it exited /// normally. #[inline] #[doc(alias = "WEXITSTATUS")] pubfn exit_status(self) -> Option<i32> { ifself.exited() {
Some(backend::process::wait::WEXITSTATUS(self.0))
} else {
None
}
}
/// Returns the number of the signal that terminated the process, if the /// process was terminated by a signal. #[inline] #[doc(alias = "WTERMSIG")] pubfn terminating_signal(self) -> Option<i32> { ifself.signaled() {
Some(backend::process::wait::WTERMSIG(self.0))
} else {
None
}
}
}
/// The status of a process after calling [`waitid`]. #[derive(Clone, Copy)] #[repr(transparent)] #[cfg(not(any(
target_os = "horizon",
target_os = "openbsd",
target_os = "redox",
target_os = "wasi"
)))] pubstruct WaitIdStatus(pub(crate) backend::c::siginfo_t);
#[cfg(linux_raw)] // SAFETY: `siginfo_t` does contain some raw pointers, such as the `si_ptr` // and the `si_addr` fields, however it's up to users to use those correctly. unsafeimpl Send for WaitIdStatus {}
#[cfg(linux_raw)] // SAFETY: Same as with `Send`. unsafeimpl Sync for WaitIdStatus {}
#[cfg(not(any(
target_os = "horizon",
target_os = "openbsd",
target_os = "redox",
target_os = "wasi"
)))] impl WaitIdStatus { /// Returns whether the process is currently stopped. #[inline] pubfn stopped(&self) -> bool { self.raw_code() == bitcast!(backend::c::CLD_STOPPED)
}
/// Returns whether the process is currently trapped. #[inline] pubfn trapped(&self) -> bool { self.raw_code() == bitcast!(backend::c::CLD_TRAPPED)
}
/// Returns whether the process has exited normally. #[inline] pubfn exited(&self) -> bool { self.raw_code() == bitcast!(backend::c::CLD_EXITED)
}
/// Returns whether the process was terminated by a signal and did not /// create a core file. #[inline] pubfn killed(&self) -> bool { self.raw_code() == bitcast!(backend::c::CLD_KILLED)
}
/// Returns whether the process was terminated by a signal and did create a /// core file. #[inline] pubfn dumped(&self) -> bool { self.raw_code() == bitcast!(backend::c::CLD_DUMPED)
}
/// Returns whether the process has continued from a job control stop. #[inline] pubfn continued(&self) -> bool { self.raw_code() == bitcast!(backend::c::CLD_CONTINUED)
}
/// Returns the number of the signal that stopped the process, if the /// process was stopped by a signal. #[inline] #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))] pubfn stopping_signal(&self) -> Option<i32> { ifself.stopped() {
Some(self.si_status())
} else {
None
}
}
/// Returns the number of the signal that trapped the process, if the /// process was trapped by a signal. #[inline] #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))] pubfn trapping_signal(&self) -> Option<i32> { ifself.trapped() {
Some(self.si_status())
} else {
None
}
}
/// Returns the exit status number returned by the process, if it exited /// normally. #[inline] #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))] pubfn exit_status(&self) -> Option<i32> { ifself.exited() {
Some(self.si_status())
} else {
None
}
}
/// Returns the number of the signal that terminated the process, if the /// process was terminated by a signal. #[inline] #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))] pubfn terminating_signal(&self) -> Option<i32> { ifself.killed() || self.dumped() {
Some(self.si_status())
} else {
None
}
}
/// Return the raw `si_signo` value returned from `waitid`. #[cfg(linux_raw)] pubfn raw_signo(&self) -> crate::ffi::c_int { self.0.si_signo()
}
/// Return the raw `si_signo` value returned from `waitid`. #[cfg(not(linux_raw))] pubfn raw_signo(&self) -> crate::ffi::c_int { self.0.si_signo
}
/// Return the raw `si_errno` value returned from `waitid`. #[cfg(linux_raw)] pubfn raw_errno(&self) -> crate::ffi::c_int { self.0.si_errno()
}
/// Return the raw `si_errno` value returned from `waitid`. #[cfg(not(linux_raw))] pubfn raw_errno(&self) -> crate::ffi::c_int { self.0.si_errno
}
/// Return the raw `si_code` value returned from `waitid`. #[cfg(linux_raw)] pubfn raw_code(&self) -> crate::ffi::c_int { self.0.si_code()
}
/// Return the raw `si_code` value returned from `waitid`. #[cfg(not(linux_raw))] pubfn raw_code(&self) -> crate::ffi::c_int { self.0.si_code
}
// This is disabled on NetBSD because the libc crate's `si_status()` // implementation doesn't appear to match what's in NetBSD's headers and we // don't get a meaningful value returned. // TODO: Report this upstream. #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))] #[allow(unsafe_code)] fn si_status(&self) -> crate::ffi::c_int { // SAFETY: POSIX [specifies] that the `siginfo_t` returned by a // `waitid` call always has a valid `si_status` value. // // [specifies]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html unsafe { self.0.si_status() }
}
}
/// The identifier to wait on in a call to [`waitid`]. #[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "wasi")))] #[derive(Debug, Clone)] #[non_exhaustive] pubenum WaitId<'a> { /// Wait on all processes. #[doc(alias = "P_ALL")]
All,
/// Wait for a specific process ID. #[doc(alias = "P_PID")]
Pid(Pid),
/// Wait for a specific process group ID, or the calling process' group ID. #[doc(alias = "P_PGID")]
Pgid(Option<Pid>),
/// Wait for a specific process file descriptor. #[cfg(target_os = "linux")] #[doc(alias = "P_PIDFD")]
PidFd(BorrowedFd<'a>),
/// Eat the lifetime for non-Linux platforms. #[doc(hidden)] #[cfg(not(target_os = "linux"))]
__EatLifetime(core::marker::PhantomData<&'a ()>),
}
/// `waitpid(pid, waitopts)`—Wait for a specific process to change state. /// /// If the pid is `None`, the call will wait for any child process whose /// process group id matches that of the calling process. Otherwise, the call /// will wait for the child process with the given pid. /// /// On Success, returns the status of the selected process. /// /// If `NOHANG` was specified in the options, and the selected child process /// didn't change state, returns `None`. /// /// To wait for a given process group (the `< -1` case of `waitpid`), use /// [`waitpgid`] or [`waitid`]. To wait for any process (the `-1` case of /// `waitpid`), use [`wait`]. /// /// # References /// - [POSIX] /// - [Linux] /// /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html /// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html #[doc(alias = "wait4")] #[cfg(not(target_os = "wasi"))] #[inline] pubfn waitpid(pid: Option<Pid>, waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
backend::process::syscalls::waitpid(pid, waitopts)
}
/// `waitpid(-pgid, waitopts)`—Wait for a process in a specific process group /// to change state. /// /// The call will wait for any child process with the given pgid. /// /// On Success, returns the status of the selected process. /// /// If `NOHANG` was specified in the options, and no selected child process /// changed state, returns `None`. /// /// # References /// - [POSIX] /// - [Linux] /// /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html /// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html #[cfg(not(target_os = "wasi"))] #[inline] pubfn waitpgid(pgid: Pid, waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
backend::process::syscalls::waitpgid(pgid, waitopts)
}
/// `wait(waitopts)`—Wait for any of the children of calling process to /// change state. /// /// On success, returns the pid of the child process whose state changed, and /// the status of said process. /// /// If `NOHANG` was specified in the options, and the selected child process /// didn't change state, returns `None`. /// /// # References /// - [POSIX] /// - [Linux] /// /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/wait.html /// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html #[cfg(not(target_os = "wasi"))] #[inline] pubfn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
backend::process::syscalls::wait(waitopts)
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.