1 // Copyright 2015 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "brillo/process_reaper.h"
6
7 #include <sys/signalfd.h>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10
11 #include <base/bind.h>
12 #include <base/posix/eintr_wrapper.h>
13 #include <brillo/asynchronous_signal_handler.h>
14 #include <brillo/daemons/daemon.h>
15 #include <brillo/location_logging.h>
16
17 namespace brillo {
18
~ProcessReaper()19 ProcessReaper::~ProcessReaper() {
20 Unregister();
21 }
22
Register(AsynchronousSignalHandlerInterface * async_signal_handler)23 void ProcessReaper::Register(
24 AsynchronousSignalHandlerInterface* async_signal_handler) {
25 CHECK(!async_signal_handler_);
26 async_signal_handler_ = async_signal_handler;
27 async_signal_handler->RegisterHandler(
28 SIGCHLD,
29 base::Bind(&ProcessReaper::HandleSIGCHLD, base::Unretained(this)));
30 }
31
Unregister()32 void ProcessReaper::Unregister() {
33 if (!async_signal_handler_)
34 return;
35 async_signal_handler_->UnregisterHandler(SIGCHLD);
36 async_signal_handler_ = nullptr;
37 }
38
WatchForChild(const tracked_objects::Location & from_here,pid_t pid,const ChildCallback & callback)39 bool ProcessReaper::WatchForChild(const tracked_objects::Location& from_here,
40 pid_t pid,
41 const ChildCallback& callback) {
42 if (watched_processes_.find(pid) != watched_processes_.end())
43 return false;
44 watched_processes_.emplace(pid, WatchedProcess{from_here, callback});
45 return true;
46 }
47
ForgetChild(pid_t pid)48 bool ProcessReaper::ForgetChild(pid_t pid) {
49 return watched_processes_.erase(pid) != 0;
50 }
51
HandleSIGCHLD(const struct signalfd_siginfo &)52 bool ProcessReaper::HandleSIGCHLD(
53 const struct signalfd_siginfo& /* sigfd_info */) {
54 // One SIGCHLD may correspond to multiple terminated children, so ignore
55 // sigfd_info and reap any available children.
56 while (true) {
57 siginfo_t info;
58 info.si_pid = 0;
59 int rc = HANDLE_EINTR(waitid(P_ALL, 0, &info, WNOHANG | WEXITED));
60
61 if (rc == -1) {
62 if (errno != ECHILD) {
63 PLOG(ERROR) << "waitid failed";
64 }
65 break;
66 }
67
68 if (info.si_pid == 0) {
69 break;
70 }
71
72 auto proc = watched_processes_.find(info.si_pid);
73 if (proc == watched_processes_.end()) {
74 LOG(INFO) << "Untracked process " << info.si_pid
75 << " terminated with status " << info.si_status
76 << " (code = " << info.si_code << ")";
77 } else {
78 DVLOG_LOC(proc->second.location, 1)
79 << "Process " << info.si_pid << " terminated with status "
80 << info.si_status << " (code = " << info.si_code << ")";
81 ChildCallback callback = std::move(proc->second.callback);
82 watched_processes_.erase(proc);
83 callback.Run(info);
84 }
85 }
86
87 // Return false to indicate that our handler should not be uninstalled.
88 return false;
89 }
90
91 } // namespace brillo
92