1use crate::process::Pid; 2use crate::{backend, io}; 3use bitflags::bitflags; 4 5bitflags! { 6 /// Options for modifying the behavior of wait/waitpid 7 pub struct WaitOptions: u32 { 8 /// Return immediately if no child has exited. 9 const NOHANG = backend::process::wait::WNOHANG as _; 10 /// Return if a child has stopped (but not traced via `ptrace(2)`) 11 const UNTRACED = backend::process::wait::WUNTRACED as _; 12 /// Return if a stopped child has been resumed by delivery of `SIGCONT` 13 const CONTINUED = backend::process::wait::WCONTINUED as _; 14 } 15} 16 17/// the status of the child processes the caller waited on 18#[derive(Debug, Clone, Copy)] 19pub struct WaitStatus(u32); 20 21impl WaitStatus { 22 /// create a `WaitStatus` out of an integer. 23 #[inline] 24 pub(crate) fn new(status: u32) -> Self { 25 Self(status) 26 } 27 28 /// Converts a `WaitStatus` into its raw representation as an integer. 29 #[inline] 30 pub const fn as_raw(self) -> u32 { 31 self.0 32 } 33 34 /// Returns whether the process is currently stopped. 35 #[inline] 36 pub fn stopped(self) -> bool { 37 backend::process::wait::WIFSTOPPED(self.0 as _) 38 } 39 40 /// Returns whether the process has continued from a job control stop. 41 #[inline] 42 pub fn continued(self) -> bool { 43 backend::process::wait::WIFCONTINUED(self.0 as _) 44 } 45 46 /// Returns the number of the signal that stopped the process, 47 /// if the process was stopped by a signal. 48 #[inline] 49 pub fn stopping_signal(self) -> Option<u32> { 50 if self.stopped() { 51 Some(backend::process::wait::WSTOPSIG(self.0 as _) as _) 52 } else { 53 None 54 } 55 } 56 57 /// Returns the exit status number returned by the process, 58 /// if it exited normally. 59 #[inline] 60 pub fn exit_status(self) -> Option<u32> { 61 if backend::process::wait::WIFEXITED(self.0 as _) { 62 Some(backend::process::wait::WEXITSTATUS(self.0 as _) as _) 63 } else { 64 None 65 } 66 } 67 68 /// Returns the number of the signal that terminated the process, 69 /// if the process was terminated by a signal. 70 #[inline] 71 pub fn terminating_signal(self) -> Option<u32> { 72 if backend::process::wait::WIFSIGNALED(self.0 as _) { 73 Some(backend::process::wait::WTERMSIG(self.0 as _) as _) 74 } else { 75 None 76 } 77 } 78} 79 80/// `waitpid(pid, waitopts)`—Wait for a specific process to change state. 81/// 82/// If the pid is `None`, the call will wait for any child process whose 83/// process group id matches that of the calling process. 84/// 85/// If the pid is equal to `RawPid::MAX`, the call will wait for any child 86/// process. 87/// 88/// Otherwise if the `wrapping_neg` of pid is less than pid, the call will wait 89/// for any child process with a group ID equal to the `wrapping_neg` of `pid`. 90/// 91/// Otherwise, the call will wait for the child process with the given pid. 92/// 93/// On Success, returns the status of the selected process. 94/// 95/// If `NOHANG` was specified in the options, and the selected child process 96/// didn't change state, returns `None`. 97/// 98/// # References 99/// - [POSIX] 100/// - [Linux] 101/// 102/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html 103/// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html 104#[cfg(not(target_os = "wasi"))] 105#[inline] 106pub fn waitpid(pid: Option<Pid>, waitopts: WaitOptions) -> io::Result<Option<WaitStatus>> { 107 Ok(backend::process::syscalls::waitpid(pid, waitopts)?.map(|(_, status)| status)) 108} 109 110/// `wait(waitopts)`—Wait for any of the children of calling process to 111/// change state. 112/// 113/// On success, returns the pid of the child process whose state changed, and 114/// the status of said process. 115/// 116/// If `NOHANG` was specified in the options, and the selected child process 117/// didn't change state, returns `None`. 118/// 119/// # References 120/// - [POSIX] 121/// - [Linux] 122/// 123/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html 124/// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html 125#[cfg(not(target_os = "wasi"))] 126#[inline] 127pub fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { 128 backend::process::syscalls::wait(waitopts) 129} 130