1 use crate::process::Pid;
2 use crate::{backend, io};
3 use bitflags::bitflags;
4
5 bitflags! {
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)]
19 pub struct WaitStatus(u32);
20
21 impl WaitStatus {
22 /// create a `WaitStatus` out of an integer.
23 #[inline]
new(status: u32) -> Self24 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]
as_raw(self) -> u3230 pub const fn as_raw(self) -> u32 {
31 self.0
32 }
33
34 /// Returns whether the process is currently stopped.
35 #[inline]
stopped(self) -> bool36 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]
continued(self) -> bool42 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]
stopping_signal(self) -> Option<u32>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]
exit_status(self) -> Option<u32>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]
terminating_signal(self) -> Option<u32>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]
waitpid(pid: Option<Pid>, waitopts: WaitOptions) -> io::Result<Option<WaitStatus>>106 pub 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]
wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>>127 pub fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
128 backend::process::syscalls::wait(waitopts)
129 }
130