Add a method to ProcessReaper to forget a tracked pid
Allow callers to remove a tracked pid if tracking is
no longer desired (e.g., if the caller has reaped the
process themselves.)
BUG=chromium:535910
Change-Id: Ie056c54a66c5aed539d2a77a41135f9b2da66582
diff --git a/brillo/process_reaper.cc b/brillo/process_reaper.cc
index 5ee1195..c2f81b2 100644
--- a/brillo/process_reaper.cc
+++ b/brillo/process_reaper.cc
@@ -45,6 +45,10 @@
return true;
}
+bool ProcessReaper::ForgetChild(pid_t pid) {
+ return watched_processes_.erase(pid) != 0;
+}
+
bool ProcessReaper::HandleSIGCHLD(const struct signalfd_siginfo& sigfd_info) {
// One SIGCHLD may correspond to multiple terminated children, so ignore
// sigfd_info and reap any available children.
diff --git a/brillo/process_reaper.h b/brillo/process_reaper.h
index d88f572..937c88c 100644
--- a/brillo/process_reaper.h
+++ b/brillo/process_reaper.h
@@ -44,6 +44,13 @@
pid_t pid,
const ChildCallback& callback);
+ // Stop watching child process |pid|. This is useful in situations
+ // where the child process may have been reaped outside of the signal
+ // handler, or the caller is no longer interested in being notified about
+ // this child process anymore. Returns true if a child was removed from
+ // the watchlist.
+ bool ForgetChild(pid_t pid);
+
private:
// SIGCHLD handler for the AsynchronousSignalHandler. Always returns false
// (meaning that the signal handler should not be unregistered).
diff --git a/brillo/process_reaper_unittest.cc b/brillo/process_reaper_unittest.cc
index 499b908..ae888d2 100644
--- a/brillo/process_reaper_unittest.cc
+++ b/brillo/process_reaper_unittest.cc
@@ -118,4 +118,24 @@
brillo_loop_.Run();
}
+TEST_F(ProcessReaperTest, ReapKilledAndForgottenChild) {
+ pid_t pid = ForkChildAndExit(0);
+ EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::Bind(
+ [this](const siginfo_t& info) {
+ ADD_FAILURE() << "Child process was still tracked.";
+ this->brillo_loop_.BreakLoop();
+ })));
+ EXPECT_TRUE(process_reaper_.ForgetChild(pid));
+
+ // A second call should return failure.
+ EXPECT_FALSE(process_reaper_.ForgetChild(pid));
+
+ // Run the loop with a timeout, as the BreakLoop() above is not expected.
+ brillo_loop_.PostDelayedTask(FROM_HERE,
+ base::Bind(&MessageLoop::BreakLoop,
+ base::Unretained(&brillo_loop_)),
+ base::TimeDelta::FromMilliseconds(100));
+ brillo_loop_.Run();
+}
+
} // namespace brillo