| // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/process/kill.h" | 
 |  | 
 | #include <algorithm> | 
 |  | 
 | #include <windows.h> | 
 | #include <io.h> | 
 | #include <stdint.h> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "base/macros.h" | 
 | #include "base/process/memory.h" | 
 | #include "base/process/process_iterator.h" | 
 |  | 
 | namespace base { | 
 |  | 
 | TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { | 
 |   DCHECK(exit_code); | 
 |  | 
 |   DWORD tmp_exit_code = 0; | 
 |  | 
 |   if (!::GetExitCodeProcess(handle, &tmp_exit_code)) { | 
 |     DPLOG(FATAL) << "GetExitCodeProcess() failed"; | 
 |  | 
 |     // This really is a random number.  We haven't received any | 
 |     // information about the exit code, presumably because this | 
 |     // process doesn't have permission to get the exit code, or | 
 |     // because of some other cause for GetExitCodeProcess to fail | 
 |     // (MSDN docs don't give the possible failure error codes for | 
 |     // this function, so it could be anything).  But we don't want | 
 |     // to leave exit_code uninitialized, since that could cause | 
 |     // random interpretations of the exit code.  So we assume it | 
 |     // terminated "normally" in this case. | 
 |     *exit_code = win::kNormalTerminationExitCode; | 
 |  | 
 |     // Assume the child has exited normally if we can't get the exit | 
 |     // code. | 
 |     return TERMINATION_STATUS_NORMAL_TERMINATION; | 
 |   } | 
 |   if (tmp_exit_code == STILL_ACTIVE) { | 
 |     DWORD wait_result = WaitForSingleObject(handle, 0); | 
 |     if (wait_result == WAIT_TIMEOUT) { | 
 |       *exit_code = wait_result; | 
 |       return TERMINATION_STATUS_STILL_RUNNING; | 
 |     } | 
 |  | 
 |     if (wait_result == WAIT_FAILED) { | 
 |       DPLOG(ERROR) << "WaitForSingleObject() failed"; | 
 |     } else { | 
 |       DCHECK_EQ(WAIT_OBJECT_0, wait_result); | 
 |  | 
 |       // Strange, the process used 0x103 (STILL_ACTIVE) as exit code. | 
 |       NOTREACHED(); | 
 |     } | 
 |  | 
 |     return TERMINATION_STATUS_ABNORMAL_TERMINATION; | 
 |   } | 
 |  | 
 |   *exit_code = tmp_exit_code; | 
 |  | 
 |   switch (tmp_exit_code) { | 
 |     case win::kNormalTerminationExitCode: | 
 |       return TERMINATION_STATUS_NORMAL_TERMINATION; | 
 |     case win::kDebuggerInactiveExitCode:    // STATUS_DEBUGGER_INACTIVE. | 
 |     case win::kKeyboardInterruptExitCode:   // Control-C/end session. | 
 |     case win::kDebuggerTerminatedExitCode:  // Debugger terminated process. | 
 |     case win::kProcessKilledExitCode:       // Task manager kill. | 
 |       return TERMINATION_STATUS_PROCESS_WAS_KILLED; | 
 |     case win::kSandboxFatalMemoryExceeded:  // Terminated process due to | 
 |                                             // exceeding the sandbox job | 
 |                                             // object memory limits. | 
 |     case win::kOomExceptionCode:            // Ran out of memory. | 
 |       return TERMINATION_STATUS_OOM; | 
 |     default: | 
 |       // All other exit codes indicate crashes. | 
 |       return TERMINATION_STATUS_PROCESS_CRASHED; | 
 |   } | 
 | } | 
 |  | 
 | bool WaitForProcessesToExit(const FilePath::StringType& executable_name, | 
 |                             TimeDelta wait, | 
 |                             const ProcessFilter* filter) { | 
 |   bool result = true; | 
 |   DWORD start_time = GetTickCount(); | 
 |  | 
 |   NamedProcessIterator iter(executable_name, filter); | 
 |   for (const ProcessEntry* entry = iter.NextProcessEntry(); entry; | 
 |        entry = iter.NextProcessEntry()) { | 
 |     DWORD remaining_wait = static_cast<DWORD>( | 
 |         std::max(static_cast<int64_t>(0), | 
 |                  wait.InMilliseconds() - (GetTickCount() - start_time))); | 
 |     HANDLE process = OpenProcess(SYNCHRONIZE, | 
 |                                  FALSE, | 
 |                                  entry->th32ProcessID); | 
 |     DWORD wait_result = WaitForSingleObject(process, remaining_wait); | 
 |     CloseHandle(process); | 
 |     result &= (wait_result == WAIT_OBJECT_0); | 
 |   } | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | bool CleanupProcesses(const FilePath::StringType& executable_name, | 
 |                       TimeDelta wait, | 
 |                       int exit_code, | 
 |                       const ProcessFilter* filter) { | 
 |   if (WaitForProcessesToExit(executable_name, wait, filter)) | 
 |     return true; | 
 |   KillProcesses(executable_name, exit_code, filter); | 
 |   return false; | 
 | } | 
 |  | 
 | }  // namespace base |