From eeb8c72561180995bc70a5db495b6f941342c8c5 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Thu, 2 Dec 2021 19:29:28 -0600 Subject: [PATCH] made running subprocesses better on windows --- core/runtime/build_opts.onyx | 5 +++ include/small_windows.h | 6 ++- scripts/run_tests.onyx | 10 ++++- src/builtins.c | 10 +++++ src/wasm_runtime.c | 84 +++++++++++++++++++++++++++++++----- 5 files changed, 102 insertions(+), 13 deletions(-) diff --git a/core/runtime/build_opts.onyx b/core/runtime/build_opts.onyx index 483257a5..af42c699 100644 --- a/core/runtime/build_opts.onyx +++ b/core/runtime/build_opts.onyx @@ -20,3 +20,8 @@ Runtime_Onyx :: 1 Runtime_Wasi :: 2 Runtime_Js :: 3 Runtime_Custom :: 4 + + + +OS_Linux :: 1 +OS_Windows :: 2 \ No newline at end of file diff --git a/include/small_windows.h b/include/small_windows.h index 4f3114dd..0950b981 100644 --- a/include/small_windows.h +++ b/include/small_windows.h @@ -285,7 +285,7 @@ typedef struct _PROCESS_INFORMATION { #define INFINITE 0xffffffffl #define INVALID_HANDLE_VALUE ((void *)(intptr_t)(-1)) - +#define STARTF_USESTDHANDLES 0x00000100 typedef DWORD WINAPI THREAD_START_ROUTINE(void *parameter); @@ -307,6 +307,10 @@ GB_DLL_IMPORT BOOL WINAPI CreateProcessA (char const * lpApplicationName, char const * lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); GB_DLL_IMPORT BOOL WINAPI GetExitCodeProcess (HANDLE hProcess, DWORD *lpExitCode); +GB_DLL_IMPORT BOOL WINAPI CreatePipe (HANDLE *hReadPipe, HANDLE *hWritePipe, SECURITY_ATTRIBUTES* lpPipeAttributes, + DWORD nSize); +GB_DLL_IMPORT BOOL WINAPI TerminateProcess (HANDLE hProcess, UINT uExitCode); +GB_DLL_IMPORT BOOL WINAPI SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); GB_DLL_IMPORT BOOL WINAPI GetLogicalProcessorInformation(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer, DWORD *return_length); GB_DLL_IMPORT DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE thread, DWORD_PTR check_mask); diff --git a/scripts/run_tests.onyx b/scripts/run_tests.onyx index 077c3dc5..4cda81e9 100644 --- a/scripts/run_tests.onyx +++ b/scripts/run_tests.onyx @@ -2,6 +2,7 @@ use package core #local wasi :: package wasi +#local runtime :: package runtime Directory_Entry :: struct { dirent : wasi.DirEnt; @@ -68,7 +69,6 @@ list_directory :: (path: str) -> Iterator(Directory_Entry) { return .{ c, next, close }; } -@Temporary find_onyx_files :: (root: str, cases: ^[..] str) { for list_directory(root) { path_buffer: [512] u8; @@ -88,12 +88,18 @@ find_onyx_files :: (root: str, cases: ^[..] str) { main :: (args) => { test_folder := "./tests"; + onyx_cmd: str; + switch runtime.OS { + case runtime.OS_Linux do onyx_cmd = "./bin/onyx"; + case runtime.OS_Windows do onyx_cmd = "onyx.exe"; + } + cases := array.make(str); find_onyx_files(test_folder, ^cases); for cases { printf("Running test {}...\n", it); - proc := io.process_spawn("./bin/onyx", .["run", it]); + proc := io.process_spawn(onyx_cmd, .["run", it]); defer io.process_destroy(^proc); proc_reader := io.reader_make(^proc); diff --git a/src/builtins.c b/src/builtins.c index 382029e2..515c133f 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -477,4 +477,14 @@ void introduce_build_options(bh_allocator a) { AstNumLit* wait_notify_available = make_int_literal(a, context.options->use_multi_threading && context.options->runtime == Runtime_Js); wait_notify_available->type_node = (AstType *) &basic_type_bool; symbol_builtin_introduce(p->scope, "Wait_Notify_Available", (AstNode *) wait_notify_available); + + i32 os; + #ifdef _BH_LINUX + os = 1; + #endif + #ifdef _BH_WINDOWS + os = 2; + #endif + AstNumLit* os_type = make_int_literal(a, os); + symbol_builtin_introduce(p->scope, "OS", (AstNode *) os_type); } diff --git a/src/wasm_runtime.c b/src/wasm_runtime.c index 3b327837..24a51965 100644 --- a/src/wasm_runtime.c +++ b/src/wasm_runtime.c @@ -191,6 +191,15 @@ typedef struct OnyxProcess { pid_t pid; #endif + +#ifdef _BH_WINDOWS + HANDLE proc_to_host_read; + HANDLE proc_to_host_write; + HANDLE host_to_proc_read; + HANDLE host_to_proc_write; + + PROCESS_INFORMATION proc_info; +#endif } OnyxProcess; WASM_INTEROP(onyx_process_spawn_impl) { @@ -225,8 +234,10 @@ WASM_INTEROP(onyx_process_spawn_impl) { process_args[0] = process_path; process_args[args_len + 1] = NULL; - pipe(process->proc_to_host); - pipe(process->host_to_proc); + if (pipe(process->proc_to_host) || pipe(process->host_to_proc)) { + wasm_val_init_ptr(&results->data[0], NULL); // Failed to run + return NULL; + } pid_t pid; switch (pid = fork()) { @@ -287,17 +298,36 @@ WASM_INTEROP(onyx_process_spawn_impl) { memset(&startup, 0, sizeof startup); startup.cb = sizeof(startup); - PROCESS_INFORMATION proc_info; - BOOL success = CreateProcessA(process_path, cmdLine, NULL, NULL, 1, 0, NULL, NULL, &startup, &proc_info); + SECURITY_ATTRIBUTES saAttr; + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.lpSecurityDescriptor = NULL; + saAttr.bInheritHandle = 1; + + BOOL success = 1; + success = success && CreatePipe(&process->host_to_proc_read, &process->host_to_proc_write, &saAttr, 4096); + success = success && CreatePipe(&process->proc_to_host_read, &process->proc_to_host_write, &saAttr, 4096); if (!success) { - results->data[0] = WASM_I32_VAL(1); // Failed to run + wasm_val_init_ptr(&results->data[0], NULL); // Failed to run @LEAK return NULL; } - DWORD result = WaitForSingleObject(proc_info.hProcess, INFINITE); - DWORD exitCode; - GetExitCodeProcess(proc_info.hProcess, &exitCode); - results->data[0] = WASM_I32_VAL(exitCode != 0 ? 2 : 0); + SetHandleInformation(process->proc_to_host_read, 1 /* HANDLE_FLAG_INHERIT */, 0); + SetHandleInformation(process->host_to_proc_write, 1 /* HANDLE_FLAG_INHERIT */, 0); + + startup.hStdInput = process->host_to_proc_read; + startup.hStdOutput = process->proc_to_host_write; + startup.hStdError = process->proc_to_host_write; + startup.dwFlags |= STARTF_USESTDHANDLES; + + success = CreateProcessA(process_path, cmdLine, NULL, NULL, 1, 0, NULL, NULL, &startup, &process->proc_info); + if (!success) { + wasm_val_init_ptr(&results->data[0], NULL); // Failed to run @LEAK + return NULL; + } + + CloseHandle(process->proc_to_host_write); + CloseHandle(process->host_to_proc_read); + wasm_val_init_ptr(&results->data[0], process); #endif return NULL; @@ -320,6 +350,11 @@ WASM_INTEROP(onyx_process_read_impl) { bytes_read = bh_max(bytes_read, 0); // Silently consume errors #endif + #ifdef _BH_WINDOWS + BOOL success = ReadFile(process->proc_to_host_read, buffer, output_len, &bytes_read, NULL); + if (!success) bytes_read = 0; + #endif + results->data[0] = WASM_I32_VAL(bytes_read); return NULL; } @@ -341,6 +376,11 @@ WASM_INTEROP(onyx_process_write_impl) { bytes_written = bh_max(bytes_written, 0); // Silently consume errors #endif + #ifdef _BH_WINDOWS + BOOL success = WriteFile(process->host_to_proc_write, buffer, input_len, &bytes_written, NULL); + if (!success) bytes_written = 0; + #endif + results->data[0] = WASM_I32_VAL(bytes_written); return NULL; } @@ -357,6 +397,11 @@ WASM_INTEROP(onyx_process_kill_impl) { results->data[0] = WASM_I32_VAL(!failed); #endif + #ifdef _BH_WINDOWS + BOOL success = TerminateProcess(process->proc_info.hProcess, 1); + results->data[0] = WASM_I32_VAL(success ? 1 : 0); + #endif + return NULL; } @@ -377,6 +422,17 @@ WASM_INTEROP(onyx_process_wait_impl) { results->data[0] = WASM_I32_VAL(exit_code != 0 ? 2 : 0); #endif + #ifdef _BH_WINDOWS + DWORD result = WaitForSingleObject(process->proc_info.hProcess, INFINITE); + CloseHandle(process->host_to_proc_write); + CloseHandle(process->proc_to_host_write); + CloseHandle(process->proc_to_host_read); + + DWORD exitCode; + GetExitCodeProcess(process->proc_info.hProcess, &exitCode); + results->data[0] = WASM_I32_VAL(exitCode != 0 ? 2 : 0); + #endif + return NULL; } @@ -390,9 +446,17 @@ WASM_INTEROP(onyx_process_destroy_impl) { kill(process->pid, SIGKILL); close(process->proc_to_host[0]); close(process->host_to_proc[1]); - bh_free(global_heap_allocator, process); #endif + #ifdef _BH_WINDOWS + TerminateProcess(process->proc_info.hProcess, 1); + CloseHandle(process->host_to_proc_write); + CloseHandle(process->proc_to_host_write); + CloseHandle(process->proc_to_host_read); + #endif + + bh_free(global_heap_allocator, process); + return NULL; } -- 2.25.1