Skip to content

Commit 5c12771

Browse files
committed
fixup! Change ChildPidWatcher to use pidfd and epoll
1 parent f3874cd commit 5c12771

1 file changed

Lines changed: 23 additions & 10 deletions

File tree

src/main/utility/childpid_watcher.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ use std::sync::Arc;
1010
use std::sync::Mutex;
1111
use 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.
1316
pub 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

7174
impl 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

Comments
 (0)