made running subprocesses better on windows
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 3 Dec 2021 01:29:28 +0000 (19:29 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 3 Dec 2021 01:29:28 +0000 (19:29 -0600)
core/runtime/build_opts.onyx
include/small_windows.h
scripts/run_tests.onyx
src/builtins.c
src/wasm_runtime.c

index 483257a5931424242bd2eafaaec241f9a7e37dc5..af42c69969e36f0a0bcb0b9462eefd8978cb9f75 100644 (file)
@@ -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
index 4f3114dda44f4acffae143e1c7c4ead413c11f51..0950b9815e174a5ce075489297d2e9b93d849279 100644 (file)
@@ -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);
index 077c3dc584c30419e29b1eedcea804de5de7c70f..4cda81e9f79e3d9affd7a078826a0afb1e4731b6 100644 (file)
@@ -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);
index 382029e2e8ea561cabf5dae64ce5c2e94b2e38df..515c133fec37dcc0757d2866d1a64be5c538b62d 100644 (file)
@@ -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);
 }
index 3b327837c0be39dc1bc5d24b6a1a1dbb0a07d21a..24a519650d87ffce1b38206e351a3108625b99cf 100644 (file)
@@ -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;
 }