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