| Index: src/trusted/platform/win/nacl_process.c
|
| diff --git a/src/trusted/platform/win/nacl_process.c b/src/trusted/platform/win/nacl_process.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..11893570be282a1fcd0c55e5744eec584025ec0f
|
| --- /dev/null
|
| +++ b/src/trusted/platform/win/nacl_process.c
|
| @@ -0,0 +1,202 @@
|
| +/*
|
| + * Copyright (c) 2012 The Native Client 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 "native_client/src/trusted/platform/nacl_process.h"
|
| +
|
| +#include <fcntl.h>
|
| +#include <io.h>
|
| +#include <windows.h>
|
| +#include <userenv.h>
|
| +#include <psapi.h>
|
| +
|
| +#include "native_client/src/include/portability.h"
|
| +#include "native_client/src/include/portability_string.h"
|
| +
|
| +#include "native_client/src/shared/platform/nacl_check.h"
|
| +#include "native_client/src/shared/platform/nacl_log.h"
|
| +#include "native_client/src/shared/platform/nacl_sync.h"
|
| +#include "native_client/src/shared/platform/nacl_sync_checked.h"
|
| +
|
| +#ifndef STATUS_SUCCESS
|
| +#define STATUS_SUCCESS ((NTSTATUS) 0)
|
| +#endif
|
| +#ifndef STATUS_WAIT_1
|
| +#define STATUS_WAIT_1 ((NTSTATUS) 0x00000001)
|
| +#endif
|
| +#ifndef STATUS_DEBUGGER_INACTIVE
|
| +#define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354)
|
| +#endif
|
| +#ifndef STATUS_CONTROL_C_EXIT
|
| +#define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013A)
|
| +#endif
|
| +#ifndef DBG_TERMINATE_PROCESS
|
| +#define DBG_TERMINATE_PROCESS ((NTSTATUS) 0x40010004)
|
| +#endif
|
| +
|
| +int NaClProcessLaunch(struct NaClProcess *npp,
|
| + char *cmd,
|
| + char *env,
|
| + int flags) {
|
| + STARTUPINFO startup_info;
|
| + PROCESS_INFORMATION process_info;
|
| + DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT;
|
| + BOOL inherit;
|
| +
|
| + NaClLog(2,
|
| + ("NaClProcessLaunch(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR
|
| + ", 0x%08"NACL_PRIxPTR", 0x%x)\n"),
|
| + (uintptr_t) npp, (uintptr_t) cmd, (uintptr_t) env, flags);
|
| +
|
| + CHECK(npp != NULL);
|
| +
|
| + ZeroMemory(&startup_info, sizeof startup_info);
|
| + startup_info.cb = sizeof startup_info;
|
| + startup_info.dwFlags = STARTF_USESTDHANDLES;
|
| +
|
| + if ((flags & NACL_PROCESS_LAUNCH_CLOSE_FDS) != 0) {
|
| + inherit = FALSE;
|
| + } else {
|
| + inherit = TRUE;
|
| + }
|
| +
|
| + if (0 != (flags & NACL_PROCESS_LAUNCH_NEW_GROUP)) {
|
| + creation_flags |= CREATE_NEW_PROCESS_GROUP;
|
| + }
|
| +
|
| + if (!CreateProcess(/* lpApplicationName= */ NULL,
|
| + cmd,
|
| + /* lpProcessAttributes= */ NULL,
|
| + /* lpThreadAttributes= */ NULL,
|
| + inherit,
|
| + creation_flags,
|
| + env,
|
| + /* lpCurrentDirectory= */NULL,
|
| + &startup_info,
|
| + &process_info)) {
|
| + NaClLog(LOG_ERROR,
|
| + "NaClProcessSpawn: CreateProcess failed, error %d\n",
|
| + GetLastError());
|
| + return 0;
|
| + }
|
| +
|
| + /* TODO(phosek): might we ever need this handle? */
|
| + DCHECK(CloseHandle(process_info.hThread));
|
| +
|
| + if (npp != NULL) {
|
| + npp->handle = process_info.hProcess;
|
| + }
|
| +
|
| + return 1;
|
| +}
|
| +
|
| +int NaClProcessKill(struct NaClProcess *npp, int exit_code, int wait) {
|
| + BOOL retval;
|
| +
|
| + NaClLog(2,
|
| + "NaClProcessKill(0x%08"NACL_PRIxPTR", %d, %d)\n",
|
| + (uintptr_t) npp, exit_code, wait);
|
| +
|
| + CHECK(npp != NULL);
|
| +
|
| + retval = TerminateProcess(npp->handle, exit_code);
|
| + if (FALSE == retval) {
|
| + NaClLog(LOG_ERROR,
|
| + "NaClProcessKill: unable to terminate process, error %d\n",
|
| + GetLastError());
|
| + goto done;
|
| + }
|
| +
|
| + if (wait != 0) {
|
| + /* The process may not end immediately due to pending I/O */
|
| + if (WAIT_OBJECT_0 != WaitForSingleObject(npp->handle, 60 * 1000)) {
|
| + NaClLog(LOG_ERROR,
|
| + "NaClProcessKill: waiting for process failed, error %d\n",
|
| + GetLastError());
|
| + }
|
| + }
|
| +
|
| + done:
|
| + return retval != FALSE;
|
| +}
|
| +
|
| +int NaClProcessGetStatus(
|
| + struct NaClProcess *npp,
|
| + int *status) {
|
| + DWORD exit_code = 0;
|
| +
|
| + NaClLog(2,
|
| + ("NaClProcessGetStatus(0x%08"NACL_PRIxPTR
|
| + ", 0x%08"NACL_PRIxPTR")\n"),
|
| + (uintptr_t) npp, (uintptr_t) status);
|
| +
|
| + CHECK(npp != NULL);
|
| +
|
| + NaClLog(4,
|
| + "NaClProcessGetStatus: checking status of process %d\n",
|
| + (int) npp->handle);
|
| +
|
| + if (!GetExitCodeProcess(npp->handle, &exit_code)) {
|
| + NaClLog(LOG_ERROR,
|
| + ("NaClProcessGetStatus: GetExitCodeProcess"
|
| + "returned error %d\n"),
|
| + GetLastError());
|
| + return 0;
|
| + }
|
| +
|
| + if (STILL_ACTIVE == exit_code) {
|
| + DWORD wait_result = WaitForSingleObject(npp->handle, 0);
|
| + if (WAIT_TIMEOUT == wait_result) {
|
| + *status = NACL_PROCESS_STATUS_STILL_RUNNING;
|
| + return 1;
|
| + }
|
| +
|
| + CHECK(WAIT_OBJECT_0 == wait_result);
|
| + /* The process used 0x103 (STILL_ACTIVE) as exit code. */
|
| + *status = NACL_PROCESS_STATUS_ABNORMAL_EXIT;
|
| + return 1;
|
| + }
|
| +
|
| + switch (exit_code) {
|
| + case STATUS_SUCCESS: /* Normal termination */
|
| + *status = NACL_PROCESS_STATUS_NORMAL_EXIT;
|
| + break;
|
| + case STATUS_DEBUGGER_INACTIVE: /* Debugger inactive */
|
| + case STATUS_CONTROL_C_EXIT: /* Keyboard interrupt */
|
| + case DBG_TERMINATE_PROCESS: /* Debugger terminated */
|
| + case STATUS_WAIT_1: /* Task manager killed */
|
| + *status = NACL_PROCESS_STATUS_KILLED;
|
| + break;
|
| + default:
|
| + /* All other exit codes indicate crashes */
|
| + *status = NACL_PROCESS_STATUS_CRASHED;
|
| + break;
|
| + }
|
| +
|
| + return 1;
|
| +}
|
| +
|
| +int NaClProcessWaitForExitCode(struct NaClProcess *npp,
|
| + int *exit_code) {
|
| + DWORD tmp_exit_code;
|
| +
|
| + NaClLog(2,
|
| + ("NaClProcessWaitForExitCode(0x%08"NACL_PRIxPTR
|
| + ", 0x%08"NACL_PRIxPTR")\n"),
|
| + (uintptr_t) npp, (uintptr_t) exit_code);
|
| +
|
| + CHECK(npp != NULL);
|
| +
|
| + if (WAIT_OBJECT_0 != WaitForSingleObject(npp->handle, INFINITE)) {
|
| + return 0;
|
| + }
|
| +
|
| + if (!GetExitCodeProcess(npp->handle, &tmp_exit_code)) {
|
| + return 0;
|
| + }
|
| +
|
| + *exit_code = tmp_exit_code;
|
| + return 1;
|
| +}
|
|
|