OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. |
| 5 */ |
| 6 |
| 7 #include "native_client/src/trusted/platform/nacl_process.h" |
| 8 |
| 9 #include <fcntl.h> |
| 10 #include <io.h> |
| 11 #include <windows.h> |
| 12 #include <userenv.h> |
| 13 #include <psapi.h> |
| 14 |
| 15 #include "native_client/src/include/portability.h" |
| 16 #include "native_client/src/include/portability_string.h" |
| 17 |
| 18 #include "native_client/src/shared/platform/nacl_check.h" |
| 19 #include "native_client/src/shared/platform/nacl_log.h" |
| 20 #include "native_client/src/shared/platform/nacl_sync.h" |
| 21 #include "native_client/src/shared/platform/nacl_sync_checked.h" |
| 22 |
| 23 #ifndef STATUS_SUCCESS |
| 24 #define STATUS_SUCCESS ((NTSTATUS) 0) |
| 25 #endif |
| 26 #ifndef STATUS_WAIT_1 |
| 27 #define STATUS_WAIT_1 ((NTSTATUS) 0x00000001) |
| 28 #endif |
| 29 #ifndef STATUS_DEBUGGER_INACTIVE |
| 30 #define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354) |
| 31 #endif |
| 32 #ifndef STATUS_CONTROL_C_EXIT |
| 33 #define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013A) |
| 34 #endif |
| 35 #ifndef DBG_TERMINATE_PROCESS |
| 36 #define DBG_TERMINATE_PROCESS ((NTSTATUS) 0x40010004) |
| 37 #endif |
| 38 |
| 39 int NaClProcessLaunch(struct NaClProcess *npp, |
| 40 char *cmd, |
| 41 char *env, |
| 42 int flags) { |
| 43 STARTUPINFO startup_info; |
| 44 PROCESS_INFORMATION process_info; |
| 45 DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT; |
| 46 BOOL inherit; |
| 47 |
| 48 NaClLog(2, |
| 49 ("NaClProcessLaunch(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR |
| 50 ", 0x%08"NACL_PRIxPTR", 0x%x)\n"), |
| 51 (uintptr_t) npp, (uintptr_t) cmd, (uintptr_t) env, flags); |
| 52 |
| 53 CHECK(npp != NULL); |
| 54 |
| 55 ZeroMemory(&startup_info, sizeof startup_info); |
| 56 startup_info.cb = sizeof startup_info; |
| 57 startup_info.dwFlags = STARTF_USESTDHANDLES; |
| 58 |
| 59 if ((flags & NACL_PROCESS_LAUNCH_CLOSE_FDS) != 0) { |
| 60 inherit = FALSE; |
| 61 } else { |
| 62 inherit = TRUE; |
| 63 } |
| 64 |
| 65 if (0 != (flags & NACL_PROCESS_LAUNCH_NEW_GROUP)) { |
| 66 creation_flags |= CREATE_NEW_PROCESS_GROUP; |
| 67 } |
| 68 |
| 69 if (!CreateProcess(/* lpApplicationName= */ NULL, |
| 70 cmd, |
| 71 /* lpProcessAttributes= */ NULL, |
| 72 /* lpThreadAttributes= */ NULL, |
| 73 inherit, |
| 74 creation_flags, |
| 75 env, |
| 76 /* lpCurrentDirectory= */NULL, |
| 77 &startup_info, |
| 78 &process_info)) { |
| 79 NaClLog(LOG_ERROR, |
| 80 "NaClProcessSpawn: CreateProcess failed, error %d\n", |
| 81 GetLastError()); |
| 82 return 0; |
| 83 } |
| 84 |
| 85 /* TODO(phosek): might we ever need this handle? */ |
| 86 DCHECK(CloseHandle(process_info.hThread)); |
| 87 |
| 88 if (npp != NULL) { |
| 89 npp->handle = process_info.hProcess; |
| 90 } |
| 91 |
| 92 return 1; |
| 93 } |
| 94 |
| 95 int NaClProcessKill(struct NaClProcess *npp, int exit_code, int wait) { |
| 96 BOOL retval; |
| 97 |
| 98 NaClLog(2, |
| 99 "NaClProcessKill(0x%08"NACL_PRIxPTR", %d, %d)\n", |
| 100 (uintptr_t) npp, exit_code, wait); |
| 101 |
| 102 CHECK(npp != NULL); |
| 103 |
| 104 retval = TerminateProcess(npp->handle, exit_code); |
| 105 if (FALSE == retval) { |
| 106 NaClLog(LOG_ERROR, |
| 107 "NaClProcessKill: unable to terminate process, error %d\n", |
| 108 GetLastError()); |
| 109 goto done; |
| 110 } |
| 111 |
| 112 if (wait != 0) { |
| 113 /* The process may not end immediately due to pending I/O */ |
| 114 if (WAIT_OBJECT_0 != WaitForSingleObject(npp->handle, 60 * 1000)) { |
| 115 NaClLog(LOG_ERROR, |
| 116 "NaClProcessKill: waiting for process failed, error %d\n", |
| 117 GetLastError()); |
| 118 } |
| 119 } |
| 120 |
| 121 done: |
| 122 return retval != FALSE; |
| 123 } |
| 124 |
| 125 int NaClProcessGetStatus( |
| 126 struct NaClProcess *npp, |
| 127 int *status) { |
| 128 DWORD exit_code = 0; |
| 129 |
| 130 NaClLog(2, |
| 131 ("NaClProcessGetStatus(0x%08"NACL_PRIxPTR |
| 132 ", 0x%08"NACL_PRIxPTR")\n"), |
| 133 (uintptr_t) npp, (uintptr_t) status); |
| 134 |
| 135 CHECK(npp != NULL); |
| 136 |
| 137 NaClLog(4, |
| 138 "NaClProcessGetStatus: checking status of process %d\n", |
| 139 (int) npp->handle); |
| 140 |
| 141 if (!GetExitCodeProcess(npp->handle, &exit_code)) { |
| 142 NaClLog(LOG_ERROR, |
| 143 ("NaClProcessGetStatus: GetExitCodeProcess" |
| 144 "returned error %d\n"), |
| 145 GetLastError()); |
| 146 return 0; |
| 147 } |
| 148 |
| 149 if (STILL_ACTIVE == exit_code) { |
| 150 DWORD wait_result = WaitForSingleObject(npp->handle, 0); |
| 151 if (WAIT_TIMEOUT == wait_result) { |
| 152 *status = NACL_PROCESS_STATUS_STILL_RUNNING; |
| 153 return 1; |
| 154 } |
| 155 |
| 156 CHECK(WAIT_OBJECT_0 == wait_result); |
| 157 /* The process used 0x103 (STILL_ACTIVE) as exit code. */ |
| 158 *status = NACL_PROCESS_STATUS_ABNORMAL_EXIT; |
| 159 return 1; |
| 160 } |
| 161 |
| 162 switch (exit_code) { |
| 163 case STATUS_SUCCESS: /* Normal termination */ |
| 164 *status = NACL_PROCESS_STATUS_NORMAL_EXIT; |
| 165 break; |
| 166 case STATUS_DEBUGGER_INACTIVE: /* Debugger inactive */ |
| 167 case STATUS_CONTROL_C_EXIT: /* Keyboard interrupt */ |
| 168 case DBG_TERMINATE_PROCESS: /* Debugger terminated */ |
| 169 case STATUS_WAIT_1: /* Task manager killed */ |
| 170 *status = NACL_PROCESS_STATUS_KILLED; |
| 171 break; |
| 172 default: |
| 173 /* All other exit codes indicate crashes */ |
| 174 *status = NACL_PROCESS_STATUS_CRASHED; |
| 175 break; |
| 176 } |
| 177 |
| 178 return 1; |
| 179 } |
| 180 |
| 181 int NaClProcessWaitForExitCode(struct NaClProcess *npp, |
| 182 int *exit_code) { |
| 183 DWORD tmp_exit_code; |
| 184 |
| 185 NaClLog(2, |
| 186 ("NaClProcessWaitForExitCode(0x%08"NACL_PRIxPTR |
| 187 ", 0x%08"NACL_PRIxPTR")\n"), |
| 188 (uintptr_t) npp, (uintptr_t) exit_code); |
| 189 |
| 190 CHECK(npp != NULL); |
| 191 |
| 192 if (WAIT_OBJECT_0 != WaitForSingleObject(npp->handle, INFINITE)) { |
| 193 return 0; |
| 194 } |
| 195 |
| 196 if (!GetExitCodeProcess(npp->handle, &tmp_exit_code)) { |
| 197 return 0; |
| 198 } |
| 199 |
| 200 *exit_code = tmp_exit_code; |
| 201 return 1; |
| 202 } |
OLD | NEW |