Skip to content

Commit 6db9c3d

Browse files
committed
Add WaitTarget for waitpid
Based on nix-rust#848 by @serejkus Fix nix-rust#840
1 parent ea099dd commit 6db9c3d

File tree

1 file changed

+52
-13
lines changed

1 file changed

+52
-13
lines changed

src/sys/wait.rs

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use cfg_if::cfg_if;
2-
use libc::{self, c_int};
3-
use crate::Result;
41
use crate::errno::Errno;
5-
use crate::unistd::Pid;
62
use crate::sys::signal::Signal;
7-
use std::convert::TryFrom;
3+
use crate::unistd::Pid;
4+
use crate::Result;
5+
use cfg_if::cfg_if;
6+
use libc::{self, c_int};
7+
use std::convert::{From, Into, TryFrom};
88

99
libc_bitflags!(
1010
pub struct WaitPidFlag: c_int {
@@ -50,6 +50,36 @@ libc_bitflags!(
5050
}
5151
);
5252

53+
/// Possible child targets of `waitpid()`.
54+
///
55+
/// The most common variants for waiting are waiting for a specific
56+
/// child via `WaitPid::Child(pid)` and waiting for any child via
57+
/// `WaitPid::AnyChild`.
58+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
59+
pub enum WaitTarget {
60+
/// A child process with `Pid` process id.
61+
Child(Pid),
62+
/// Any child process of the same process group as the calling process.
63+
SameGroupChild,
64+
/// Any child process.
65+
AnyChild,
66+
/// Any child process of `Pid` process group id. Note, do not negate
67+
/// this value, use process id of group leader instead.
68+
ChildOfGroup(Pid),
69+
}
70+
71+
impl From<Pid> for WaitTarget {
72+
/// Convert libc `pid_t` to `waitpid`'s `pid` as Rust safe `WaitTarget`.
73+
fn from(pid: Pid) -> WaitTarget {
74+
match pid.as_raw() {
75+
i if i > 0 => WaitTarget::Child(pid),
76+
-1 => WaitTarget::AnyChild,
77+
0 => WaitTarget::SameGroupChild,
78+
_ => WaitTarget::ChildOfGroup(pid),
79+
}
80+
}
81+
}
82+
5383
/// Possible return values from `wait()` or `waitpid()`.
5484
///
5585
/// Each status (other than `StillAlive`) describes a state transition
@@ -214,7 +244,11 @@ impl WaitStatus {
214244
}
215245
}
216246

217-
pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
247+
/// Wrapper around `libc::waitpid` that uses [`WaitTarget`] to determine
248+
/// `Pid` target. It waits for the specified `who` target optionally with
249+
/// [`WaitPidFlag`] to specify options for waiting and return the result of
250+
/// [`WaitStatus`].
251+
pub fn waitpid<P: Into<WaitTarget>>(who: P, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
218252
use self::WaitStatus::*;
219253

220254
let mut status: i32 = 0;
@@ -224,20 +258,25 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re
224258
None => 0,
225259
};
226260

227-
let res = unsafe {
228-
libc::waitpid(
229-
pid.into().unwrap_or_else(|| Pid::from_raw(-1)).into(),
230-
&mut status as *mut c_int,
231-
option_bits,
232-
)
261+
let pid = match who.into() {
262+
WaitTarget::Child(pid) => pid.into(),
263+
WaitTarget::SameGroupChild => 0,
264+
WaitTarget::AnyChild => -1,
265+
WaitTarget::ChildOfGroup(pid) => {
266+
let pid: libc::pid_t = pid.into();
267+
-pid
268+
}
233269
};
234270

271+
let res = unsafe { libc::waitpid(pid, &mut status as *mut c_int, option_bits) };
272+
235273
match Errno::result(res)? {
236274
0 => Ok(StillAlive),
237275
res => WaitStatus::from_raw(Pid::from_raw(res), status),
238276
}
239277
}
240278

279+
/// Wrapper around `libc::wait` to wait until any child process terminates.
241280
pub fn wait() -> Result<WaitStatus> {
242-
waitpid(None, None)
281+
waitpid(WaitTarget::AnyChild, None)
243282
}

0 commit comments

Comments
 (0)