1
- use cfg_if:: cfg_if;
2
- use libc:: { self , c_int} ;
3
- use crate :: Result ;
4
1
use crate :: errno:: Errno ;
5
- use crate :: unistd:: Pid ;
6
2
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 } ;
8
8
9
9
libc_bitflags ! (
10
10
pub struct WaitPidFlag : c_int {
@@ -50,6 +50,36 @@ libc_bitflags!(
50
50
}
51
51
) ;
52
52
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
+
53
83
/// Possible return values from `wait()` or `waitpid()`.
54
84
///
55
85
/// Each status (other than `StillAlive`) describes a state transition
@@ -214,7 +244,11 @@ impl WaitStatus {
214
244
}
215
245
}
216
246
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 > {
218
252
use self :: WaitStatus :: * ;
219
253
220
254
let mut status: i32 = 0 ;
@@ -224,20 +258,25 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re
224
258
None => 0 ,
225
259
} ;
226
260
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
+ }
233
269
} ;
234
270
271
+ let res = unsafe { libc:: waitpid ( pid, & mut status as * mut c_int , option_bits) } ;
272
+
235
273
match Errno :: result ( res) ? {
236
274
0 => Ok ( StillAlive ) ,
237
275
res => WaitStatus :: from_raw ( Pid :: from_raw ( res) , status) ,
238
276
}
239
277
}
240
278
279
+ /// Wrapper around `libc::wait` to wait until any child process terminates.
241
280
pub fn wait ( ) -> Result < WaitStatus > {
242
- waitpid ( None , None )
281
+ waitpid ( WaitTarget :: AnyChild , None )
243
282
}
0 commit comments