• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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