1471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo// Copyright 2015 The Chromium OS Authors. All rights reserved.
2471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo// Use of this source code is governed by a BSD-style license that can be
3471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo// found in the LICENSE file.
4471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include "brillo/process_reaper.h"
6471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
7471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo#include <sys/signalfd.h>
8471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo#include <sys/types.h>
9471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo#include <sys/wait.h>
10471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
11471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo#include <base/bind.h>
12471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo#include <base/posix/eintr_wrapper.h>
139ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/asynchronous_signal_handler.h>
149ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/daemons/daemon.h>
159ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/location_logging.h>
16471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
179ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo {
18471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
19471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex DeymoProcessReaper::~ProcessReaper() {
2038c16335b69d8f6611746e6267bc68105e237e97Alex Deymo  Unregister();
21471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo}
22471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
2338c16335b69d8f6611746e6267bc68105e237e97Alex Deymovoid ProcessReaper::Register(
249ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    AsynchronousSignalHandlerInterface* async_signal_handler) {
2538c16335b69d8f6611746e6267bc68105e237e97Alex Deymo  CHECK(!async_signal_handler_);
26471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  async_signal_handler_ = async_signal_handler;
27471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  async_signal_handler->RegisterHandler(
28471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      SIGCHLD,
29471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      base::Bind(&ProcessReaper::HandleSIGCHLD, base::Unretained(this)));
30471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo}
31471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
32471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymovoid ProcessReaper::Unregister() {
3338c16335b69d8f6611746e6267bc68105e237e97Alex Deymo  if (!async_signal_handler_)
3438c16335b69d8f6611746e6267bc68105e237e97Alex Deymo    return;
3538c16335b69d8f6611746e6267bc68105e237e97Alex Deymo  async_signal_handler_->UnregisterHandler(SIGCHLD);
3638c16335b69d8f6611746e6267bc68105e237e97Alex Deymo  async_signal_handler_ = nullptr;
37471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo}
38471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
39471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymobool ProcessReaper::WatchForChild(const tracked_objects::Location& from_here,
40471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo                                  pid_t pid,
41471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo                                  const ChildCallback& callback) {
42471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  if (watched_processes_.find(pid) != watched_processes_.end())
43471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    return false;
44471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  watched_processes_.emplace(pid, WatchedProcess{from_here, callback});
45471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  return true;
46471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo}
47471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
48b6a5c6113b0b7ae947c5a1729d4b9d08287a83e2Paul Stewartbool ProcessReaper::ForgetChild(pid_t pid) {
49b6a5c6113b0b7ae947c5a1729d4b9d08287a83e2Paul Stewart  return watched_processes_.erase(pid) != 0;
50b6a5c6113b0b7ae947c5a1729d4b9d08287a83e2Paul Stewart}
51b6a5c6113b0b7ae947c5a1729d4b9d08287a83e2Paul Stewart
522fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wileybool ProcessReaper::HandleSIGCHLD(
532fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley    const struct signalfd_siginfo& /* sigfd_info */) {
54471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  // One SIGCHLD may correspond to multiple terminated children, so ignore
55471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  // sigfd_info and reap any available children.
56471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  while (true) {
57471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    siginfo_t info;
58471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    info.si_pid = 0;
59471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    int rc = HANDLE_EINTR(waitid(P_ALL, 0, &info, WNOHANG | WEXITED));
60471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
61471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    if (rc == -1) {
62471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      if (errno != ECHILD) {
63471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo        PLOG(ERROR) << "waitid failed";
64471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      }
65471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      break;
66471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    }
67471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
68471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    if (info.si_pid == 0) {
69471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      break;
70471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    }
71471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
72471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    auto proc = watched_processes_.find(info.si_pid);
73471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    if (proc == watched_processes_.end()) {
744a71a24c29810f08dfa39610e2c6f22e134e3df1Jorge Lucangeli Obes      LOG(INFO) << "Untracked process " << info.si_pid
75471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo                << " terminated with status " << info.si_status
76471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo                << " (code = " << info.si_code << ")";
77471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    } else {
78471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      DVLOG_LOC(proc->second.location, 1)
79471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo          << "Process " << info.si_pid << " terminated with status "
80471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo          << info.si_status << " (code = " << info.si_code << ")";
81471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      ChildCallback callback = std::move(proc->second.callback);
82471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      watched_processes_.erase(proc);
83471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo      callback.Run(info);
84471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo    }
85471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  }
86471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
87471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  // Return false to indicate that our handler should not be uninstalled.
88471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo  return false;
89471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo}
90471776dcf9a6a861e3f9f63121fd13b1a1b3f180Alex Deymo
919ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko}  // namespace brillo
92