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