[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 1 | // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/process/kill.h" |
| 6 | |
Wez | c18a57c | 2018-04-02 20:20:14 | [diff] [blame^] | 7 | #include <algorithm> |
| 8 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 9 | #include <windows.h> |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 10 | #include <io.h> |
| 11 | #include <stdint.h> |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 12 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 13 | #include "base/logging.h" |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 14 | #include "base/macros.h" |
wfh | fa40c272 | 2016-07-26 01:12:28 | [diff] [blame] | 15 | #include "base/process/memory.h" |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 16 | #include "base/process/process_iterator.h" |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 17 | |
| 18 | namespace base { |
| 19 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 20 | TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { |
Wez | 05c2c68 | 2017-08-17 16:20:11 | [diff] [blame] | 21 | DCHECK(exit_code); |
| 22 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 23 | DWORD tmp_exit_code = 0; |
| 24 | |
| 25 | if (!::GetExitCodeProcess(handle, &tmp_exit_code)) { |
[email protected] | ad8cfa9 | 2014-05-21 20:06:23 | [diff] [blame] | 26 | DPLOG(FATAL) << "GetExitCodeProcess() failed"; |
Wez | 05c2c68 | 2017-08-17 16:20:11 | [diff] [blame] | 27 | |
| 28 | // This really is a random number. We haven't received any |
| 29 | // information about the exit code, presumably because this |
| 30 | // process doesn't have permission to get the exit code, or |
| 31 | // because of some other cause for GetExitCodeProcess to fail |
| 32 | // (MSDN docs don't give the possible failure error codes for |
| 33 | // this function, so it could be anything). But we don't want |
| 34 | // to leave exit_code uninitialized, since that could cause |
| 35 | // random interpretations of the exit code. So we assume it |
| 36 | // terminated "normally" in this case. |
Bruce Dawson | ec015851 | 2017-11-16 09:10:40 | [diff] [blame] | 37 | *exit_code = win::kNormalTerminationExitCode; |
Wez | 05c2c68 | 2017-08-17 16:20:11 | [diff] [blame] | 38 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 39 | // Assume the child has exited normally if we can't get the exit |
| 40 | // code. |
| 41 | return TERMINATION_STATUS_NORMAL_TERMINATION; |
| 42 | } |
| 43 | if (tmp_exit_code == STILL_ACTIVE) { |
| 44 | DWORD wait_result = WaitForSingleObject(handle, 0); |
| 45 | if (wait_result == WAIT_TIMEOUT) { |
Wez | 05c2c68 | 2017-08-17 16:20:11 | [diff] [blame] | 46 | *exit_code = wait_result; |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 47 | return TERMINATION_STATUS_STILL_RUNNING; |
| 48 | } |
| 49 | |
| 50 | if (wait_result == WAIT_FAILED) { |
[email protected] | ad8cfa9 | 2014-05-21 20:06:23 | [diff] [blame] | 51 | DPLOG(ERROR) << "WaitForSingleObject() failed"; |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 52 | } else { |
| 53 | DCHECK_EQ(WAIT_OBJECT_0, wait_result); |
| 54 | |
| 55 | // Strange, the process used 0x103 (STILL_ACTIVE) as exit code. |
| 56 | NOTREACHED(); |
| 57 | } |
| 58 | |
| 59 | return TERMINATION_STATUS_ABNORMAL_TERMINATION; |
| 60 | } |
| 61 | |
Wez | 05c2c68 | 2017-08-17 16:20:11 | [diff] [blame] | 62 | *exit_code = tmp_exit_code; |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 63 | |
| 64 | switch (tmp_exit_code) { |
Bruce Dawson | ec015851 | 2017-11-16 09:10:40 | [diff] [blame] | 65 | case win::kNormalTerminationExitCode: |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 66 | return TERMINATION_STATUS_NORMAL_TERMINATION; |
Bruce Dawson | ec015851 | 2017-11-16 09:10:40 | [diff] [blame] | 67 | case win::kDebuggerInactiveExitCode: // STATUS_DEBUGGER_INACTIVE. |
| 68 | case win::kKeyboardInterruptExitCode: // Control-C/end session. |
| 69 | case win::kDebuggerTerminatedExitCode: // Debugger terminated process. |
| 70 | case win::kProcessKilledExitCode: // Task manager kill. |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 71 | return TERMINATION_STATUS_PROCESS_WAS_KILLED; |
Bruce Dawson | ec015851 | 2017-11-16 09:10:40 | [diff] [blame] | 72 | case win::kSandboxFatalMemoryExceeded: // Terminated process due to |
| 73 | // exceeding the sandbox job |
| 74 | // object memory limits. |
| 75 | case win::kOomExceptionCode: // Ran out of memory. |
wfh | fa40c272 | 2016-07-26 01:12:28 | [diff] [blame] | 76 | return TERMINATION_STATUS_OOM; |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 77 | default: |
| 78 | // All other exit codes indicate crashes. |
| 79 | return TERMINATION_STATUS_PROCESS_CRASHED; |
| 80 | } |
| 81 | } |
| 82 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 83 | bool WaitForProcessesToExit(const FilePath::StringType& executable_name, |
rvargas | 2f70a15 | 2015-02-24 00:28:11 | [diff] [blame] | 84 | TimeDelta wait, |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 85 | const ProcessFilter* filter) { |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 86 | bool result = true; |
| 87 | DWORD start_time = GetTickCount(); |
| 88 | |
| 89 | NamedProcessIterator iter(executable_name, filter); |
[email protected] | ed8e57da | 2014-07-03 07:03:39 | [diff] [blame] | 90 | for (const ProcessEntry* entry = iter.NextProcessEntry(); entry; |
| 91 | entry = iter.NextProcessEntry()) { |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 92 | DWORD remaining_wait = static_cast<DWORD>( |
| 93 | std::max(static_cast<int64_t>(0), |
| 94 | wait.InMilliseconds() - (GetTickCount() - start_time))); |
brucedawson | d350943 | 2015-09-18 18:28:13 | [diff] [blame] | 95 | HANDLE process = OpenProcess(SYNCHRONIZE, |
| 96 | FALSE, |
| 97 | entry->th32ProcessID); |
| 98 | DWORD wait_result = WaitForSingleObject(process, remaining_wait); |
| 99 | CloseHandle(process); |
[email protected] | ed8e57da | 2014-07-03 07:03:39 | [diff] [blame] | 100 | result &= (wait_result == WAIT_OBJECT_0); |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | return result; |
| 104 | } |
| 105 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 106 | bool CleanupProcesses(const FilePath::StringType& executable_name, |
rvargas | 2f70a15 | 2015-02-24 00:28:11 | [diff] [blame] | 107 | TimeDelta wait, |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 108 | int exit_code, |
| 109 | const ProcessFilter* filter) { |
[email protected] | ed8e57da | 2014-07-03 07:03:39 | [diff] [blame] | 110 | if (WaitForProcessesToExit(executable_name, wait, filter)) |
| 111 | return true; |
| 112 | KillProcesses(executable_name, exit_code, filter); |
| 113 | return false; |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 114 | } |
| 115 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 116 | } // namespace base |