• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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