17dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
27dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
37dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// found in the LICENSE file.
47dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/process/kill.h"
67dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include <signal.h>
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include <sys/types.h>
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include <sys/wait.h>
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include <unistd.h>
117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/file_util.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/files/scoped_file.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/logging.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/posix/eintr_wrapper.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/process/process_iterator.h"
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/synchronization/waitable_event.h"
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/threading/platform_thread.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace base {
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace {
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool WaitpidWithTimeout(ProcessHandle handle,
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        int* status,
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        base::TimeDelta wait) {
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // This POSIX version of this function only guarantees that we wait no less
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // than |wait| for the process to exit.  The child process may
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // exit sometime before the timeout has ended but we may still block for up
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // to 256 milliseconds after the fact.
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  //
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // waitpid() has no direct support on POSIX for specifying a timeout, you can
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // either ask it to block indefinitely or return immediately (WNOHANG).
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // When a child process terminates a SIGCHLD signal is sent to the parent.
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Catching this signal would involve installing a signal handler which may
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // affect other parts of the application and would be difficult to debug.
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  //
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Our strategy is to call waitpid() once up front to check if the process
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // has already exited, otherwise to loop for |wait|, sleeping for
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // at most 256 milliseconds each time using usleep() and then calling
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // waitpid().  The amount of time we sleep starts out at 1 milliseconds, and
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // we double it every 4 sleep cycles.
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  //
457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // usleep() is speced to exit if a signal is received for which a handler
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // has been installed.  This means that when a SIGCHLD is sent, it will exit
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // depending on behavior external to this function.
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  //
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // This function is used primarily for unit tests, if we want to use it in
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // the application itself it would probably be best to examine other routes.
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (wait.InMilliseconds() == base::kNoTimeout) {
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return HANDLE_EINTR(waitpid(handle, status, 0)) > 0;
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  static const int64 kMaxSleepInMicroseconds = 1 << 18;  // ~256 milliseconds.
587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int64 max_sleep_time_usecs = 1 << 10;  // ~1 milliseconds.
597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int64 double_sleep_time = 0;
607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If the process hasn't exited yet, then sleep and try again.
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  TimeTicks wakeup_time = TimeTicks::Now() + wait;
637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  while (ret_pid == 0) {
647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    TimeTicks now = TimeTicks::Now();
657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (now > wakeup_time)
667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      break;
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Guaranteed to be non-negative!
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Sleep for a bit while we wait for the process to finish.
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (sleep_time_usecs > max_sleep_time_usecs)
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      sleep_time_usecs = max_sleep_time_usecs;
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // usleep() will return 0 and set errno to EINTR on receipt of a signal
747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // such as SIGCHLD.
757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    usleep(sleep_time_usecs);
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        (double_sleep_time++ % 4 == 0)) {
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      max_sleep_time_usecs *= 2;
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return ret_pid > 0;
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                           bool can_block,
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                           int* exit_code) {
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int status = 0;
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const pid_t result = HANDLE_EINTR(waitpid(handle, &status,
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                            can_block ? 0 : WNOHANG));
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (result == -1) {
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DPLOG(ERROR) << "waitpid(" << handle << ")";
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (exit_code)
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      *exit_code = 0;
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return TERMINATION_STATUS_NORMAL_TERMINATION;
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else if (result == 0) {
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // the child hasn't exited yet.
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (exit_code)
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      *exit_code = 0;
1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return TERMINATION_STATUS_STILL_RUNNING;
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (exit_code)
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    *exit_code = status;
1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (WIFSIGNALED(status)) {
1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    switch (WTERMSIG(status)) {
1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      case SIGABRT:
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      case SIGBUS:
1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      case SIGFPE:
1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      case SIGILL:
1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      case SIGSEGV:
1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        return TERMINATION_STATUS_PROCESS_CRASHED;
1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      case SIGINT:
1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      case SIGKILL:
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      case SIGTERM:
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        return TERMINATION_STATUS_PROCESS_WAS_KILLED;
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      default:
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        break;
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return TERMINATION_STATUS_NORMAL_TERMINATION;
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Attempts to kill the process identified by the given process
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// entry structure.  Ignores specified exit_code; posix can't force that.
1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Returns true if this is successful, false otherwise.
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GT(process_id, 1) << " tried to kill invalid process_id";
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (process_id <= 1)
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool result = kill(process_id, SIGTERM) == 0;
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (result && wait) {
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int tries = 60;
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (RunningOnValgrind()) {
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // Wait for some extra time when running under Valgrind since the child
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // processes may take some time doing leak checking.
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      tries *= 2;
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    unsigned sleep_ms = 4;
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // The process may not end immediately due to pending I/O
1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    bool exited = false;
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    while (tries-- > 0) {
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG));
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (pid == process_id) {
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        exited = true;
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        break;
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      }
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (pid == -1) {
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if (errno == ECHILD) {
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          // The wait may fail with ECHILD if another process also waited for
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          // the same pid, causing the process state to get cleaned up.
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          exited = true;
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          break;
1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        }
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        DPLOG(ERROR) << "Error waiting for process " << process_id;
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      }
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      usleep(sleep_ms * 1000);
1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      const unsigned kMaxSleepMs = 1000;
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (sleep_ms < kMaxSleepMs)
1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        sleep_ms *= 2;
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // If we're waiting and the child hasn't died by now, force it
1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // with a SIGKILL.
1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!exited)
1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      result = kill(process_id, SIGKILL) == 0;
1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!result)
1837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DPLOG(ERROR) << "Unable to terminate process " << process_id;
1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return result;
1867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool KillProcessGroup(ProcessHandle process_group_id) {
1897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool result = kill(-1 * process_group_id, SIGKILL) == 0;
1907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!result)
1917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DPLOG(ERROR) << "Unable to terminate process group " << process_group_id;
1927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return result;
1937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1957dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
1967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return GetTerminationStatusImpl(handle, false /* can_block */, exit_code);
1977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
199d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)TerminationStatus GetKnownDeadTerminationStatus(ProcessHandle handle,
200d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                                int* exit_code) {
201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bool result = kill(handle, SIGKILL) == 0;
202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!result)
204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DPLOG(ERROR) << "Unable to terminate process " << handle;
205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return GetTerminationStatusImpl(handle, true /* can_block */, exit_code);
2077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool WaitForExitCode(ProcessHandle handle, int* exit_code) {
2107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int status;
2117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) {
2127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    NOTREACHED();
2137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (WIFEXITED(status)) {
2177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    *exit_code = WEXITSTATUS(status);
2187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return true;
2197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If it didn't exit cleanly, it must have been signaled.
2227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(WIFSIGNALED(status));
2237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return false;
2247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool WaitForExitCodeWithTimeout(ProcessHandle handle,
2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                int* exit_code,
2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                base::TimeDelta timeout) {
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int status;
230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!WaitpidWithTimeout(handle, &status, timeout))
2317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (WIFSIGNALED(status)) {
2337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    *exit_code = -1;
2347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return true;
2357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (WIFEXITED(status)) {
2377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    *exit_code = WEXITSTATUS(status);
2387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return true;
2397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return false;
2417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool WaitForProcessesToExit(const FilePath::StringType& executable_name,
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            base::TimeDelta wait,
2457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            const ProcessFilter* filter) {
2467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool result = false;
2477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(port): This is inefficient, but works if there are multiple procs.
2497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(port): use waitpid to avoid leaving zombies around
2507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::TimeTicks end_time = base::TimeTicks::Now() + wait;
2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  do {
2537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    NamedProcessIterator iter(executable_name, filter);
2547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!iter.NextProcessEntry()) {
2557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      result = true;
2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      break;
2577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
2587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
2597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta());
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return result;
2627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#if defined(OS_MACOSX)
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Using kqueue on Mac so that we can wait on non-child processes.
2667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// We can't use kqueues on child processes because we need to reap
2677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// our own children using wait.
2687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstatic bool WaitForSingleNonChildProcess(ProcessHandle handle,
2697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                         base::TimeDelta wait) {
2707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_GT(handle, 0);
2717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta());
2727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ScopedFD kq(kqueue());
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!kq.is_valid()) {
2757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DPLOG(ERROR) << "kqueue";
2767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  struct kevent change = {0};
2807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
2827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (result == -1) {
2837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (errno == ESRCH) {
2847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // If the process wasn't found, it must be dead.
2857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return true;
2867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
2877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DPLOG(ERROR) << "kevent (setup " << handle << ")";
2897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Keep track of the elapsed time to be able to restart kevent if it's
2937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // interrupted.
2947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool wait_forever = wait.InMilliseconds() == base::kNoTimeout;
2957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::TimeDelta remaining_delta;
2967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::TimeTicks deadline;
2977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!wait_forever) {
2987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    remaining_delta = wait;
2997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    deadline = base::TimeTicks::Now() + remaining_delta;
3007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  result = -1;
3037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  struct kevent event = {0};
3047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  while (wait_forever || remaining_delta > base::TimeDelta()) {
3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    struct timespec remaining_timespec;
3077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    struct timespec* remaining_timespec_ptr;
3087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (wait_forever) {
3097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      remaining_timespec_ptr = NULL;
3107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } else {
3117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      remaining_timespec = remaining_delta.ToTimeSpec();
3127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      remaining_timespec_ptr = &remaining_timespec;
3137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
3147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
3167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (result == -1 && errno == EINTR) {
3187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (!wait_forever) {
3197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        remaining_delta = deadline - base::TimeTicks::Now();
3207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      }
3217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      result = 0;
3227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } else {
3237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      break;
3247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
3257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (result < 0) {
3287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DPLOG(ERROR) << "kevent (wait " << handle << ")";
3297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
3307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else if (result > 1) {
3317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
3327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                << result;
3337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
3347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else if (result == 0) {
3357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Timed out.
3367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
3377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_EQ(result, 1);
3407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (event.filter != EVFILT_PROC ||
3427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      (event.fflags & NOTE_EXIT) == 0 ||
3437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      event.ident != static_cast<uintptr_t>(handle)) {
3447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DLOG(ERROR) << "kevent (wait " << handle
3457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                << "): unexpected event: filter=" << event.filter
3467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                << ", fflags=" << event.fflags
3477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                << ", ident=" << event.ident;
3487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
3497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
3527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#endif  // OS_MACOSX
3547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
3567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ProcessHandle parent_pid = GetParentProcessId(handle);
3577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ProcessHandle our_pid = Process::Current().handle();
3587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (parent_pid != our_pid) {
3597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#if defined(OS_MACOSX)
3607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // On Mac we can wait on non child processes.
3617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return WaitForSingleNonChildProcess(handle, wait);
3627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#else
3637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Currently on Linux we can't handle non child processes.
3647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    NOTIMPLEMENTED();
3657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#endif  // OS_MACOSX
3667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int status;
369f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!WaitpidWithTimeout(handle, &status, wait))
3707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return WIFEXITED(status);
3727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool CleanupProcesses(const FilePath::StringType& executable_name,
3757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      base::TimeDelta wait,
3767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      int exit_code,
3777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      const ProcessFilter* filter) {
3787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
3797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!exited_cleanly)
3807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    KillProcesses(executable_name, exit_code, filter);
3817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return exited_cleanly;
3827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#if !defined(OS_MACOSX)
3857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace {
3877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Return true if the given child is dead. This will also reap the process.
3897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Doesn't block.
3907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstatic bool IsChildDead(pid_t child) {
3917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
3927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (result == -1) {
3937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DPLOG(ERROR) << "waitpid(" << child << ")";
3947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    NOTREACHED();
3957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else if (result > 0) {
3967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // The child has died.
3977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return true;
3987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return false;
4017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
4027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// A thread class which waits for the given child to exit and reaps it.
4047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// If the child doesn't exit within a couple of seconds, kill it.
4057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass BackgroundReaper : public PlatformThread::Delegate {
4067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch public:
4077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  BackgroundReaper(pid_t child, unsigned timeout)
4087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      : child_(child),
4097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        timeout_(timeout) {
4107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Overridden from PlatformThread::Delegate:
4137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  virtual void ThreadMain() OVERRIDE {
4147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    WaitForChildToDie();
4157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    delete this;
4167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  void WaitForChildToDie() {
4197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Wait forever case.
4207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (timeout_ == 0) {
4217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0));
4227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (r != child_) {
4237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        DPLOG(ERROR) << "While waiting for " << child_
4247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                     << " to terminate, we got the following result: " << r;
4257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      }
4267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return;
4277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
4287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // There's no good way to wait for a specific child to exit in a timed
4307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // fashion. (No kqueue on Linux), so we just loop and sleep.
4317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Wait for 2 * timeout_ 500 milliseconds intervals.
4337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for (unsigned i = 0; i < 2 * timeout_; ++i) {
4347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
4357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (IsChildDead(child_))
4367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        return;
4377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
4387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (kill(child_, SIGKILL) == 0) {
4407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // SIGKILL is uncatchable. Since the signal was delivered, we can
4417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // just wait for the process to die now in a blocking manner.
4427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0)
4437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        DPLOG(WARNING) << "waitpid";
4447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } else {
4457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      DLOG(ERROR) << "While waiting for " << child_ << " to terminate we"
4467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                  << " failed to deliver a SIGKILL signal (" << errno << ").";
4477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
4487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch private:
4517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const pid_t child_;
4527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Number of seconds to wait, if 0 then wait forever and do not attempt to
4537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // kill |child_|.
4547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const unsigned timeout_;
4557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(BackgroundReaper);
4577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch};
4587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace
4607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid EnsureProcessTerminated(ProcessHandle process) {
4627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If the child is already dead, then there's nothing to do.
4637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (IsChildDead(process))
4647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
4657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const unsigned timeout = 2;  // seconds
4677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  BackgroundReaper* reaper = new BackgroundReaper(process, timeout);
4687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  PlatformThread::CreateNonJoinable(0, reaper);
4697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
4707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid EnsureProcessGetsReaped(ProcessHandle process) {
4727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If the child is already dead, then there's nothing to do.
4737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (IsChildDead(process))
4747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
4757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  BackgroundReaper* reaper = new BackgroundReaper(process, 0);
4777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  PlatformThread::CreateNonJoinable(0, reaper);
4787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
4797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#endif  // !defined(OS_MACOSX)
4817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace base
483