@@ -10,6 +10,9 @@ use std::sync::Arc;
1010use std:: sync:: Mutex ;
1111use std:: thread;
1212
13+ /// Utility for monitoring a set of child pid's, calling registered callbacks
14+ /// when one exits or is killed. Starts a background thread, which is shut down
15+ /// when the object is dropped.
1316pub struct ChildPidWatcher {
1417 inner : Arc < Mutex < Inner > > ,
1518 epoll : std:: os:: unix:: io:: RawFd ,
@@ -69,7 +72,8 @@ fn is_zombie(pid: Pid) -> bool {
6972}
7073
7174impl ChildPidWatcher {
72- /// Get a reference to the global singleton watcher.
75+ /// Create a ChildPidWatcher. Spawns a background thread, which is joined
76+ /// when the object is dropped.
7377 pub fn new ( ) -> Self {
7478 let epoll = epoll_create1 ( EpollCreateFlags :: empty ( ) ) . unwrap ( ) ;
7579 let command_notifier =
@@ -94,7 +98,7 @@ impl ChildPidWatcher {
9498 epoll,
9599 } ;
96100 let thread_handle = {
97- let inner = watcher. inner . clone ( ) ;
101+ let inner = Arc :: clone ( & watcher. inner ) ;
98102 let epoll = watcher. epoll ;
99103 thread:: Builder :: new ( )
100104 . name ( "child-pid-watcher" . into ( ) )
@@ -133,14 +137,22 @@ impl ChildPidWatcher {
133137 Err ( nix:: Error :: Sys ( nix:: errno:: Errno :: EAGAIN ) ) => true ,
134138 Err ( e) => panic!( "Unexpected error {:?}" , e) ,
135139 } ) ;
136- // Run commands
140+ // Run commands
137141 std:: mem:: swap ( & mut commands, & mut inner. commands ) ;
138142 for cmd in commands. drain ( ..) {
139143 match cmd {
140144 Command :: RunCallbacks ( pid) => {
141145 inner. run_callbacks_for_fd ( epoll, pid) ;
142146 }
143- Command :: Finish => done = true ,
147+ Command :: Finish => {
148+ done = true ;
149+ // There could be more commands queued and/or more epoll
150+ // events ready, but it doesn't matter. We don't
151+ // guarantee to callers whether callbacks have run or
152+ // not after having sent `Finish`; only that no more
153+ // callbacks will run after the thread is joined.
154+ break ;
155+ }
144156 }
145157 }
146158 }
@@ -153,7 +165,7 @@ impl ChildPidWatcher {
153165 /// The returned handle is guaranteed to be non-zero.
154166 ///
155167 /// Panics if `pid` doesn't exist.
156- pub fn watch ( & self , pid : Pid , callback : Box < dyn Send + FnOnce ( Pid ) > ) -> WatchHandle {
168+ pub fn watch ( & self , pid : Pid , callback : impl Send + FnOnce ( Pid ) + ' static ) -> WatchHandle {
157169 let mut inner = self . inner . lock ( ) . unwrap ( ) ;
158170 if !inner. pidfds . contains_key ( & pid) {
159171 let pidfd: RawFd = unsafe { libc:: syscall ( libc:: SYS_pidfd_open , pid. as_raw ( ) , 0 ) }
@@ -174,7 +186,7 @@ impl ChildPidWatcher {
174186 let handle = inner. next_handle ;
175187 inner. next_handle += 1 ;
176188 let callbacks = inner. callbacks . entry ( pid) . or_default ( ) ;
177- callbacks. insert ( handle, callback) ;
189+ callbacks. insert ( handle, Box :: new ( callback) ) ;
178190 handle
179191 }
180192
@@ -441,10 +453,11 @@ mod export {
441453 data : * mut libc:: c_void ,
442454 ) -> WatchHandle {
443455 let data = SyncSendPointer ( data) ;
444- unsafe { watcher. as_ref ( ) } . unwrap ( ) . watch (
445- Pid :: from_raw ( pid) ,
446- Box :: new ( move |pid| callback ( pid. into ( ) , data. ptr ( ) ) ) ,
447- )
456+ unsafe { watcher. as_ref ( ) }
457+ . unwrap ( )
458+ . watch ( Pid :: from_raw ( pid) , move |pid| {
459+ callback ( pid. into ( ) , data. ptr ( ) )
460+ } )
448461 }
449462
450463 /// Unregisters a callback. After returning, the corresponding callback is
0 commit comments