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