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/location_logging.h> 15 16 namespace brillo { 17 18 ProcessReaper::~ProcessReaper() { 19 Unregister(); 20 } 21 22 void ProcessReaper::Register( 23 AsynchronousSignalHandlerInterface* async_signal_handler) { 24 CHECK(!async_signal_handler_); 25 async_signal_handler_ = async_signal_handler; 26 async_signal_handler->RegisterHandler( 27 SIGCHLD, 28 base::Bind(&ProcessReaper::HandleSIGCHLD, base::Unretained(this))); 29 } 30 31 void ProcessReaper::Unregister() { 32 if (!async_signal_handler_) 33 return; 34 async_signal_handler_->UnregisterHandler(SIGCHLD); 35 async_signal_handler_ = nullptr; 36 } 37 38 bool ProcessReaper::WatchForChild(const base::Location& from_here, 39 pid_t pid, 40 const ChildCallback& callback) { 41 if (watched_processes_.find(pid) != watched_processes_.end()) 42 return false; 43 watched_processes_.emplace(pid, WatchedProcess{from_here, callback}); 44 return true; 45 } 46 47 bool ProcessReaper::ForgetChild(pid_t pid) { 48 return watched_processes_.erase(pid) != 0; 49 } 50 51 bool ProcessReaper::HandleSIGCHLD( 52 const struct signalfd_siginfo& /* sigfd_info */) { 53 // One SIGCHLD may correspond to multiple terminated children, so ignore 54 // sigfd_info and reap any available children. 55 while (true) { 56 siginfo_t info; 57 info.si_pid = 0; 58 int rc = HANDLE_EINTR(waitid(P_ALL, 0, &info, WNOHANG | WEXITED)); 59 60 if (rc == -1) { 61 if (errno != ECHILD) { 62 PLOG(ERROR) << "waitid failed"; 63 } 64 break; 65 } 66 67 if (info.si_pid == 0) { 68 break; 69 } 70 71 auto proc = watched_processes_.find(info.si_pid); 72 if (proc == watched_processes_.end()) { 73 LOG(INFO) << "Untracked process " << info.si_pid 74 << " terminated with status " << info.si_status 75 << " (code = " << info.si_code << ")"; 76 } else { 77 DVLOG_LOC(proc->second.location, 1) 78 << "Process " << info.si_pid << " terminated with status " 79 << info.si_status << " (code = " << info.si_code << ")"; 80 ChildCallback callback = std::move(proc->second.callback); 81 watched_processes_.erase(proc); 82 callback.Run(info); 83 } 84 } 85 86 // Return false to indicate that our handler should not be uninstalled. 87 return false; 88 } 89 90 } // namespace brillo 91