Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(165)

Unified Diff: src/trusted/platform/win/nacl_process.c

Issue 10832400: Process abstraction layer for NaCl Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Provide consistent interface across all platforms. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..021a875b45f2b831c95773e126bcab36d607d380
--- /dev/null
+++ b/src/trusted/platform/win/nacl_process.c
@@ -0,0 +1,241 @@
+/*
+ * 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
Mark Seaborn 2012/08/24 00:22:42 Aren't these defined by the Windows headers? If s
+#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
+
+static char *NaClEscapeShellArg(const char *str) {
Mark Seaborn 2012/08/24 00:22:42 I don't know whether this properly implements Wind
+ const char *p;
+ char *esc;
+ char *q;
+
+ esc = calloc(2 * strlen(str) + 1, sizeof *esc);
+ for (p = str, q = esc; 0 != *p; ++p) {
+ if (*p == '"') {
+ *q++ = '\\';
+ } else if (*p == '\\' && *(p + 1) == '"') {
+ *q++ = '\\';
+ }
+ *q++ = *p;
+ }
+
+ return esc;
+}
+
+int NaClProcessLaunch(struct NaClProcess *npp,
+ char *const *argv,
+ char *const *envp,
+ int flags) {
+ char cmd[MAX_PATH];
+ char const *const *p;
+ size_t off;
+ 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) argv, (uintptr_t) envp, flags);
+
+ CHECK(npp != NULL);
+
+ ZeroMemory(&startup_info, sizeof startup_info);
Mark Seaborn 2012/08/24 00:22:42 Using memset() is more usual, since it's a better-
+ startup_info.cb = sizeof startup_info;
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+
+ /* Convert arguments to a single command string */
+ off = 0;
+ for (p = argv; NULL != *p; ++p) {
+ size_t len;
+ char *arg;
+ if (p != argv) {
+ cmd[off++] = ' ';
+ }
+ arg = NaClEscapeShellArg(*p);
+ len = _snprintf(cmd + off, MAX_PATH - off, "\"%s\"", arg);
+ free(arg);
+ if (MAX_PATH - off < len) {
+ break;
+ }
+ off += len;
+ }
+ cmd[off] = '\0';
+
+ 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,
+ envp,
+ /* 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)) {
Mark Seaborn 2012/08/24 00:22:42 Why a hard-coded timeout? What is the use case?
+ 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;
+}

Powered by Google App Engine
This is Rietveld 408576698