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 <io.h>
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include <windows.h>
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/bind.h"
117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/bind_helpers.h"
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/logging.h"
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/process/process_iterator.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/win/object_watcher.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace base {
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace {
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Exit codes with special meanings on Windows.
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst DWORD kNormalTerminationExitCode = 0;
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst DWORD kDebuggerInactiveExitCode = 0xC0000354;
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst DWORD kKeyboardInterruptExitCode = 0xC000013A;
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst DWORD kDebuggerTerminatedExitCode = 0x40010004;
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// This exit code is used by the Windows task manager when it kills a
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// process.  It's value is obviously not that unique, and it's
297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// surprising to me that the task manager uses this value, but it
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// seems to be common practice on Windows to test for it as an
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// indication that the task manager has killed something if the
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// process goes away.
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst DWORD kProcessKilledExitCode = 1;
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Maximum amount of time (in milliseconds) to wait for the process to exit.
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstatic const int kWaitInterval = 2000;
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass TimerExpiredTask : public win::ObjectWatcher::Delegate {
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch public:
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  explicit TimerExpiredTask(ProcessHandle process);
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ~TimerExpiredTask();
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  void TimedOut();
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // MessageLoop::Watcher -----------------------------------------------------
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  virtual void OnObjectSignaled(HANDLE object);
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch private:
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  void KillProcess();
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // The process that we are watching.
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ProcessHandle process_;
537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  win::ObjectWatcher watcher_;
557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch};
587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
597dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTimerExpiredTask::TimerExpiredTask(ProcessHandle process) : process_(process) {
607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  watcher_.StartWatching(process_, this);
617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
637dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTimerExpiredTask::~TimerExpiredTask() {
647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  TimedOut();
657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!process_) << "Make sure to close the handle.";
667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid TimerExpiredTask::TimedOut() {
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (process_)
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    KillProcess();
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid TimerExpiredTask::OnObjectSignaled(HANDLE object) {
747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  CloseHandle(process_);
757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  process_ = NULL;
767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid TimerExpiredTask::KillProcess() {
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Stop watching the process handle since we're killing it.
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  watcher_.StopWatching();
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // OK, time to get frisky.  We don't actually care when the process
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // terminates.  We just care that it eventually terminates, and that's what
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TerminateProcess should do for us. Don't check for the result code since
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // it fails quite often. This should be investigated eventually.
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::KillProcess(process_, kProcessKilledExitCode, false);
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Now, just cleanup as if the process exited normally.
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  OnObjectSignaled(process_);
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool KillProcess(ProcessHandle process, int exit_code, bool wait) {
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool result = (TerminateProcess(process, exit_code) != FALSE);
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (result && wait) {
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // The process may not end immediately due to pending I/O
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DPLOG(ERROR) << "Error waiting for process exit";
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else if (!result) {
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DPLOG(ERROR) << "Unable to terminate process";
1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return result;
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Attempts to kill the process identified by the given process
1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// entry structure, giving it the specified exit code.
1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Returns true if this is successful, false otherwise.
1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool KillProcessById(ProcessId process_id, int exit_code, bool wait) {
1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE,
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               FALSE,  // Don't inherit handle
1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               process_id);
1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!process) {
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DPLOG(ERROR) << "Unable to open process " << process_id;
1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool ret = KillProcess(process, exit_code, wait);
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  CloseHandle(process);
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return ret;
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DWORD tmp_exit_code = 0;
1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DPLOG(FATAL) << "GetExitCodeProcess() failed";
1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (exit_code) {
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // This really is a random number.  We haven't received any
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // information about the exit code, presumably because this
1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // process doesn't have permission to get the exit code, or
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // because of some other cause for GetExitCodeProcess to fail
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // (MSDN docs don't give the possible failure error codes for
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // this function, so it could be anything).  But we don't want
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // to leave exit_code uninitialized, since that could cause
1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // random interpretations of the exit code.  So we assume it
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // terminated "normally" in this case.
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      *exit_code = kNormalTerminationExitCode;
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Assume the child has exited normally if we can't get the exit
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // code.
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return TERMINATION_STATUS_NORMAL_TERMINATION;
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (tmp_exit_code == STILL_ACTIVE) {
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DWORD wait_result = WaitForSingleObject(handle, 0);
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (wait_result == WAIT_TIMEOUT) {
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (exit_code)
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        *exit_code = wait_result;
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return TERMINATION_STATUS_STILL_RUNNING;
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (wait_result == WAIT_FAILED) {
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DPLOG(ERROR) << "WaitForSingleObject() failed";
1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } else {
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      DCHECK_EQ(WAIT_OBJECT_0, wait_result);
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      NOTREACHED();
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (exit_code)
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    *exit_code = tmp_exit_code;
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  switch (tmp_exit_code) {
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    case kNormalTerminationExitCode:
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return TERMINATION_STATUS_NORMAL_TERMINATION;
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    case kDebuggerInactiveExitCode:  // STATUS_DEBUGGER_INACTIVE.
1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    case kKeyboardInterruptExitCode:  // Control-C/end session.
1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    case kDebuggerTerminatedExitCode:  // Debugger terminated process.
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    case kProcessKilledExitCode:  // Task manager kill.
1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return TERMINATION_STATUS_PROCESS_WAS_KILLED;
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    default:
1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // All other exit codes indicate crashes.
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return TERMINATION_STATUS_PROCESS_CRASHED;
1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool WaitForExitCode(ProcessHandle handle, int* exit_code) {
1817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool success = WaitForExitCodeWithTimeout(
1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      handle, exit_code, base::TimeDelta::FromMilliseconds(INFINITE));
1837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  CloseProcessHandle(handle);
1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return success;
1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool WaitForExitCodeWithTimeout(ProcessHandle handle,
1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                int* exit_code,
1897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                base::TimeDelta timeout) {
1907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (::WaitForSingleObject(handle, timeout.InMilliseconds()) != WAIT_OBJECT_0)
1917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
1927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DWORD temp_code;  // Don't clobber out-parameters in case of failure.
1937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!::GetExitCodeProcess(handle, &temp_code))
1947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
1957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  *exit_code = temp_code;
1977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
1987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool WaitForProcessesToExit(const FilePath::StringType& executable_name,
2017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            base::TimeDelta wait,
2027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            const ProcessFilter* filter) {
2037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool result = true;
2047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DWORD start_time = GetTickCount();
2057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  NamedProcessIterator iter(executable_name, filter);
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (const ProcessEntry* entry = iter.NextProcessEntry(); entry;
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       entry = iter.NextProcessEntry()) {
2097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DWORD remaining_wait = std::max<int64>(
2107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        0, wait.InMilliseconds() - (GetTickCount() - start_time));
2117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    HANDLE process = OpenProcess(SYNCHRONIZE,
2127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 FALSE,
2137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 entry->th32ProcessID);
2147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DWORD wait_result = WaitForSingleObject(process, remaining_wait);
2157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    CloseHandle(process);
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    result &= (wait_result == WAIT_OBJECT_0);
2177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return result;
2207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
2237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int exit_code;
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return WaitForExitCodeWithTimeout(handle, &exit_code, wait) && exit_code == 0;
2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool CleanupProcesses(const FilePath::StringType& executable_name,
2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      base::TimeDelta wait,
2297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      int exit_code,
2307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      const ProcessFilter* filter) {
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (WaitForProcessesToExit(executable_name, wait, filter))
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return true;
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  KillProcesses(executable_name, exit_code, filter);
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return false;
2357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid EnsureProcessTerminated(ProcessHandle process) {
2387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(process != GetCurrentProcess());
2397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If already signaled, then we are done!
2417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    CloseHandle(process);
2437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  MessageLoop::current()->PostDelayedTask(
2477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      FROM_HERE,
2487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&TimerExpiredTask::TimedOut,
2497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 base::Owned(new TimerExpiredTask(process))),
2507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::TimeDelta::FromMilliseconds(kWaitInterval));
2517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace base
254