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 19 ProcessReaper::~ProcessReaper() { 20 Unregister(); 21 } 22 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 32 void ProcessReaper::Unregister() { 33 if (!async_signal_handler_) 34 return; 35 async_signal_handler_->UnregisterHandler(SIGCHLD); 36 async_signal_handler_ = nullptr; 37 } 38 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 48 bool ProcessReaper::ForgetChild(pid_t pid) { 49 return watched_processes_.erase(pid) != 0; 50 } 51 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