1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be
3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file.
4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/process/kill.h"
6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
7cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include <errno.h>
8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <signal.h>
9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <sys/types.h>
10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <sys/wait.h>
11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <unistd.h>
12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/files/file_util.h"
14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/files/scoped_file.h"
15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/logging.h"
16cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include "base/macros.h"
17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/posix/eintr_wrapper.h"
18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/process/process_iterator.h"
19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/synchronization/waitable_event.h"
20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/platform_thread.h"
21cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include "build/build_config.h"
22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base {
24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace {
26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                           bool can_block,
29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                           int* exit_code) {
30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int status = 0;
31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const pid_t result = HANDLE_EINTR(waitpid(handle, &status,
32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                            can_block ? 0 : WNOHANG));
33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (result == -1) {
34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    DPLOG(ERROR) << "waitpid(" << handle << ")";
35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (exit_code)
36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      *exit_code = 0;
37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return TERMINATION_STATUS_NORMAL_TERMINATION;
38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  } else if (result == 0) {
39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // the child hasn't exited yet.
40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (exit_code)
41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      *exit_code = 0;
42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return TERMINATION_STATUS_STILL_RUNNING;
43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (exit_code)
46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    *exit_code = status;
47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (WIFSIGNALED(status)) {
49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    switch (WTERMSIG(status)) {
50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      case SIGABRT:
51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      case SIGBUS:
52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      case SIGFPE:
53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      case SIGILL:
54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      case SIGSEGV:
55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        return TERMINATION_STATUS_PROCESS_CRASHED;
56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      case SIGKILL:
57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#if defined(OS_CHROMEOS)
58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        // On ChromeOS, only way a process gets kill by SIGKILL
59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        // is by oom-killer.
60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        return TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM;
61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif
62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      case SIGINT:
63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      case SIGTERM:
64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        return TERMINATION_STATUS_PROCESS_WAS_KILLED;
65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      default:
66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        break;
67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
72b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
73b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return TERMINATION_STATUS_NORMAL_TERMINATION;
74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
75b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace
77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#if !defined(OS_NACL_NONSFI)
79b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbool KillProcessGroup(ProcessHandle process_group_id) {
80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool result = kill(-1 * process_group_id, SIGKILL) == 0;
81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!result)
82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    DPLOG(ERROR) << "Unable to terminate process group " << process_group_id;
83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return result;
84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif  // !defined(OS_NACL_NONSFI)
86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return GetTerminationStatusImpl(handle, false /* can_block */, exit_code);
89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTerminationStatus GetKnownDeadTerminationStatus(ProcessHandle handle,
92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                                int* exit_code) {
93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool result = kill(handle, SIGKILL) == 0;
94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!result)
96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    DPLOG(ERROR) << "Unable to terminate process " << handle;
97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return GetTerminationStatusImpl(handle, true /* can_block */, exit_code);
99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#if !defined(OS_NACL_NONSFI)
102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbool WaitForProcessesToExit(const FilePath::StringType& executable_name,
103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                            TimeDelta wait,
104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                            const ProcessFilter* filter) {
105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool result = false;
106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // TODO(port): This is inefficient, but works if there are multiple procs.
108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // TODO(port): use waitpid to avoid leaving zombies around
109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  TimeTicks end_time = TimeTicks::Now() + wait;
111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  do {
112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    NamedProcessIterator iter(executable_name, filter);
113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (!iter.NextProcessEntry()) {
114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      result = true;
115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      break;
116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  } while ((end_time - TimeTicks::Now()) > TimeDelta());
119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return result;
121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbool CleanupProcesses(const FilePath::StringType& executable_name,
124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                      TimeDelta wait,
125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                      int exit_code,
126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                      const ProcessFilter* filter) {
127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!exited_cleanly)
129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    KillProcesses(executable_name, exit_code, filter);
130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return exited_cleanly;
131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#if !defined(OS_MACOSX)
134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace {
136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Return true if the given child is dead. This will also reap the process.
138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Doesn't block.
139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratstatic bool IsChildDead(pid_t child) {
140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (result == -1) {
142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    DPLOG(ERROR) << "waitpid(" << child << ")";
143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    NOTREACHED();
144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  } else if (result > 0) {
145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // The child has died.
146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return true;
147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return false;
150b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// A thread class which waits for the given child to exit and reaps it.
153b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// If the child doesn't exit within a couple of seconds, kill it.
154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass BackgroundReaper : public PlatformThread::Delegate {
155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public:
156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  BackgroundReaper(pid_t child, unsigned timeout)
157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      : child_(child),
158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        timeout_(timeout) {
159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Overridden from PlatformThread::Delegate:
162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  void ThreadMain() override {
163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    WaitForChildToDie();
164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    delete this;
165b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  void WaitForChildToDie() {
168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Wait forever case.
169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (timeout_ == 0) {
170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0));
171b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (r != child_) {
172b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        DPLOG(ERROR) << "While waiting for " << child_
173b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                     << " to terminate, we got the following result: " << r;
174b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
175b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      return;
176b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
177b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
178b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // There's no good way to wait for a specific child to exit in a timed
179b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // fashion. (No kqueue on Linux), so we just loop and sleep.
180b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
181b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Wait for 2 * timeout_ 500 milliseconds intervals.
182b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    for (unsigned i = 0; i < 2 * timeout_; ++i) {
183b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
184b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (IsChildDead(child_))
185b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        return;
186b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
187b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
188b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (kill(child_, SIGKILL) == 0) {
189b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // SIGKILL is uncatchable. Since the signal was delivered, we can
190b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      // just wait for the process to die now in a blocking manner.
191b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0)
192b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        DPLOG(WARNING) << "waitpid";
193b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    } else {
194b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      DLOG(ERROR) << "While waiting for " << child_ << " to terminate we"
195b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                  << " failed to deliver a SIGKILL signal (" << errno << ").";
196b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
197b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
198b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
199b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private:
200b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const pid_t child_;
201b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Number of seconds to wait, if 0 then wait forever and do not attempt to
202b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // kill |child_|.
203b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const unsigned timeout_;
204b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
205b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DISALLOW_COPY_AND_ASSIGN(BackgroundReaper);
206b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat};
207b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
208b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace
209b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
210b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid EnsureProcessTerminated(Process process) {
211b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // If the child is already dead, then there's nothing to do.
212b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (IsChildDead(process.Pid()))
213b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
214b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
215b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const unsigned timeout = 2;  // seconds
216b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  BackgroundReaper* reaper = new BackgroundReaper(process.Pid(), timeout);
217b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  PlatformThread::CreateNonJoinable(0, reaper);
218b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
219b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
220b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid EnsureProcessGetsReaped(ProcessId pid) {
221b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // If the child is already dead, then there's nothing to do.
222b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (IsChildDead(pid))
223b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
224b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
225b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  BackgroundReaper* reaper = new BackgroundReaper(pid, 0);
226b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  PlatformThread::CreateNonJoinable(0, reaper);
227b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
228b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
229b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif  // !defined(OS_MACOSX)
230b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif  // !defined(OS_NACL_NONSFI)
231b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
232b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace base
233