separated onyx runtime parts
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 6 Sep 2022 02:58:24 +0000 (21:58 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 6 Sep 2022 02:58:24 +0000 (21:58 -0500)
runtime/onyx_runtime.c
runtime/src/ort_cptr.h [new file with mode: 0644]
runtime/src/ort_directories.h [new file with mode: 0644]
runtime/src/ort_files.h [new file with mode: 0644]
runtime/src/ort_net.h [new file with mode: 0644]
runtime/src/ort_os.h [new file with mode: 0644]
runtime/src/ort_processes.h [new file with mode: 0644]
runtime/src/ort_threads.h [new file with mode: 0644]
runtime/src/ort_time.h [new file with mode: 0644]

index 88a13553809ba5eae18dbc96e9f6fa6c0d110762..cdcf83e1ceae85c5b7a464e4dc260cfac349a649 100644 (file)
 
 #include "types.h"  // For POINTER_SIZE
 
-#define ONYX_FILE_ERROR_NONE 0
-#define ONYX_FILE_ERROR_NOT_FOUND 1
-#define ONYX_FILE_ERROR_EXISTS 2
-#define ONYX_FILE_ERROR_PERMISSION 3
-#define ONYX_FILE_ERROR_BAD_FILE 4
-#define ONYX_FILE_ERROR_BAD_MODE 5
+#include "src/ort_files.h"
+#include "src/ort_directories.h"
+#include "src/ort_threads.h"
+#include "src/ort_processes.h"
+#include "src/ort_os.h"
+#include "src/ort_time.h"
+#include "src/ort_cptr.h"
+#include "src/ort_net.h"
 
-ONYX_DEF(__file_open_impl, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
-    int   path_len = params->data[1].of.i32;
-
-    char path[512] = {0};
-    path_len = bh_min(path_len, 511);
-    strncpy(path, path_ptr, path_len);
-    path[path_len] = 0;
-
-    int mode = params->data[2].of.i32;
-
-    bh_file_mode bh_mode;
-    switch (mode) {
-        case 1: bh_mode = BH_FILE_MODE_READ; break;
-        case 2: bh_mode = BH_FILE_MODE_WRITE; break;
-        case 3: bh_mode = BH_FILE_MODE_APPEND; break;
-    }
-
-    bh_file file;
-    bh_file_error error = bh_file_open_mode(&file, bh_mode, path);
-    if (error == BH_FILE_ERROR_INVALID) {
-        results->data[0] = WASM_I32_VAL(ONYX_FILE_ERROR_NOT_FOUND);
-        return NULL;
-    }
-
-    *(u64 *) ONYX_PTR(params->data[3].of.i32) = (u64) file.fd;
-    results->data[0] = WASM_I32_VAL(ONYX_FILE_ERROR_NONE);
-    return NULL;
-}
-
-ONYX_DEF(__file_close, (WASM_I64), (WASM_I32)) {
-    i64 fd = params->data[0].of.i64;
-
-    bh_file file = { (bh_file_descriptor) fd };
-    bh_file_error error = bh_file_close(&file);
-    if (error == BH_FILE_ERROR_INVALID) {
-        results->data[0] = WASM_I32_VAL(ONYX_FILE_ERROR_NOT_FOUND);
-        return NULL;
-    }
-
-    results->data[0] = WASM_I32_VAL(ONYX_FILE_ERROR_NONE);
-    return NULL;
-}
-
-ONYX_DEF(__file_exists, (WASM_I32, WASM_I32), (WASM_I32)) {
-    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
-    int   path_len = params->data[1].of.i32;
-
-    char path[512] = {0};
-    path_len = bh_min(path_len, 511);
-    strncpy(path, path_ptr, path_len);
-    path[path_len] = 0;
-
-    results->data[0] = WASM_I32_VAL(bh_file_exists(path));
-    return NULL;
-}
-
-ONYX_DEF(__file_stat, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
-    int   path_len = params->data[1].of.i32;
-
-    char path[512] = {0};
-    path_len = bh_min(path_len, 511);
-    strncpy(path, path_ptr, path_len);
-    path[path_len] = 0;
-
-    results->data[0] = WASM_I32_VAL(bh_file_stat(path, ONYX_PTR(params->data[2].of.i32)));
-    return NULL;
-}
-
-ONYX_DEF(__file_remove, (WASM_I32, WASM_I32), (WASM_I32)) {
-    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
-    int   path_len = params->data[1].of.i32;
-
-    char path[512] = {0};
-    path_len = bh_min(path_len, 511);
-    strncpy(path, path_ptr, path_len);
-    path[path_len] = 0;
-
-    results->data[0] = WASM_I32_VAL(bh_file_remove(path));
-    return NULL;
-}
-
-ONYX_DEF(__file_seek, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
-    i64 fd = params->data[0].of.i64;
-    i32 offset = params->data[1].of.i32;
-    i32 whence = params->data[2].of.i32;
-
-    bh_file file = { (bh_file_descriptor) fd };
-    bh_file_whence bh_whence;
-    switch (whence) {
-        case 0: bh_whence = BH_FILE_WHENCE_BEGIN; break;
-        case 1: bh_whence = BH_FILE_WHENCE_CURRENT; break;
-        case 2: bh_whence = BH_FILE_WHENCE_END; break;
-    }
-
-    i64 new_offset = bh_file_seek(&file, offset, whence);
-    results->data[0] = WASM_I32_VAL((i32) new_offset);
-    return NULL;
-}
-
-ONYX_DEF(__file_tell, (WASM_I64), (WASM_I32)) {
-    i64 fd = params->data[0].of.i64;
-    bh_file file = { (bh_file_descriptor) fd };
-    results->data[0] = WASM_I32_VAL(bh_file_tell(&file));
-    return NULL;
-}
-
-ONYX_DEF(__file_read, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    i64 fd = params->data[0].of.i64;
-    bh_file file = { (bh_file_descriptor) fd };
-
-    i32 curr_pos = bh_file_tell(&file);
-    b32 success = bh_file_read_at(&file,
-            bh_file_tell(&file),
-            ONYX_PTR(params->data[1].of.i32),
-            params->data[2].of.i32,
-            (i64 *) ONYX_PTR(params->data[3].of.i32));
-
-    bh_file_seek_to(&file, curr_pos + *(i32 *) ONYX_PTR(params->data[3].of.i32));
-
-    results->data[0] = WASM_I32_VAL(0);
-    if (!success) results->data[0] = WASM_I32_VAL(2);
-    return NULL;
-}
-
-ONYX_DEF(__file_write, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    i64 fd = params->data[0].of.i64;
-    bh_file file = { (bh_file_descriptor) fd };
-
-    i32 curr_pos = bh_file_tell(&file);
-    b32 success = bh_file_write_at(&file,
-            bh_file_tell(&file),
-            ONYX_PTR(params->data[1].of.i32),
-            params->data[2].of.i32,
-            (i64 *) ONYX_PTR(params->data[3].of.i32));
-
-    bh_file_seek_to(&file, curr_pos + *(i32 *) ONYX_PTR(params->data[3].of.i32));
-
-    results->data[0] = WASM_I32_VAL(0);
-    if (!success) results->data[0] = WASM_I32_VAL(2);
-    return NULL;
-}
-
-ONYX_DEF(__file_flush, (WASM_I64), (WASM_I32)) {
-    i64 fd = params->data[0].of.i64;
-    bh_file file = { (bh_file_descriptor) fd };
-    bh_file_flush(&file);
-    results->data[0] = WASM_I32_VAL(0);
-    return NULL;
-}
-
-ONYX_DEF(__file_size, (WASM_I64), (WASM_I32)) {
-    i64 fd = params->data[0].of.i64;
-    bh_file file = { (bh_file_descriptor) fd };
-    results->data[0] = WASM_I32_VAL(bh_file_size(&file));
-    return NULL;
-}
-
-ONYX_DEF(__file_get_standard, (WASM_I32, WASM_I32), (WASM_I32)) {
-    bh_file_standard standard = (bh_file_standard) params->data[0].of.i32;
-
-    bh_file file;
-    bh_file_error error = bh_file_get_standard(&file, standard);
-    if (error == BH_FILE_ERROR_NONE) {
-        *(u64 *) ONYX_PTR(params->data[1].of.i32) = (u64) file.fd;
-    }
-
-    results->data[0] = WASM_I32_VAL(error == BH_FILE_ERROR_NONE);
-    return NULL;
-}
-
-ONYX_DEF(__file_rename, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    char *old_path_ptr = ONYX_PTR(params->data[0].of.i32);
-    int   old_path_len = params->data[1].of.i32;
-
-    char old_path[512] = {0};
-    old_path_len = bh_min(old_path_len, 511);
-    strncpy(old_path, old_path_ptr, old_path_len);
-    old_path[old_path_len] = 0;
-
-    char *new_path_ptr = ONYX_PTR(params->data[2].of.i32);
-    int   new_path_len = params->data[3].of.i32;
-
-    char new_path[512] = {0};
-    new_path_len = bh_min(new_path_len, 511);
-    strncpy(new_path, new_path_ptr, new_path_len);
-    new_path[new_path_len] = 0;
-
-#ifdef _BH_WINDOWS
-    results->data[0] = WASM_I32_VAL(MoveFileA(old_path, new_path));
-    return NULL;
-#endif
-
-#ifdef _BH_LINUX
-    results->data[0] = WASM_I32_VAL(rename(old_path, new_path) == 0);
-    return NULL;
-#endif
-}
-
-//
-// Directories
-//
-
-ONYX_DEF(__dir_open, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
-    int   path_len = params->data[1].of.i32;
-
-    char path[512] = {0};
-    path_len = bh_min(path_len, 511);
-    strncpy(path, path_ptr, path_len);
-    path[path_len] = 0;
-
-#ifdef _BH_WINDOWS
-    for (int i=0; i<path_len; i++) if (path[i] == '/') path[i] = '\\';
-    strncat(path, "\\*.*", 511);
-
-    Windows_Directory_Opened* dir = malloc(sizeof(Windows_Directory_Opened));
-    dir->hndl = FindFirstFileA(path, &dir->found_file);
-    if (dir->hndl == INVALID_HANDLE_VALUE) {
-        results->data[0] = WASM_I32_VAL(0);
-        return NULL;
-    }
-
-    *(u64 *) ONYX_PTR(params->data[2].of.i32) = (u64) dir;
-
-    results->data[0] = WASM_I32_VAL(1);
-    return NULL;
-#endif
-
-#ifdef _BH_LINUX
-    DIR* dir = opendir(path);
-    *(u64 *) ONYX_PTR(params->data[2].of.i32) = (u64) dir;
-    results->data[0] = WASM_I32_VAL(dir != NULL);
-    return NULL;
-#endif
-}
-
-// (DIR*, PTR<DIRENT>) -> BOOL
-ONYX_DEF(__dir_read, (WASM_I64, WASM_I32), (WASM_I32)) {
-#ifdef _BH_WINDOWS
-    Windows_Directory_Opened* dir = (Windows_Directory_Opened *) params->data[0].of.i64;
-    if (dir == NULL) {
-        results->data[0] = WASM_I32_VAL(0);
-        return NULL;
-    }
-
-    do {
-        BOOL success = FindNextFileA(dir->hndl, &dir->found_file);
-        if (!success) {
-            results->data[0] = WASM_I32_VAL(0);
-            return NULL;
-        }
-    } while (!strcmp(dir->found_file.cFileName, ".") || !strcmp(dir->found_file.cFileName, ".."));
-
-    u32 out = params->data[1].of.i32;
-    assert(out != 0);
-
-    *(u32 *) ONYX_PTR(out + 0) = (dir->found_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 3 : 4;
-    *(u32 *) ONYX_PTR(out + 4) = 0;
-    *(u32 *) ONYX_PTR(out + 8) = strlen(dir->found_file.cFileName);
-    strncpy(ONYX_PTR(out + 12), dir->found_file.cFileName, 256);
-
-    results->data[0] = WASM_I32_VAL(1);
-    return NULL;
-#endif
-
-#ifdef _BH_LINUX
-    DIR* dir = (DIR *) params->data[0].of.i64;
-    if (dir == NULL) {
-        results->data[0] = WASM_I32_VAL(0);
-        return NULL;
-    }
-
-    struct dirent *ent;
-    while (1) {
-        ent = readdir(dir);
-        if (ent == NULL) {
-            results->data[0] = WASM_I32_VAL(0);
-            return NULL;
-        }
-
-        // Skip the current directory and parent directory
-        if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) break;
-    }
-
-    u32 type = 0;
-    switch (ent->d_type) {
-        case DT_UNKNOWN: break;
-        case DT_BLK: type = 1; break;
-        case DT_CHR: type = 2; break;
-        case DT_DIR: type = 3; break;
-        case DT_LNK: type = 5; break;
-        case DT_REG: type = 4; break;
-        default: type = 6; break;
-    }
-
-    u32 out = params->data[1].of.i32;
-    assert(out != 0);
-
-    *(u32 *) ONYX_PTR(out + 0) = type;
-    *(u32 *) ONYX_PTR(out + 4) = (u32) ent->d_ino;
-    *(u32 *) ONYX_PTR(out + 8) = strlen(ent->d_name);
-    strncpy(ONYX_PTR(out + 12), ent->d_name, 256);
-
-    results->data[0] = WASM_I32_VAL(1);
-    return NULL;
-#endif
-}
-
-ONYX_DEF(__dir_close, (WASM_I64), ()) {
-#ifdef _BH_WINDOWS
-    Windows_Directory_Opened* dir = (Windows_Directory_Opened *) params->data[0].of.i64;
-
-    FindClose(dir->hndl);
-    free(dir);
-
-    return NULL;
-#endif
-
-#ifdef _BH_LINUX
-    DIR* dir = (DIR *) params->data[0].of.i64;
-    if (dir == NULL) return NULL;
-
-    closedir(dir);
-#endif
-    return NULL;
-}
-
-ONYX_DEF(__dir_create, (WASM_I32, WASM_I32), (WASM_I32)) {
-    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
-    int   path_len = params->data[1].of.i32;
-
-    char path[512] = {0};
-    path_len = bh_min(path_len, 511);
-    strncpy(path, path_ptr, path_len);
-    path[path_len] = 0;
-
-#ifdef _BH_WINDOWS
-    results->data[0] = WASM_I32_VAL(CreateDirectoryA(path));
-    return NULL;
-#endif
-
-#ifdef _BH_LINUX
-    results->data[0] = WASM_I32_VAL(mkdir(path, 0777) == 0);
-    return NULL;
-#endif
-}
-
-ONYX_DEF(__dir_remove, (WASM_I32, WASM_I32), (WASM_I32)) {
-    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
-    int   path_len = params->data[1].of.i32;
-
-    char path[512] = {0};
-    path_len = bh_min(path_len, 511);
-    strncpy(path, path_ptr, path_len);
-    path[path_len] = 0;
-
-#ifdef _BH_WINDOWS
-    results->data[0] = WASM_I32_VAL(RemoveDirectoryA(path));
-    return NULL;
-#endif
-
-#ifdef _BH_LINUX
-    results->data[0] = WASM_I32_VAL(rmdir(path) == 0);
-    return NULL;
-#endif
-}
-
-//
-// THREADS
-//
-typedef struct OnyxThread {
-    i32 id;
-    i32 tls_base;
-    i32 funcidx;
-    i32 dataptr;
-    wasm_instance_t* instance;
-
-    #ifdef _BH_LINUX
-        pthread_t thread;
-    #endif
-
-    #ifdef _BH_WINDOWS
-        HANDLE thread_handle;
-        i32    thread_id;
-    #endif
-} OnyxThread;
-
-static bh_arr(OnyxThread) threads = NULL;
-
-#ifdef _BH_LINUX
-static void *onyx_run_thread(void *data) {
-#endif
-#ifdef _BH_WINDOWS
-static i32 onyx_run_thread(void *data) {
-#endif
-    OnyxThread *thread = (OnyxThread *) data;
-
-    wasm_store_t *wasm_store = runtime->wasm_store_new(runtime->wasm_engine);
-
-    wasm_trap_t* traps = NULL;
-    thread->instance = runtime->wasm_instance_new(wasm_store, runtime->wasm_module, &runtime->wasm_imports, &traps);
-
-    wasm_extern_t* start_extern = runtime->wasm_extern_lookup_by_name(runtime->wasm_module, thread->instance, "_thread_start");
-    wasm_func_t*   start_func   = runtime->wasm_extern_as_func(start_extern);
-
-    wasm_extern_t* exit_extern = runtime->wasm_extern_lookup_by_name(runtime->wasm_module, thread->instance, "_thread_exit");
-    wasm_func_t*   exit_func   = runtime->wasm_extern_as_func(exit_extern);
-
-    wasm_trap_t* trap=NULL;
-
-    // NOTE: This is cached in a local variable because there is a tiny chance that if a lot of threads are created
-    // then the backing array for the thread handles will move and thread* we have well not be valid. I'm betting on this
-    // not happening before now in the function; however, it *could* happen before we call thread_exit. This would be bad
-    // because of the normal reasons why accessing memory that you don't own any more is bad.
-    i32 thread_id = thread->id;
-
-    { // Call the _thread_start procedure
-        wasm_val_t args[]    = { WASM_I32_VAL(thread_id), WASM_I32_VAL(thread->tls_base), WASM_I32_VAL(thread->funcidx), WASM_I32_VAL(thread->dataptr) };
-        wasm_val_vec_t results = { 0, 0 };
-        wasm_val_vec_t args_array = WASM_ARRAY_VEC(args);
-
-        trap = runtime->wasm_func_call(start_func, &args_array, &results);
-        if (trap != NULL) {
-            bh_printf("THREAD: %d\n", thread_id);
-            runtime->onyx_print_trap(trap);
-        }
-    }
-
-    { // Call the _thread_exit procedure
-        wasm_val_t args[]    = { WASM_I32_VAL(thread_id) };
-        wasm_val_vec_t results = { 0, 0 };
-        wasm_val_vec_t args_array = WASM_ARRAY_VEC(args);
-
-        trap = runtime->wasm_func_call(exit_func, &args_array, &results);
-    }
-
-    runtime->wasm_store_delete(wasm_store);
-
-    return 0;
-}
-
-ONYX_DEF(__spawn_thread, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    if (threads == NULL) bh_arr_new(bh_heap_allocator(), threads, 128);
-    bh_arr_insert_end(threads, 1);
-    OnyxThread *thread = &bh_arr_last(threads);
-
-    thread->id       = params->data[0].of.i32;
-    thread->tls_base = params->data[1].of.i32;
-    thread->funcidx  = params->data[2].of.i32;
-    thread->dataptr  = params->data[3].of.i32;
-
-    #ifdef _BH_LINUX
-        pthread_create(&thread->thread, NULL, onyx_run_thread, thread);
-    #endif
-
-    #ifdef _BH_WINDOWS
-        // thread->thread_handle = CreateThread(NULL, 0, onyx_run_thread, thread, 0, &thread->thread_id);
-        thread->thread_handle = (HANDLE) _beginthreadex(NULL, 0, onyx_run_thread, thread, 0, &thread->thread_id);
-    #endif
-
-    results->data[0] = WASM_I32_VAL(1);
-    return NULL;
-}
-
-ONYX_DEF(__kill_thread, (WASM_I32), (WASM_I32)) {
-    i32 thread_id = params->data[0].of.i32;
-
-    i32 i = 0;
-    bh_arr_each(OnyxThread, thread, threads) {
-        if (thread->id == thread_id) {
-            #ifdef _BH_LINUX
-            // This leads to some weirdness and bugs...
-            //
-            pthread_kill(thread->thread, SIGKILL);
-            #endif
-
-            #ifdef _BH_WINDOWS
-            TerminateThread(thread->thread_handle, 0);
-            CloseHandle(thread->thread_handle);
-            #endif
-
-            bh_arr_deleten(threads, i, 1);
-            results->data[0] = WASM_I32_VAL(1);
-            return NULL;
-        }
-
-        i++;
-    }
-
-    results->data[0] = WASM_I32_VAL(0);
-    return NULL;
-}
-
-
-
-
-//
-// PROCESS
-//
-#define ONYX_PROCESS_MAGIC_NUMBER 0xdeadfadebabecafe
-typedef struct OnyxProcess {
-    u64 magic_number;
-
-#ifdef _BH_LINUX
-    // Pipes
-    i32 proc_to_host[2];
-    i32 host_to_proc[2];
-
-    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;
-
-ONYX_DEF(__process_spawn, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I64)) {
-    char* process_str = ONYX_PTR(params->data[0].of.i32);
-    i32   process_len = params->data[1].of.i32;
-    i32   args_ptr    = params->data[2].of.i32;
-    i32   args_len    = params->data[3].of.i32;
-    b32   blocking_io = !params->data[4].of.i32;
-    char *cwd_str     = ONYX_PTR(params->data[5].of.i32);
-    i32   cwd_len     = params->data[6].of.i32;
-
-    char process_path[1024];
-    process_len = bh_min(1023, process_len);
-    memcpy(process_path, process_str, process_len);
-    process_path[process_len] = '\0';
-
-    char starting_dir[1024];
-    if (cwd_len > 0) {
-        cwd_len = bh_min(1023, cwd_len);
-        memcpy(starting_dir, cwd_str, cwd_len);
-        starting_dir[cwd_len] = '\0';
-    }
-
-    OnyxProcess *process = malloc(sizeof(OnyxProcess));
-    memset(process, 0, sizeof(*process));
-    process->magic_number = ONYX_PROCESS_MAGIC_NUMBER;
-
-    #ifdef _BH_LINUX
-        // :Security - alloca a user controlled string.
-        char **process_args = alloca(sizeof(char *) * (args_len + 2));
-        byte_t* array_loc = ONYX_PTR(args_ptr);
-        fori (i, 0, args_len) {
-            char *arg_str = ONYX_PTR(*(i32 *) (array_loc + i * 2 * POINTER_SIZE));
-            i32   arg_len = *(i32 *) (array_loc + i * 2 * POINTER_SIZE + POINTER_SIZE);
-
-            char *arg = alloca(sizeof(char) * (arg_len + 1));
-            memcpy(arg, arg_str, arg_len);
-            arg[arg_len] = '\0';
-            process_args[i + 1] = arg;
-        }
-        process_args[0] = process_path;
-        process_args[args_len + 1] = NULL;
-
-        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()) {
-            case -1: // Bad fork
-                wasm_val_init_ptr(&results->data[0], NULL); // Failed to run
-
-                close(process->proc_to_host[0]);
-                close(process->proc_to_host[1]);
-                close(process->host_to_proc[0]);
-                close(process->host_to_proc[1]);
-                break;
-
-            case 0: // Child process
-                close(process->proc_to_host[0]);
-                close(process->host_to_proc[1]);
-                dup2(process->host_to_proc[0], 0); // Map the output to the pipe
-                dup2(process->proc_to_host[1], 1); // Map the output to the pipe
-                dup2(process->proc_to_host[1], 2); // Stderr to stdout
-
-                if (!blocking_io) {
-                    fcntl(0, F_SETFL, O_NONBLOCK);
-                    fcntl(1, F_SETFL, O_NONBLOCK);
-                }
-
-                if (cwd_len > 0) {
-                    chdir(starting_dir); // Switch current working directory.
-                }
-
-                execvp(process_path, process_args);
-                exit(-1);
-                break;
-
-            default: {
-                process->pid = pid;
-                close(process->host_to_proc[0]);
-                close(process->proc_to_host[1]);
-
-                wasm_val_init_ptr(&results->data[0], process);
-                break;
-            }
-        }
-
-    #endif
-
-    #ifdef _BH_WINDOWS
-        // CLEANUP CLEANUP CLEANUP: This is so freaking bad...
-        char cmdLine[2048];
-        memset(cmdLine, 0, 2048);
-        strncat(cmdLine, "\"", 2047);
-        strncat(cmdLine, process_path, 2047);
-        strncat(cmdLine, "\"", 2047);
-
-        byte_t* array_loc = ONYX_PTR(args_ptr);
-        fori (i, 0, args_len) {
-            char *arg_str = ONYX_PTR(*(i32 *) (array_loc + i * 2 * POINTER_SIZE));
-            i32   arg_len = *(i32 *) (array_loc + i * 2 * POINTER_SIZE + 4);
-
-            strncat(cmdLine, " \"", 2047);
-            strncat(cmdLine, arg_str, arg_len);
-            strncat(cmdLine, "\"", 2047);
-        }
-
-        STARTUPINFOA startup;
-        memset(&startup, 0, sizeof startup);
-        startup.cb = sizeof(startup);
-
-        SECURITY_ATTRIBUTES saAttr;
-        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
-        saAttr.lpSecurityDescriptor = NULL;
-        saAttr.bInheritHandle = 1;
-
-        i32 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) {
-            // printf("FAILED TO CREATE PIPES: %d\n", GetLastError());
-            wasm_val_init_ptr(&results->data[0], NULL); // Failed to run @LEAK
-            return NULL;
-        }
-
-        success = SetHandleInformation(process->proc_to_host_read, 1 /* HANDLE_FLAG_INHERIT */, 0);
-        success = success && SetHandleInformation(process->host_to_proc_write, 1 /* HANDLE_FLAG_INHERIT */, 0);
-        if (!success) {
-            // printf("FAILED TO CONFIGURE PIPES: %d\n", GetLastError());
-            wasm_val_init_ptr(&results->data[0], NULL); // Failed to run @LEAK
-            return NULL;
-        }
-
-        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;
-
-        memset(&process->proc_info, 0, sizeof process->proc_info);
-
-        char *working_dir = NULL;
-        if (cwd_len > 0) {
-            working_dir = starting_dir;
-        }
-
-        success = CreateProcessA(process_path, cmdLine, &saAttr, &saAttr, 1, 0, NULL, working_dir, &startup, &process->proc_info);
-        if (!success) {
-            printf("FAILED TO CREATE PROCESS: %d\n", GetLastError());
-            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;
-}
-
-ONYX_DEF(__process_read, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
-    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
-    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
-        results->data[0] = WASM_I32_VAL(0);
-        return NULL;
-    }
-
-    i32 output_ptr = params->data[1].of.i32;
-    i32 output_len = params->data[2].of.i32;
-    u8 *buffer = ONYX_PTR(output_ptr);
-
-    i32 bytes_read;
-    #ifdef _BH_LINUX
-        bytes_read = read(process->proc_to_host[0], buffer, output_len);
-        if (bytes_read < 0) {
-            switch (errno) {
-                case EAGAIN: bytes_read =  0; break;
-                case EBADF:  bytes_read = -1; break;
-                default:     bytes_read = -2; break;
-            }
-        }
-    #endif
-
-    #ifdef _BH_WINDOWS
-        i32 success = ReadFile(process->proc_to_host_read, buffer, output_len, &bytes_read, NULL);
-        if (!success) {
-            bytes_read = -1;
-        }
-    #endif
-
-    results->data[0] = WASM_I32_VAL(bytes_read);
-    return NULL;
-}
-
-ONYX_DEF(__process_write, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
-    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
-    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
-        results->data[0] = WASM_I32_VAL(0);
-        return NULL;
-    }
-
-    i32 input_ptr = params->data[1].of.i32;
-    i32 input_len = params->data[2].of.i32;
-    u8 *buffer = ONYX_PTR(input_ptr);
-
-    i32 bytes_written;
-    #ifdef _BH_LINUX
-        bytes_written = write(process->host_to_proc[1], buffer, input_len);
-        bytes_written = bh_max(bytes_written, 0);  // Silently consume errors
-    #endif
-
-    #ifdef _BH_WINDOWS
-        i32 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;
-}
-
-ONYX_DEF(__process_kill, (WASM_I64), (WASM_I32)) {
-    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
-    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
-        results->data[0] = WASM_I32_VAL(0);
-        return NULL;
-    }
-
-    #ifdef _BH_LINUX
-        i32 failed = kill(process->pid, SIGKILL);
-        results->data[0] = WASM_I32_VAL(!failed);
-    #endif
-
-    #ifdef _BH_WINDOWS
-        i32 success = TerminateProcess(process->proc_info.hProcess, 1);
-        results->data[0] = WASM_I32_VAL(success ? 1 : 0);
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__process_wait, (WASM_I64), (WASM_I32)) {
-    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
-    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
-        results->data[0] = WASM_I32_VAL(1);
-        return NULL;
-    }
-
-    #ifdef _BH_LINUX
-        i32 status;
-        waitpid(process->pid, &status, 0);
-
-        i32 exit_code = WEXITSTATUS(status);
-        results->data[0] = WASM_I32_VAL(exit_code != 0 ? 2 : 0);
-    #endif
-
-    #ifdef _BH_WINDOWS
-        DWORD exitCode;
-        while (1) {
-            if (!WaitForSingleObject(process->proc_info.hProcess, INFINITE)) {
-                // HACK HACK HACK
-                DWORD error = GetLastError();
-                if (error != 109 && error != 6) {
-                    // printf("ERROR IN WAIT FOR SINGLE: %d\n", error);
-                    results->data[0] = WASM_I32_VAL(1);
-                    return NULL;
-                }
-            }
-
-            if (!GetExitCodeProcess(process->proc_info.hProcess, &exitCode)) {
-                // HACK HACK HACK
-                // Apparently, I'm doing something wrong (maybe?) where the process handle becomes
-                // invalid and causes error 6 "invalid handle". So I think I can safely assume that
-                // if that is the case, then the process exited? probably successfuly? hopefully?
-                // Honestly I don't know and I can't find any documentation describing when a process
-                // handle goes invalid, other than after you close it explicitly. But in the run_tests
-                // script, I'm not calling either process_kill or process_destroy, which are the only
-                // other functions that close the process handle. So I'm left in the dark as to why this
-                // is happening, but oh well. This works for now.
-                //                                                           - brendanfh 2021/12/03
-                if (GetLastError() == 6) {
-                    exitCode = 0;
-                    break;
-                }
-
-                results->data[0] = WASM_I32_VAL(3);
-                return NULL;
-            }
-
-            // 259 is STILL_ACTIVE (aka STATUS_PENDING), which means that the process has not yet exited
-            if (exitCode != 259) break;
-        }
-
-        results->data[0] = WASM_I32_VAL(exitCode != 0 ? 2 : 0);
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__process_destroy, (WASM_I64), ()) {
-    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
-    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
-        return NULL;
-    }
-
-    #ifdef _BH_LINUX
-        close(process->proc_to_host[0]);
-        close(process->host_to_proc[1]);
-    #endif
-
-    #ifdef _BH_WINDOWS
-        if (!CloseHandle(process->proc_info.hThread)
-         || !CloseHandle(process->proc_info.hProcess)) {
-            // printf("ERROR CLOSING HANDLES: %d\n", GetLastError());
-         }
-    #endif
-
-    free(process);
-
-    return NULL;
-}
-
-ONYX_DEF(__args_get, (WASM_I32, WASM_I32), ()) {
-    if (runtime->argc == 0 || runtime->argv == NULL) {
-        return NULL;
-    }
-
-    i32 buffer_base = params->data[1].of.i32;
-
-    for (int i=0; i<runtime->argc; i++) {
-        // Should this be strncpy? What would the length be?
-        strcpy(ONYX_PTR(buffer_base), runtime->argv[i]);
-        *(i32 *) ONYX_PTR(params->data[0].of.i32 + i * 4) = buffer_base;
-        buffer_base += strlen(runtime->argv[i]) + 1;
-    }
-
-    return NULL;
-}
-
-ONYX_DEF(__args_sizes_get, (WASM_I32, WASM_I32), ()) {
-    *(i32 *) ONYX_PTR(params->data[0].of.i32) = runtime->argc;
-
-    i32 argv_size = 0;
-    for (int i=0; i<runtime->argc; i++) {
-        argv_size += strlen(runtime->argv[i]) + 1;
-    }
-
-    *(i32 *) ONYX_PTR(params->data[1].of.i32) = argv_size;
-    return NULL;
-}
-
-ONYX_DEF(__exit, (WASM_I32), ()) {
-    exit(params->data[0].of.i32);
-    return NULL;
-}
-
-ONYX_DEF(__sleep, (WASM_I32), ()) {
-    #ifdef _BH_LINUX
-    usleep(params->data[0].of.i32 * 1000);
-    #endif
-
-    #ifdef _BH_WINDOWS
-    Sleep(params->data[0].of.i32);
-    #endif
-    return NULL;
-}
-
-ONYX_DEF(__time, (), (WASM_I64)) {
-    results->data[0] = WASM_I64_VAL(bh_time_curr());
-    return NULL;
-}
-
-
-
-
-//
-// Dates and Times
-//
-ONYX_DEF(__time_localtime, (WASM_I64, WASM_I32), ()) {
-    u64 t = params->data[0].of.i64;
-    *(struct tm *) ONYX_PTR(params->data[1].of.i32) = *localtime(&t);
-    return NULL;
-}
-
-ONYX_DEF(__time_gmtime, (WASM_I64, WASM_I32), ()) {
-    u64 t = params->data[0].of.i64;
-    *(struct tm *) ONYX_PTR(params->data[1].of.i32) = *gmtime(&t);
-    return NULL;
-}
-
-ONYX_DEF(__time_strftime, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    u32 len = strftime(ONYX_PTR(params->data[0].of.i32), params->data[1].of.i32, ONYX_PTR(params->data[2].of.i32), ONYX_PTR(params->data[3].of.i32));
-    results->data[0] = WASM_I32_VAL(len); 
-    return NULL;
-}
-
-ONYX_DEF(__time_strptime, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    #if defined(_BH_LINUX)
-    char *rem = strptime(ONYX_PTR(params->data[0].of.i32), params->data[1].of.i32, ONYX_PTR(params->data[2].of.i32), ONYX_PTR(params->data[3].of.i32));
-    results->data[0] = WASM_I32_VAL(rem != NULL); 
-    #else
-    results->data[0] = WASM_I32_VAL(0);
-    #endif
-    return NULL;
-}
-
-
-
-//
-// Networking
-//
-struct onyx_socket_addr {
-    unsigned short family;
-    unsigned short port;
-    unsigned int   addr;
-};
-
-static inline int onyx_socket_domain(int i) {
-    #if defined(_BH_LINUX)
-    switch (i) {    // :EnumDependent
-        case 0: return AF_UNIX;
-        case 1: return AF_INET;
-        case 2: return AF_INET6;
-        default: return -1;
-    }
-    #elif defined(_BH_WINDOWS)
-    return -1;
-    #endif
-}
-
-static inline int onyx_socket_protocol(int i) {
-    #if defined(_BH_LINUX)
-    switch (i) {    // :EnumDependent
-        case 0: return SOCK_STREAM;
-        case 1: return SOCK_DGRAM;
-        default: return -1;
-    }
-    #elif defined(_BH_WINDOWS)
-    return -1;
-    #endif
-}
-
-ONYX_DEF(__net_create_socket, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-
-    #ifdef _BH_LINUX
-    int domain = onyx_socket_domain(params->data[1].of.i32);
-    if (domain == -1) goto bad_settings;
-
-    int type = onyx_socket_protocol(params->data[2].of.i32);
-    if (type == -1) goto bad_settings;
-
-    *((int *) ONYX_PTR(params->data[0].of.i32)) = socket(domain, type, 0);
-
-    results->data[0] = WASM_I32_VAL(0);
-    return NULL;
-    #endif 
-
-    #ifdef _BH_WINDOWS
-    #endif
-
-bad_settings:
-    results->data[0] = WASM_I32_VAL(1); // :EnumDependent
-    return NULL;
-}
-
-ONYX_DEF(__net_close_socket, (WASM_I32), ()) {
-    #ifdef _BH_LINUX
-    shutdown(params->data[0].of.i32, SHUT_RDWR);
-    close(params->data[0].of.i32);
-    #endif
-
-    #ifdef _BH_WINDOWS
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_setting, (WASM_I32, WASM_I32, WASM_I32), ()) {
-    #ifdef _BH_LINUX
-    switch (params->data[1].of.i32) {
-        case 1: { // :EnumDependent  Non-Blocking
-            int s = params->data[0].of.i32;
-            int flags = fcntl(s, F_GETFL, 0);
-            if (params->data[2].of.i32) {
-                flags |= O_NONBLOCK;
-            } else {
-                flags &= ~O_NONBLOCK;
-            }
-
-            fcntl(s, F_SETFL, flags);
-            break;
-        }
-
-        case 2: { // :EnumDependent  Broadcast
-            int s = params->data[0].of.i32;
-            setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &params->data[2].of.i32, sizeof(int));
-            break;
-        }
-    }
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_bind, (WASM_I32, WASM_I32), (WASM_I32)) {
-
-    #ifdef _BH_LINUX
-    int res = -1;
-
-    struct onyx_socket_addr *oaddr = (void *) ONYX_PTR(params->data[1].of.i32);
-    int family = onyx_socket_domain(oaddr->family);
-    int port   = oaddr->port;
-
-    switch (family) {
-        case AF_INET: {
-            struct sockaddr_in bind_addr;
-            memset(&bind_addr, 0, sizeof(bind_addr));
-
-            bind_addr.sin_family = AF_INET;
-            bind_addr.sin_addr.s_addr = htonl(oaddr->addr);
-            bind_addr.sin_port = htons(port);
-
-            res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
-            break;
-        }
-
-        case AF_INET6: {
-            struct sockaddr_in6 bind_addr;
-            memset(&bind_addr, 0, sizeof(bind_addr));
-
-            bind_addr.sin6_family = AF_INET6;
-            memcpy(&bind_addr.sin6_addr.s6_addr, (void *) &oaddr->addr, 16);
-            bind_addr.sin6_port = htons(port);
-            
-            res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
-            break;
-        }
-
-        case AF_UNIX: {
-            struct sockaddr_un bind_addr;
-            memset(&bind_addr, 0, sizeof(bind_addr));
-
-            bind_addr.sun_family = AF_UNIX;
-            strncpy(&bind_addr.sun_path, (char *) &oaddr->addr, 108);
-            
-            res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
-            break;
-        }
-    }
-
-    results->data[0] = WASM_I32_VAL(res >= 0);
-    #endif
-
-    #ifdef _BH_WINDOWS
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_listen, (WASM_I32, WASM_I32), ()) {
-    #ifdef _BH_LINUX
-    listen(params->data[0].of.i32, params->data[1].of.i32);
-    #endif
-
-    #ifdef _BH_WINDOWS
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_accept, (WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    struct sockaddr_in client_addr;
-    int client_len = sizeof(client_addr);
-    memset(&client_addr, 0, client_len);
-
-    int client_socket = accept(params->data[0].of.i32, &client_addr, &client_len);
-
-    struct onyx_socket_addr* out_addr = (struct onyx_socket_addr *) ONYX_PTR(params->data[1].of.i32); 
-    out_addr->family = client_addr.sin_family;
-    out_addr->port   = ntohs(client_addr.sin_port);
-    out_addr->addr   = ntohl(client_addr.sin_addr.s_addr);
-
-    results->data[0] = WASM_I32_VAL(client_socket);
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_connect_unix, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    int   hostlen  = params->data[2].of.i32;
-    char *hostname = alloca(hostlen + 1);
-    memcpy(hostname, ONYX_PTR(params->data[1].of.i32), hostlen);
-    hostname[hostlen] = '\0';
-
-    struct sockaddr_un server_addr;
-    memset(&server_addr, 0, sizeof(server_addr));
-
-    server_addr.sun_family = AF_UNIX; // See comment above
-    memcpy((char *)&server_addr.sun_path, hostname, hostlen);
-
-    int result = connect(params->data[0].of.i32, &server_addr, sizeof(server_addr));
-    if (result == 0) results->data[0] = WASM_I32_VAL(0);
-    else             results->data[0] = WASM_I32_VAL(3); // :EnumDependent
-    #endif
-    
-    return NULL;
-}
-
-ONYX_DEF(__net_connect_ipv4, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    int   hostlen  = params->data[2].of.i32;
-    char *hostname = alloca(hostlen + 1);
-    memcpy(hostname, ONYX_PTR(params->data[1].of.i32), hostlen);
-    hostname[hostlen] = '\0';
-
-    struct hostent *host;
-    host = gethostbyname(hostname); // TODO: Replace this call, as it is obselete.
-    if (host == NULL) {
-        results->data[0] = WASM_I32_VAL(2);  // :EnumDependent
-        return NULL;
-    }
-
-    struct sockaddr_in server_addr;
-    memset(&server_addr, 0, sizeof(server_addr));
-
-    server_addr.sin_family = AF_INET; // See comment above
-    memcpy((char *)&server_addr.sin_addr.s_addr, (char *)host->h_addr, host->h_length);
-    server_addr.sin_port = htons(params->data[3].of.i32);
-
-    int result = connect(params->data[0].of.i32, &server_addr, sizeof(server_addr));
-    if (result == 0) results->data[0] = WASM_I32_VAL(0);
-    else             results->data[0] = WASM_I32_VAL(3); // :EnumDependent
-
-    return NULL;
-    #endif
-
-    #ifdef _BH_WINDOWS
-    #endif
-}
-
-ONYX_DEF(__net_send, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    // TODO: The flags at the end should be controllable.
-    int sent = send(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, MSG_NOSIGNAL);
-    results->data[0] = WASM_I32_VAL(sent);
-    #endif
-    
-    return NULL;
-}
-
-ONYX_DEF(__net_sendto, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    struct sockaddr_in dest_addr;
-    int dest_addr_len = sizeof(dest_addr);
-    memset(&dest_addr, 0, dest_addr_len);
-
-    struct onyx_socket_addr *o_addr = (struct onyx_socket_addr *) ONYX_PTR(params->data[3].of.i32);
-    dest_addr.sin_family = AF_INET; // TODO: See other comments related to AF_NET above.
-    dest_addr.sin_port = htons(o_addr->port);
-    dest_addr.sin_addr.s_addr = htonl(o_addr->addr);
-
-    // TODO: The flags at the end should be controllable.
-    int sent = sendto(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, MSG_NOSIGNAL, &dest_addr, dest_addr_len);
-    results->data[0] = WASM_I32_VAL(sent);
-    #endif
-    
-    return NULL;
-}
-
-ONYX_DEF(__net_recv, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    *(i32 *) ONYX_PTR(params->data[3].of.i32) = 0;
-
-    #ifdef _BH_LINUX
-    // TODO: The flags at the end should be controllable.
-    int received = recv(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, 0);
-    results->data[0] = WASM_I32_VAL(received);
-
-    if (received < 0) {
-        if (errno == EAGAIN || errno == EWOULDBLOCK) {
-            *(i32 *) ONYX_PTR(params->data[3].of.i32) = 1;
-        }
-    }
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_recvfrom, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    *(i32 *) ONYX_PTR(params->data[4].of.i32) = 0;
-
-    #ifdef _BH_LINUX
-    struct onyx_socket_addr *out_addr = (struct onyx_socket_addr *) ONYX_PTR(params->data[3].of.i32);
-
-    struct sockaddr_in client_addr;
-    int socket_len = sizeof(client_addr);
-    memset(&client_addr, 0, socket_len);
-
-    int received = recvfrom(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, 0, &client_addr, &socket_len);
-    out_addr->family = client_addr.sin_family;
-    out_addr->port   = ntohs(client_addr.sin_port);
-    out_addr->addr   = ntohl(client_addr.sin_addr.s_addr);
-
-    results->data[0] = WASM_I32_VAL(received);
-
-    if (received < 0) {
-        if (errno == EAGAIN || errno == EWOULDBLOCK) {
-            *(i32 *) ONYX_PTR(params->data[3].of.i32) = 1;
-        }
-    }
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_poll_recv, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), ()) {
-    #ifdef _BH_LINUX
-    int i, res, cursor;
-    struct pollfd* fds;
-
-    fds = alloca(params->data[1].of.i32 * sizeof(struct pollfd));
-
-    for (i=0; i<params->data[1].of.i32; i++) {
-        fds[i].fd = *(i32 *) ONYX_PTR(params->data[0].of.i32 + 4 * i);
-        fds[i].events = POLLIN;
-        fds[i].revents = 0;
-    }
-
-    res = poll(fds, params->data[1].of.i32, params->data[2].of.i32);
-
-    for (i=0; i<params->data[1].of.i32; i++) {
-        *(i32 *) ONYX_PTR(params->data[3].of.i32 + 4 * i) = 0; // NO_CHANGE
-
-        if (fds[i].revents & POLLIN) {
-            *(i32 *) ONYX_PTR(params->data[3].of.i32 + 4 * i) = 1; // READABLE
-        }
-
-        if ((fds[i].revents & POLLHUP)
-            || (fds[i].revents & POLLNVAL)
-            || (fds[i].revents & POLLERR)) {
-            *(i32 *) ONYX_PTR(params->data[3].of.i32 + 4 * i) = 2; // CLOSED
-        }
-    }
-
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_host_to_net_s, (WASM_I32), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(htons(params->data[0].of.i32));
-    return NULL;
-}
-
-ONYX_DEF(__net_host_to_net_l, (WASM_I32), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(htonl(params->data[0].of.i32));
-    return NULL;
-}
-
-ONYX_DEF(__net_net_to_host_s, (WASM_I32), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(ntohs(params->data[0].of.i32));
-    return NULL;
-}
-
-ONYX_DEF(__net_net_to_host_l, (WASM_I32), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(ntohl(params->data[0].of.i32));
-    return NULL;
-}
-
-
-//
-// C-Pointers
-//
-// These are wildly unsafe and break the core principles of the security
-// of WebAssembly, so there should be a way to turn them off!
-//
-ONYX_DEF(__cptr_make, (WASM_I32), (WASM_I64)) {
-    wasm_val_init_ptr(&results->data[0], ONYX_PTR(params->data[0].of.i32));
-    return NULL;
-}
-
-ONYX_DEF(__cptr_read, (WASM_I64, WASM_I32, WASM_I32), ()) {
-    memcpy(ONYX_PTR(params->data[1].of.i32), (void *) params->data[0].of.i64, params->data[2].of.i32);
-    return NULL;
-}
-
-ONYX_DEF(__cptr_read_u8, (WASM_I64), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(*(u8 *) params->data[0].of.i64);
-    return NULL;
-}
-
-ONYX_DEF(__cptr_read_u16, (WASM_I64), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(*(u16 *) params->data[0].of.i64);
-    return NULL;
-}
-
-ONYX_DEF(__cptr_read_u32, (WASM_I64), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(*(u32 *) params->data[0].of.i64);
-    return NULL;
-}
-
-ONYX_DEF(__cptr_read_u64, (WASM_I64), (WASM_I64)) {
-    results->data[0] = WASM_I64_VAL(*(u64 *) params->data[0].of.i64);
-    return NULL;
-}
-
-ONYX_DEF(__cptr_extract_str, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
-    unsigned int len = strlen((char *) params->data[0].of.i64);
-
-    if (params->data[2].of.i32 != 0) {
-        strncpy(ONYX_PTR(params->data[1].of.i32), (char *) params->data[0].of.i64, params->data[2].of.i32);
-    }
-
-    results->data[0] = WASM_I32_VAL(len);
-    return NULL;
-}
 
 ONYX_LIBRARY {
     ONYX_FUNC(__file_open_impl)
diff --git a/runtime/src/ort_cptr.h b/runtime/src/ort_cptr.h
new file mode 100644 (file)
index 0000000..f9d5185
--- /dev/null
@@ -0,0 +1,48 @@
+
+//
+// C-Pointers
+//
+// These are wildly unsafe and break the core principles of the security
+// of WebAssembly, so there should be a way to turn them off!
+//
+ONYX_DEF(__cptr_make, (WASM_I32), (WASM_I64)) {
+    wasm_val_init_ptr(&results->data[0], ONYX_PTR(params->data[0].of.i32));
+    return NULL;
+}
+
+ONYX_DEF(__cptr_read, (WASM_I64, WASM_I32, WASM_I32), ()) {
+    memcpy(ONYX_PTR(params->data[1].of.i32), (void *) params->data[0].of.i64, params->data[2].of.i32);
+    return NULL;
+}
+
+ONYX_DEF(__cptr_read_u8, (WASM_I64), (WASM_I32)) {
+    results->data[0] = WASM_I32_VAL(*(u8 *) params->data[0].of.i64);
+    return NULL;
+}
+
+ONYX_DEF(__cptr_read_u16, (WASM_I64), (WASM_I32)) {
+    results->data[0] = WASM_I32_VAL(*(u16 *) params->data[0].of.i64);
+    return NULL;
+}
+
+ONYX_DEF(__cptr_read_u32, (WASM_I64), (WASM_I32)) {
+    results->data[0] = WASM_I32_VAL(*(u32 *) params->data[0].of.i64);
+    return NULL;
+}
+
+ONYX_DEF(__cptr_read_u64, (WASM_I64), (WASM_I64)) {
+    results->data[0] = WASM_I64_VAL(*(u64 *) params->data[0].of.i64);
+    return NULL;
+}
+
+ONYX_DEF(__cptr_extract_str, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
+    unsigned int len = strlen((char *) params->data[0].of.i64);
+
+    if (params->data[2].of.i32 != 0) {
+        strncpy(ONYX_PTR(params->data[1].of.i32), (char *) params->data[0].of.i64, params->data[2].of.i32);
+    }
+
+    results->data[0] = WASM_I32_VAL(len);
+    return NULL;
+}
+
diff --git a/runtime/src/ort_directories.h b/runtime/src/ort_directories.h
new file mode 100644 (file)
index 0000000..3cc8d35
--- /dev/null
@@ -0,0 +1,168 @@
+//
+// Directories
+//
+
+ONYX_DEF(__dir_open, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
+    int   path_len = params->data[1].of.i32;
+
+    char path[512] = {0};
+    path_len = bh_min(path_len, 511);
+    strncpy(path, path_ptr, path_len);
+    path[path_len] = 0;
+
+#ifdef _BH_WINDOWS
+    for (int i=0; i<path_len; i++) if (path[i] == '/') path[i] = '\\';
+    strncat(path, "\\*.*", 511);
+
+    Windows_Directory_Opened* dir = malloc(sizeof(Windows_Directory_Opened));
+    dir->hndl = FindFirstFileA(path, &dir->found_file);
+    if (dir->hndl == INVALID_HANDLE_VALUE) {
+        results->data[0] = WASM_I32_VAL(0);
+        return NULL;
+    }
+
+    *(u64 *) ONYX_PTR(params->data[2].of.i32) = (u64) dir;
+
+    results->data[0] = WASM_I32_VAL(1);
+    return NULL;
+#endif
+
+#ifdef _BH_LINUX
+    DIR* dir = opendir(path);
+    *(u64 *) ONYX_PTR(params->data[2].of.i32) = (u64) dir;
+    results->data[0] = WASM_I32_VAL(dir != NULL);
+    return NULL;
+#endif
+}
+
+// (DIR*, PTR<DIRENT>) -> BOOL
+ONYX_DEF(__dir_read, (WASM_I64, WASM_I32), (WASM_I32)) {
+#ifdef _BH_WINDOWS
+    Windows_Directory_Opened* dir = (Windows_Directory_Opened *) params->data[0].of.i64;
+    if (dir == NULL) {
+        results->data[0] = WASM_I32_VAL(0);
+        return NULL;
+    }
+
+    do {
+        BOOL success = FindNextFileA(dir->hndl, &dir->found_file);
+        if (!success) {
+            results->data[0] = WASM_I32_VAL(0);
+            return NULL;
+        }
+    } while (!strcmp(dir->found_file.cFileName, ".") || !strcmp(dir->found_file.cFileName, ".."));
+
+    u32 out = params->data[1].of.i32;
+    assert(out != 0);
+
+    *(u32 *) ONYX_PTR(out + 0) = (dir->found_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 3 : 4;
+    *(u32 *) ONYX_PTR(out + 4) = 0;
+    *(u32 *) ONYX_PTR(out + 8) = strlen(dir->found_file.cFileName);
+    strncpy(ONYX_PTR(out + 12), dir->found_file.cFileName, 256);
+
+    results->data[0] = WASM_I32_VAL(1);
+    return NULL;
+#endif
+
+#ifdef _BH_LINUX
+    DIR* dir = (DIR *) params->data[0].of.i64;
+    if (dir == NULL) {
+        results->data[0] = WASM_I32_VAL(0);
+        return NULL;
+    }
+
+    struct dirent *ent;
+    while (1) {
+        ent = readdir(dir);
+        if (ent == NULL) {
+            results->data[0] = WASM_I32_VAL(0);
+            return NULL;
+        }
+
+        // Skip the current directory and parent directory
+        if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) break;
+    }
+
+    u32 type = 0;
+    switch (ent->d_type) {
+        case DT_UNKNOWN: break;
+        case DT_BLK: type = 1; break;
+        case DT_CHR: type = 2; break;
+        case DT_DIR: type = 3; break;
+        case DT_LNK: type = 5; break;
+        case DT_REG: type = 4; break;
+        default: type = 6; break;
+    }
+
+    u32 out = params->data[1].of.i32;
+    assert(out != 0);
+
+    *(u32 *) ONYX_PTR(out + 0) = type;
+    *(u32 *) ONYX_PTR(out + 4) = (u32) ent->d_ino;
+    *(u32 *) ONYX_PTR(out + 8) = strlen(ent->d_name);
+    strncpy(ONYX_PTR(out + 12), ent->d_name, 256);
+
+    results->data[0] = WASM_I32_VAL(1);
+    return NULL;
+#endif
+}
+
+ONYX_DEF(__dir_close, (WASM_I64), ()) {
+#ifdef _BH_WINDOWS
+    Windows_Directory_Opened* dir = (Windows_Directory_Opened *) params->data[0].of.i64;
+
+    FindClose(dir->hndl);
+    free(dir);
+
+    return NULL;
+#endif
+
+#ifdef _BH_LINUX
+    DIR* dir = (DIR *) params->data[0].of.i64;
+    if (dir == NULL) return NULL;
+
+    closedir(dir);
+#endif
+    return NULL;
+}
+
+ONYX_DEF(__dir_create, (WASM_I32, WASM_I32), (WASM_I32)) {
+    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
+    int   path_len = params->data[1].of.i32;
+
+    char path[512] = {0};
+    path_len = bh_min(path_len, 511);
+    strncpy(path, path_ptr, path_len);
+    path[path_len] = 0;
+
+#ifdef _BH_WINDOWS
+    results->data[0] = WASM_I32_VAL(CreateDirectoryA(path));
+    return NULL;
+#endif
+
+#ifdef _BH_LINUX
+    results->data[0] = WASM_I32_VAL(mkdir(path, 0777) == 0);
+    return NULL;
+#endif
+}
+
+ONYX_DEF(__dir_remove, (WASM_I32, WASM_I32), (WASM_I32)) {
+    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
+    int   path_len = params->data[1].of.i32;
+
+    char path[512] = {0};
+    path_len = bh_min(path_len, 511);
+    strncpy(path, path_ptr, path_len);
+    path[path_len] = 0;
+
+#ifdef _BH_WINDOWS
+    results->data[0] = WASM_I32_VAL(RemoveDirectoryA(path));
+    return NULL;
+#endif
+
+#ifdef _BH_LINUX
+    results->data[0] = WASM_I32_VAL(rmdir(path) == 0);
+    return NULL;
+#endif
+}
diff --git a/runtime/src/ort_files.h b/runtime/src/ort_files.h
new file mode 100644 (file)
index 0000000..de6e3e0
--- /dev/null
@@ -0,0 +1,212 @@
+
+//
+// Files
+//
+
+#define ONYX_FILE_ERROR_NONE 0
+#define ONYX_FILE_ERROR_NOT_FOUND 1
+#define ONYX_FILE_ERROR_EXISTS 2
+#define ONYX_FILE_ERROR_PERMISSION 3
+#define ONYX_FILE_ERROR_BAD_FILE 4
+#define ONYX_FILE_ERROR_BAD_MODE 5
+
+ONYX_DEF(__file_open_impl, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
+    int   path_len = params->data[1].of.i32;
+
+    char path[512] = {0};
+    path_len = bh_min(path_len, 511);
+    strncpy(path, path_ptr, path_len);
+    path[path_len] = 0;
+
+    int mode = params->data[2].of.i32;
+
+    bh_file_mode bh_mode;
+    switch (mode) {
+        case 1: bh_mode = BH_FILE_MODE_READ; break;
+        case 2: bh_mode = BH_FILE_MODE_WRITE; break;
+        case 3: bh_mode = BH_FILE_MODE_APPEND; break;
+    }
+
+    bh_file file;
+    bh_file_error error = bh_file_open_mode(&file, bh_mode, path);
+    if (error == BH_FILE_ERROR_INVALID) {
+        results->data[0] = WASM_I32_VAL(ONYX_FILE_ERROR_NOT_FOUND);
+        return NULL;
+    }
+
+    *(u64 *) ONYX_PTR(params->data[3].of.i32) = (u64) file.fd;
+    results->data[0] = WASM_I32_VAL(ONYX_FILE_ERROR_NONE);
+    return NULL;
+}
+
+ONYX_DEF(__file_close, (WASM_I64), (WASM_I32)) {
+    i64 fd = params->data[0].of.i64;
+
+    bh_file file = { (bh_file_descriptor) fd };
+    bh_file_error error = bh_file_close(&file);
+    if (error == BH_FILE_ERROR_INVALID) {
+        results->data[0] = WASM_I32_VAL(ONYX_FILE_ERROR_NOT_FOUND);
+        return NULL;
+    }
+
+    results->data[0] = WASM_I32_VAL(ONYX_FILE_ERROR_NONE);
+    return NULL;
+}
+
+ONYX_DEF(__file_exists, (WASM_I32, WASM_I32), (WASM_I32)) {
+    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
+    int   path_len = params->data[1].of.i32;
+
+    char path[512] = {0};
+    path_len = bh_min(path_len, 511);
+    strncpy(path, path_ptr, path_len);
+    path[path_len] = 0;
+
+    results->data[0] = WASM_I32_VAL(bh_file_exists(path));
+    return NULL;
+}
+
+ONYX_DEF(__file_stat, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
+    int   path_len = params->data[1].of.i32;
+
+    char path[512] = {0};
+    path_len = bh_min(path_len, 511);
+    strncpy(path, path_ptr, path_len);
+    path[path_len] = 0;
+
+    results->data[0] = WASM_I32_VAL(bh_file_stat(path, ONYX_PTR(params->data[2].of.i32)));
+    return NULL;
+}
+
+ONYX_DEF(__file_remove, (WASM_I32, WASM_I32), (WASM_I32)) {
+    char *path_ptr = ONYX_PTR(params->data[0].of.i32);
+    int   path_len = params->data[1].of.i32;
+
+    char path[512] = {0};
+    path_len = bh_min(path_len, 511);
+    strncpy(path, path_ptr, path_len);
+    path[path_len] = 0;
+
+    results->data[0] = WASM_I32_VAL(bh_file_remove(path));
+    return NULL;
+}
+
+ONYX_DEF(__file_seek, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
+    i64 fd = params->data[0].of.i64;
+    i32 offset = params->data[1].of.i32;
+    i32 whence = params->data[2].of.i32;
+
+    bh_file file = { (bh_file_descriptor) fd };
+    bh_file_whence bh_whence;
+    switch (whence) {
+        case 0: bh_whence = BH_FILE_WHENCE_BEGIN; break;
+        case 1: bh_whence = BH_FILE_WHENCE_CURRENT; break;
+        case 2: bh_whence = BH_FILE_WHENCE_END; break;
+    }
+
+    i64 new_offset = bh_file_seek(&file, offset, whence);
+    results->data[0] = WASM_I32_VAL((i32) new_offset);
+    return NULL;
+}
+
+ONYX_DEF(__file_tell, (WASM_I64), (WASM_I32)) {
+    i64 fd = params->data[0].of.i64;
+    bh_file file = { (bh_file_descriptor) fd };
+    results->data[0] = WASM_I32_VAL(bh_file_tell(&file));
+    return NULL;
+}
+
+ONYX_DEF(__file_read, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    i64 fd = params->data[0].of.i64;
+    bh_file file = { (bh_file_descriptor) fd };
+
+    i32 curr_pos = bh_file_tell(&file);
+    b32 success = bh_file_read_at(&file,
+            bh_file_tell(&file),
+            ONYX_PTR(params->data[1].of.i32),
+            params->data[2].of.i32,
+            (i64 *) ONYX_PTR(params->data[3].of.i32));
+
+    bh_file_seek_to(&file, curr_pos + *(i32 *) ONYX_PTR(params->data[3].of.i32));
+
+    results->data[0] = WASM_I32_VAL(0);
+    if (!success) results->data[0] = WASM_I32_VAL(2);
+    return NULL;
+}
+
+ONYX_DEF(__file_write, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    i64 fd = params->data[0].of.i64;
+    bh_file file = { (bh_file_descriptor) fd };
+
+    i32 curr_pos = bh_file_tell(&file);
+    b32 success = bh_file_write_at(&file,
+            bh_file_tell(&file),
+            ONYX_PTR(params->data[1].of.i32),
+            params->data[2].of.i32,
+            (i64 *) ONYX_PTR(params->data[3].of.i32));
+
+    bh_file_seek_to(&file, curr_pos + *(i32 *) ONYX_PTR(params->data[3].of.i32));
+
+    results->data[0] = WASM_I32_VAL(0);
+    if (!success) results->data[0] = WASM_I32_VAL(2);
+    return NULL;
+}
+
+ONYX_DEF(__file_flush, (WASM_I64), (WASM_I32)) {
+    i64 fd = params->data[0].of.i64;
+    bh_file file = { (bh_file_descriptor) fd };
+    bh_file_flush(&file);
+    results->data[0] = WASM_I32_VAL(0);
+    return NULL;
+}
+
+ONYX_DEF(__file_size, (WASM_I64), (WASM_I32)) {
+    i64 fd = params->data[0].of.i64;
+    bh_file file = { (bh_file_descriptor) fd };
+    results->data[0] = WASM_I32_VAL(bh_file_size(&file));
+    return NULL;
+}
+
+ONYX_DEF(__file_get_standard, (WASM_I32, WASM_I32), (WASM_I32)) {
+    bh_file_standard standard = (bh_file_standard) params->data[0].of.i32;
+
+    bh_file file;
+    bh_file_error error = bh_file_get_standard(&file, standard);
+    if (error == BH_FILE_ERROR_NONE) {
+        *(u64 *) ONYX_PTR(params->data[1].of.i32) = (u64) file.fd;
+    }
+
+    results->data[0] = WASM_I32_VAL(error == BH_FILE_ERROR_NONE);
+    return NULL;
+}
+
+ONYX_DEF(__file_rename, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    char *old_path_ptr = ONYX_PTR(params->data[0].of.i32);
+    int   old_path_len = params->data[1].of.i32;
+
+    char old_path[512] = {0};
+    old_path_len = bh_min(old_path_len, 511);
+    strncpy(old_path, old_path_ptr, old_path_len);
+    old_path[old_path_len] = 0;
+
+    char *new_path_ptr = ONYX_PTR(params->data[2].of.i32);
+    int   new_path_len = params->data[3].of.i32;
+
+    char new_path[512] = {0};
+    new_path_len = bh_min(new_path_len, 511);
+    strncpy(new_path, new_path_ptr, new_path_len);
+    new_path[new_path_len] = 0;
+
+#ifdef _BH_WINDOWS
+    results->data[0] = WASM_I32_VAL(MoveFileA(old_path, new_path));
+    return NULL;
+#endif
+
+#ifdef _BH_LINUX
+    results->data[0] = WASM_I32_VAL(rename(old_path, new_path) == 0);
+    return NULL;
+#endif
+}
+
diff --git a/runtime/src/ort_net.h b/runtime/src/ort_net.h
new file mode 100644 (file)
index 0000000..9b2e4c5
--- /dev/null
@@ -0,0 +1,363 @@
+
+//
+// Networking
+//
+
+struct onyx_socket_addr {
+    unsigned short family;
+    unsigned short port;
+    unsigned int   addr;
+};
+
+static inline int onyx_socket_domain(int i) {
+    #if defined(_BH_LINUX)
+    switch (i) {    // :EnumDependent
+        case 0: return AF_UNIX;
+        case 1: return AF_INET;
+        case 2: return AF_INET6;
+        default: return -1;
+    }
+    #elif defined(_BH_WINDOWS)
+    return -1;
+    #endif
+}
+
+static inline int onyx_socket_protocol(int i) {
+    #if defined(_BH_LINUX)
+    switch (i) {    // :EnumDependent
+        case 0: return SOCK_STREAM;
+        case 1: return SOCK_DGRAM;
+        default: return -1;
+    }
+    #elif defined(_BH_WINDOWS)
+    return -1;
+    #endif
+}
+
+ONYX_DEF(__net_create_socket, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+
+    #ifdef _BH_LINUX
+    int domain = onyx_socket_domain(params->data[1].of.i32);
+    if (domain == -1) goto bad_settings;
+
+    int type = onyx_socket_protocol(params->data[2].of.i32);
+    if (type == -1) goto bad_settings;
+
+    *((int *) ONYX_PTR(params->data[0].of.i32)) = socket(domain, type, 0);
+
+    results->data[0] = WASM_I32_VAL(0);
+    return NULL;
+    #endif 
+
+    #ifdef _BH_WINDOWS
+    #endif
+
+bad_settings:
+    results->data[0] = WASM_I32_VAL(1); // :EnumDependent
+    return NULL;
+}
+
+ONYX_DEF(__net_close_socket, (WASM_I32), ()) {
+    #ifdef _BH_LINUX
+    shutdown(params->data[0].of.i32, SHUT_RDWR);
+    close(params->data[0].of.i32);
+    #endif
+
+    #ifdef _BH_WINDOWS
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__net_setting, (WASM_I32, WASM_I32, WASM_I32), ()) {
+    #ifdef _BH_LINUX
+    switch (params->data[1].of.i32) {
+        case 1: { // :EnumDependent  Non-Blocking
+            int s = params->data[0].of.i32;
+            int flags = fcntl(s, F_GETFL, 0);
+            if (params->data[2].of.i32) {
+                flags |= O_NONBLOCK;
+            } else {
+                flags &= ~O_NONBLOCK;
+            }
+
+            fcntl(s, F_SETFL, flags);
+            break;
+        }
+
+        case 2: { // :EnumDependent  Broadcast
+            int s = params->data[0].of.i32;
+            setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &params->data[2].of.i32, sizeof(int));
+            break;
+        }
+    }
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__net_bind, (WASM_I32, WASM_I32), (WASM_I32)) {
+
+    #ifdef _BH_LINUX
+    int res = -1;
+
+    struct onyx_socket_addr *oaddr = (void *) ONYX_PTR(params->data[1].of.i32);
+    int family = onyx_socket_domain(oaddr->family);
+    int port   = oaddr->port;
+
+    switch (family) {
+        case AF_INET: {
+            struct sockaddr_in bind_addr;
+            memset(&bind_addr, 0, sizeof(bind_addr));
+
+            bind_addr.sin_family = AF_INET;
+            bind_addr.sin_addr.s_addr = htonl(oaddr->addr);
+            bind_addr.sin_port = htons(port);
+
+            res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
+            break;
+        }
+
+        case AF_INET6: {
+            struct sockaddr_in6 bind_addr;
+            memset(&bind_addr, 0, sizeof(bind_addr));
+
+            bind_addr.sin6_family = AF_INET6;
+            memcpy(&bind_addr.sin6_addr.s6_addr, (void *) &oaddr->addr, 16);
+            bind_addr.sin6_port = htons(port);
+            
+            res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
+            break;
+        }
+
+        case AF_UNIX: {
+            struct sockaddr_un bind_addr;
+            memset(&bind_addr, 0, sizeof(bind_addr));
+
+            bind_addr.sun_family = AF_UNIX;
+            strncpy(&bind_addr.sun_path, (char *) &oaddr->addr, 108);
+            
+            res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
+            break;
+        }
+    }
+
+    results->data[0] = WASM_I32_VAL(res >= 0);
+    #endif
+
+    #ifdef _BH_WINDOWS
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__net_listen, (WASM_I32, WASM_I32), ()) {
+    #ifdef _BH_LINUX
+    listen(params->data[0].of.i32, params->data[1].of.i32);
+    #endif
+
+    #ifdef _BH_WINDOWS
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__net_accept, (WASM_I32, WASM_I32), (WASM_I32)) {
+    #ifdef _BH_LINUX
+    struct sockaddr_in client_addr;
+    int client_len = sizeof(client_addr);
+    memset(&client_addr, 0, client_len);
+
+    int client_socket = accept(params->data[0].of.i32, &client_addr, &client_len);
+
+    struct onyx_socket_addr* out_addr = (struct onyx_socket_addr *) ONYX_PTR(params->data[1].of.i32); 
+    out_addr->family = client_addr.sin_family;
+    out_addr->port   = ntohs(client_addr.sin_port);
+    out_addr->addr   = ntohl(client_addr.sin_addr.s_addr);
+
+    results->data[0] = WASM_I32_VAL(client_socket);
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__net_connect_unix, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    #ifdef _BH_LINUX
+    int   hostlen  = params->data[2].of.i32;
+    char *hostname = alloca(hostlen + 1);
+    memcpy(hostname, ONYX_PTR(params->data[1].of.i32), hostlen);
+    hostname[hostlen] = '\0';
+
+    struct sockaddr_un server_addr;
+    memset(&server_addr, 0, sizeof(server_addr));
+
+    server_addr.sun_family = AF_UNIX; // See comment above
+    memcpy((char *)&server_addr.sun_path, hostname, hostlen);
+
+    int result = connect(params->data[0].of.i32, &server_addr, sizeof(server_addr));
+    if (result == 0) results->data[0] = WASM_I32_VAL(0);
+    else             results->data[0] = WASM_I32_VAL(3); // :EnumDependent
+    #endif
+    
+    return NULL;
+}
+
+ONYX_DEF(__net_connect_ipv4, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    #ifdef _BH_LINUX
+    int   hostlen  = params->data[2].of.i32;
+    char *hostname = alloca(hostlen + 1);
+    memcpy(hostname, ONYX_PTR(params->data[1].of.i32), hostlen);
+    hostname[hostlen] = '\0';
+
+    struct hostent *host;
+    host = gethostbyname(hostname); // TODO: Replace this call, as it is obselete.
+    if (host == NULL) {
+        results->data[0] = WASM_I32_VAL(2);  // :EnumDependent
+        return NULL;
+    }
+
+    struct sockaddr_in server_addr;
+    memset(&server_addr, 0, sizeof(server_addr));
+
+    server_addr.sin_family = AF_INET; // See comment above
+    memcpy((char *)&server_addr.sin_addr.s_addr, (char *)host->h_addr, host->h_length);
+    server_addr.sin_port = htons(params->data[3].of.i32);
+
+    int result = connect(params->data[0].of.i32, &server_addr, sizeof(server_addr));
+    if (result == 0) results->data[0] = WASM_I32_VAL(0);
+    else             results->data[0] = WASM_I32_VAL(3); // :EnumDependent
+
+    return NULL;
+    #endif
+
+    #ifdef _BH_WINDOWS
+    #endif
+}
+
+ONYX_DEF(__net_send, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    #ifdef _BH_LINUX
+    // TODO: The flags at the end should be controllable.
+    int sent = send(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, MSG_NOSIGNAL);
+    results->data[0] = WASM_I32_VAL(sent);
+    #endif
+    
+    return NULL;
+}
+
+ONYX_DEF(__net_sendto, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    #ifdef _BH_LINUX
+    struct sockaddr_in dest_addr;
+    int dest_addr_len = sizeof(dest_addr);
+    memset(&dest_addr, 0, dest_addr_len);
+
+    struct onyx_socket_addr *o_addr = (struct onyx_socket_addr *) ONYX_PTR(params->data[3].of.i32);
+    dest_addr.sin_family = AF_INET; // TODO: See other comments related to AF_NET above.
+    dest_addr.sin_port = htons(o_addr->port);
+    dest_addr.sin_addr.s_addr = htonl(o_addr->addr);
+
+    // TODO: The flags at the end should be controllable.
+    int sent = sendto(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, MSG_NOSIGNAL, &dest_addr, dest_addr_len);
+    results->data[0] = WASM_I32_VAL(sent);
+    #endif
+    
+    return NULL;
+}
+
+ONYX_DEF(__net_recv, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    *(i32 *) ONYX_PTR(params->data[3].of.i32) = 0;
+
+    #ifdef _BH_LINUX
+    // TODO: The flags at the end should be controllable.
+    int received = recv(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, 0);
+    results->data[0] = WASM_I32_VAL(received);
+
+    if (received < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            *(i32 *) ONYX_PTR(params->data[3].of.i32) = 1;
+        }
+    }
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__net_recvfrom, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    *(i32 *) ONYX_PTR(params->data[4].of.i32) = 0;
+
+    #ifdef _BH_LINUX
+    struct onyx_socket_addr *out_addr = (struct onyx_socket_addr *) ONYX_PTR(params->data[3].of.i32);
+
+    struct sockaddr_in client_addr;
+    int socket_len = sizeof(client_addr);
+    memset(&client_addr, 0, socket_len);
+
+    int received = recvfrom(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, 0, &client_addr, &socket_len);
+    out_addr->family = client_addr.sin_family;
+    out_addr->port   = ntohs(client_addr.sin_port);
+    out_addr->addr   = ntohl(client_addr.sin_addr.s_addr);
+
+    results->data[0] = WASM_I32_VAL(received);
+
+    if (received < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            *(i32 *) ONYX_PTR(params->data[3].of.i32) = 1;
+        }
+    }
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__net_poll_recv, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), ()) {
+    #ifdef _BH_LINUX
+    int i, res, cursor;
+    struct pollfd* fds;
+
+    fds = alloca(params->data[1].of.i32 * sizeof(struct pollfd));
+
+    for (i=0; i<params->data[1].of.i32; i++) {
+        fds[i].fd = *(i32 *) ONYX_PTR(params->data[0].of.i32 + 4 * i);
+        fds[i].events = POLLIN;
+        fds[i].revents = 0;
+    }
+
+    res = poll(fds, params->data[1].of.i32, params->data[2].of.i32);
+
+    for (i=0; i<params->data[1].of.i32; i++) {
+        *(i32 *) ONYX_PTR(params->data[3].of.i32 + 4 * i) = 0; // NO_CHANGE
+
+        if (fds[i].revents & POLLIN) {
+            *(i32 *) ONYX_PTR(params->data[3].of.i32 + 4 * i) = 1; // READABLE
+        }
+
+        if ((fds[i].revents & POLLHUP)
+            || (fds[i].revents & POLLNVAL)
+            || (fds[i].revents & POLLERR)) {
+            *(i32 *) ONYX_PTR(params->data[3].of.i32 + 4 * i) = 2; // CLOSED
+        }
+    }
+
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__net_host_to_net_s, (WASM_I32), (WASM_I32)) {
+    results->data[0] = WASM_I32_VAL(htons(params->data[0].of.i32));
+    return NULL;
+}
+
+ONYX_DEF(__net_host_to_net_l, (WASM_I32), (WASM_I32)) {
+    results->data[0] = WASM_I32_VAL(htonl(params->data[0].of.i32));
+    return NULL;
+}
+
+ONYX_DEF(__net_net_to_host_s, (WASM_I32), (WASM_I32)) {
+    results->data[0] = WASM_I32_VAL(ntohs(params->data[0].of.i32));
+    return NULL;
+}
+
+ONYX_DEF(__net_net_to_host_l, (WASM_I32), (WASM_I32)) {
+    results->data[0] = WASM_I32_VAL(ntohl(params->data[0].of.i32));
+    return NULL;
+}
diff --git a/runtime/src/ort_os.h b/runtime/src/ort_os.h
new file mode 100644 (file)
index 0000000..05fbf65
--- /dev/null
@@ -0,0 +1,55 @@
+
+//
+// OS Things
+//
+
+ONYX_DEF(__args_get, (WASM_I32, WASM_I32), ()) {
+    if (runtime->argc == 0 || runtime->argv == NULL) {
+        return NULL;
+    }
+
+    i32 buffer_base = params->data[1].of.i32;
+
+    for (int i=0; i<runtime->argc; i++) {
+        // Should this be strncpy? What would the length be?
+        strcpy(ONYX_PTR(buffer_base), runtime->argv[i]);
+        *(i32 *) ONYX_PTR(params->data[0].of.i32 + i * 4) = buffer_base;
+        buffer_base += strlen(runtime->argv[i]) + 1;
+    }
+
+    return NULL;
+}
+
+ONYX_DEF(__args_sizes_get, (WASM_I32, WASM_I32), ()) {
+    *(i32 *) ONYX_PTR(params->data[0].of.i32) = runtime->argc;
+
+    i32 argv_size = 0;
+    for (int i=0; i<runtime->argc; i++) {
+        argv_size += strlen(runtime->argv[i]) + 1;
+    }
+
+    *(i32 *) ONYX_PTR(params->data[1].of.i32) = argv_size;
+    return NULL;
+}
+
+ONYX_DEF(__exit, (WASM_I32), ()) {
+    exit(params->data[0].of.i32);
+    return NULL;
+}
+
+ONYX_DEF(__sleep, (WASM_I32), ()) {
+    #ifdef _BH_LINUX
+    usleep(params->data[0].of.i32 * 1000);
+    #endif
+
+    #ifdef _BH_WINDOWS
+    Sleep(params->data[0].of.i32);
+    #endif
+    return NULL;
+}
+
+ONYX_DEF(__time, (), (WASM_I64)) {
+    results->data[0] = WASM_I64_VAL(bh_time_curr());
+    return NULL;
+}
+
diff --git a/runtime/src/ort_processes.h b/runtime/src/ort_processes.h
new file mode 100644 (file)
index 0000000..600deca
--- /dev/null
@@ -0,0 +1,348 @@
+
+//
+// PROCESS
+//
+
+#define ONYX_PROCESS_MAGIC_NUMBER 0xdeadfadebabecafe
+typedef struct OnyxProcess {
+    u64 magic_number;
+
+#ifdef _BH_LINUX
+    // Pipes
+    i32 proc_to_host[2];
+    i32 host_to_proc[2];
+
+    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;
+
+ONYX_DEF(__process_spawn, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I64)) {
+    char* process_str = ONYX_PTR(params->data[0].of.i32);
+    i32   process_len = params->data[1].of.i32;
+    i32   args_ptr    = params->data[2].of.i32;
+    i32   args_len    = params->data[3].of.i32;
+    b32   blocking_io = !params->data[4].of.i32;
+    char *cwd_str     = ONYX_PTR(params->data[5].of.i32);
+    i32   cwd_len     = params->data[6].of.i32;
+
+    char process_path[1024];
+    process_len = bh_min(1023, process_len);
+    memcpy(process_path, process_str, process_len);
+    process_path[process_len] = '\0';
+
+    char starting_dir[1024];
+    if (cwd_len > 0) {
+        cwd_len = bh_min(1023, cwd_len);
+        memcpy(starting_dir, cwd_str, cwd_len);
+        starting_dir[cwd_len] = '\0';
+    }
+
+    OnyxProcess *process = malloc(sizeof(OnyxProcess));
+    memset(process, 0, sizeof(*process));
+    process->magic_number = ONYX_PROCESS_MAGIC_NUMBER;
+
+    #ifdef _BH_LINUX
+        // :Security - alloca a user controlled string.
+        char **process_args = alloca(sizeof(char *) * (args_len + 2));
+        byte_t* array_loc = ONYX_PTR(args_ptr);
+        fori (i, 0, args_len) {
+            char *arg_str = ONYX_PTR(*(i32 *) (array_loc + i * 2 * POINTER_SIZE));
+            i32   arg_len = *(i32 *) (array_loc + i * 2 * POINTER_SIZE + POINTER_SIZE);
+
+            char *arg = alloca(sizeof(char) * (arg_len + 1));
+            memcpy(arg, arg_str, arg_len);
+            arg[arg_len] = '\0';
+            process_args[i + 1] = arg;
+        }
+        process_args[0] = process_path;
+        process_args[args_len + 1] = NULL;
+
+        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()) {
+            case -1: // Bad fork
+                wasm_val_init_ptr(&results->data[0], NULL); // Failed to run
+
+                close(process->proc_to_host[0]);
+                close(process->proc_to_host[1]);
+                close(process->host_to_proc[0]);
+                close(process->host_to_proc[1]);
+                break;
+
+            case 0: // Child process
+                close(process->proc_to_host[0]);
+                close(process->host_to_proc[1]);
+                dup2(process->host_to_proc[0], 0); // Map the output to the pipe
+                dup2(process->proc_to_host[1], 1); // Map the output to the pipe
+                dup2(process->proc_to_host[1], 2); // Stderr to stdout
+
+                if (!blocking_io) {
+                    fcntl(0, F_SETFL, O_NONBLOCK);
+                    fcntl(1, F_SETFL, O_NONBLOCK);
+                }
+
+                if (cwd_len > 0) {
+                    chdir(starting_dir); // Switch current working directory.
+                }
+
+                execvp(process_path, process_args);
+                exit(-1);
+                break;
+
+            default: {
+                process->pid = pid;
+                close(process->host_to_proc[0]);
+                close(process->proc_to_host[1]);
+
+                wasm_val_init_ptr(&results->data[0], process);
+                break;
+            }
+        }
+
+    #endif
+
+    #ifdef _BH_WINDOWS
+        // CLEANUP CLEANUP CLEANUP: This is so freaking bad...
+        char cmdLine[2048];
+        memset(cmdLine, 0, 2048);
+        strncat(cmdLine, "\"", 2047);
+        strncat(cmdLine, process_path, 2047);
+        strncat(cmdLine, "\"", 2047);
+
+        byte_t* array_loc = ONYX_PTR(args_ptr);
+        fori (i, 0, args_len) {
+            char *arg_str = ONYX_PTR(*(i32 *) (array_loc + i * 2 * POINTER_SIZE));
+            i32   arg_len = *(i32 *) (array_loc + i * 2 * POINTER_SIZE + 4);
+
+            strncat(cmdLine, " \"", 2047);
+            strncat(cmdLine, arg_str, arg_len);
+            strncat(cmdLine, "\"", 2047);
+        }
+
+        STARTUPINFOA startup;
+        memset(&startup, 0, sizeof startup);
+        startup.cb = sizeof(startup);
+
+        SECURITY_ATTRIBUTES saAttr;
+        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+        saAttr.lpSecurityDescriptor = NULL;
+        saAttr.bInheritHandle = 1;
+
+        i32 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) {
+            // printf("FAILED TO CREATE PIPES: %d\n", GetLastError());
+            wasm_val_init_ptr(&results->data[0], NULL); // Failed to run @LEAK
+            return NULL;
+        }
+
+        success = SetHandleInformation(process->proc_to_host_read, 1 /* HANDLE_FLAG_INHERIT */, 0);
+        success = success && SetHandleInformation(process->host_to_proc_write, 1 /* HANDLE_FLAG_INHERIT */, 0);
+        if (!success) {
+            // printf("FAILED TO CONFIGURE PIPES: %d\n", GetLastError());
+            wasm_val_init_ptr(&results->data[0], NULL); // Failed to run @LEAK
+            return NULL;
+        }
+
+        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;
+
+        memset(&process->proc_info, 0, sizeof process->proc_info);
+
+        char *working_dir = NULL;
+        if (cwd_len > 0) {
+            working_dir = starting_dir;
+        }
+
+        success = CreateProcessA(process_path, cmdLine, &saAttr, &saAttr, 1, 0, NULL, working_dir, &startup, &process->proc_info);
+        if (!success) {
+            printf("FAILED TO CREATE PROCESS: %d\n", GetLastError());
+            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;
+}
+
+ONYX_DEF(__process_read, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
+    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
+    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
+        results->data[0] = WASM_I32_VAL(0);
+        return NULL;
+    }
+
+    i32 output_ptr = params->data[1].of.i32;
+    i32 output_len = params->data[2].of.i32;
+    u8 *buffer = ONYX_PTR(output_ptr);
+
+    i32 bytes_read;
+    #ifdef _BH_LINUX
+        bytes_read = read(process->proc_to_host[0], buffer, output_len);
+        if (bytes_read < 0) {
+            switch (errno) {
+                case EAGAIN: bytes_read =  0; break;
+                case EBADF:  bytes_read = -1; break;
+                default:     bytes_read = -2; break;
+            }
+        }
+    #endif
+
+    #ifdef _BH_WINDOWS
+        i32 success = ReadFile(process->proc_to_host_read, buffer, output_len, &bytes_read, NULL);
+        if (!success) {
+            bytes_read = -1;
+        }
+    #endif
+
+    results->data[0] = WASM_I32_VAL(bytes_read);
+    return NULL;
+}
+
+ONYX_DEF(__process_write, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
+    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
+    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
+        results->data[0] = WASM_I32_VAL(0);
+        return NULL;
+    }
+
+    i32 input_ptr = params->data[1].of.i32;
+    i32 input_len = params->data[2].of.i32;
+    u8 *buffer = ONYX_PTR(input_ptr);
+
+    i32 bytes_written;
+    #ifdef _BH_LINUX
+        bytes_written = write(process->host_to_proc[1], buffer, input_len);
+        bytes_written = bh_max(bytes_written, 0);  // Silently consume errors
+    #endif
+
+    #ifdef _BH_WINDOWS
+        i32 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;
+}
+
+ONYX_DEF(__process_kill, (WASM_I64), (WASM_I32)) {
+    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
+    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
+        results->data[0] = WASM_I32_VAL(0);
+        return NULL;
+    }
+
+    #ifdef _BH_LINUX
+        i32 failed = kill(process->pid, SIGKILL);
+        results->data[0] = WASM_I32_VAL(!failed);
+    #endif
+
+    #ifdef _BH_WINDOWS
+        i32 success = TerminateProcess(process->proc_info.hProcess, 1);
+        results->data[0] = WASM_I32_VAL(success ? 1 : 0);
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__process_wait, (WASM_I64), (WASM_I32)) {
+    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
+    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
+        results->data[0] = WASM_I32_VAL(1);
+        return NULL;
+    }
+
+    #ifdef _BH_LINUX
+        i32 status;
+        waitpid(process->pid, &status, 0);
+
+        i32 exit_code = WEXITSTATUS(status);
+        results->data[0] = WASM_I32_VAL(exit_code != 0 ? 2 : 0);
+    #endif
+
+    #ifdef _BH_WINDOWS
+        DWORD exitCode;
+        while (1) {
+            if (!WaitForSingleObject(process->proc_info.hProcess, INFINITE)) {
+                // HACK HACK HACK
+                DWORD error = GetLastError();
+                if (error != 109 && error != 6) {
+                    // printf("ERROR IN WAIT FOR SINGLE: %d\n", error);
+                    results->data[0] = WASM_I32_VAL(1);
+                    return NULL;
+                }
+            }
+
+            if (!GetExitCodeProcess(process->proc_info.hProcess, &exitCode)) {
+                // HACK HACK HACK
+                // Apparently, I'm doing something wrong (maybe?) where the process handle becomes
+                // invalid and causes error 6 "invalid handle". So I think I can safely assume that
+                // if that is the case, then the process exited? probably successfuly? hopefully?
+                // Honestly I don't know and I can't find any documentation describing when a process
+                // handle goes invalid, other than after you close it explicitly. But in the run_tests
+                // script, I'm not calling either process_kill or process_destroy, which are the only
+                // other functions that close the process handle. So I'm left in the dark as to why this
+                // is happening, but oh well. This works for now.
+                //                                                           - brendanfh 2021/12/03
+                if (GetLastError() == 6) {
+                    exitCode = 0;
+                    break;
+                }
+
+                results->data[0] = WASM_I32_VAL(3);
+                return NULL;
+            }
+
+            // 259 is STILL_ACTIVE (aka STATUS_PENDING), which means that the process has not yet exited
+            if (exitCode != 259) break;
+        }
+
+        results->data[0] = WASM_I32_VAL(exitCode != 0 ? 2 : 0);
+    #endif
+
+    return NULL;
+}
+
+ONYX_DEF(__process_destroy, (WASM_I64), ()) {
+    OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64;
+    if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) {
+        return NULL;
+    }
+
+    #ifdef _BH_LINUX
+        close(process->proc_to_host[0]);
+        close(process->host_to_proc[1]);
+    #endif
+
+    #ifdef _BH_WINDOWS
+        if (!CloseHandle(process->proc_info.hThread)
+         || !CloseHandle(process->proc_info.hProcess)) {
+            // printf("ERROR CLOSING HANDLES: %d\n", GetLastError());
+         }
+    #endif
+
+    free(process);
+
+    return NULL;
+}
diff --git a/runtime/src/ort_threads.h b/runtime/src/ort_threads.h
new file mode 100644 (file)
index 0000000..75cf471
--- /dev/null
@@ -0,0 +1,127 @@
+
+//
+// THREADS
+//
+typedef struct OnyxThread {
+    i32 id;
+    i32 tls_base;
+    i32 funcidx;
+    i32 dataptr;
+    wasm_instance_t* instance;
+
+    #ifdef _BH_LINUX
+        pthread_t thread;
+    #endif
+
+    #ifdef _BH_WINDOWS
+        HANDLE thread_handle;
+        i32    thread_id;
+    #endif
+} OnyxThread;
+
+static bh_arr(OnyxThread) threads = NULL;
+
+#ifdef _BH_LINUX
+static void *onyx_run_thread(void *data) {
+#endif
+#ifdef _BH_WINDOWS
+static i32 onyx_run_thread(void *data) {
+#endif
+    OnyxThread *thread = (OnyxThread *) data;
+
+    wasm_store_t *wasm_store = runtime->wasm_store_new(runtime->wasm_engine);
+
+    wasm_trap_t* traps = NULL;
+    thread->instance = runtime->wasm_instance_new(wasm_store, runtime->wasm_module, &runtime->wasm_imports, &traps);
+
+    wasm_extern_t* start_extern = runtime->wasm_extern_lookup_by_name(runtime->wasm_module, thread->instance, "_thread_start");
+    wasm_func_t*   start_func   = runtime->wasm_extern_as_func(start_extern);
+
+    wasm_extern_t* exit_extern = runtime->wasm_extern_lookup_by_name(runtime->wasm_module, thread->instance, "_thread_exit");
+    wasm_func_t*   exit_func   = runtime->wasm_extern_as_func(exit_extern);
+
+    wasm_trap_t* trap=NULL;
+
+    // NOTE: This is cached in a local variable because there is a tiny chance that if a lot of threads are created
+    // then the backing array for the thread handles will move and thread* we have well not be valid. I'm betting on this
+    // not happening before now in the function; however, it *could* happen before we call thread_exit. This would be bad
+    // because of the normal reasons why accessing memory that you don't own any more is bad.
+    i32 thread_id = thread->id;
+
+    { // Call the _thread_start procedure
+        wasm_val_t args[]    = { WASM_I32_VAL(thread_id), WASM_I32_VAL(thread->tls_base), WASM_I32_VAL(thread->funcidx), WASM_I32_VAL(thread->dataptr) };
+        wasm_val_vec_t results = { 0, 0 };
+        wasm_val_vec_t args_array = WASM_ARRAY_VEC(args);
+
+        trap = runtime->wasm_func_call(start_func, &args_array, &results);
+        if (trap != NULL) {
+            bh_printf("THREAD: %d\n", thread_id);
+            runtime->onyx_print_trap(trap);
+        }
+    }
+
+    { // Call the _thread_exit procedure
+        wasm_val_t args[]    = { WASM_I32_VAL(thread_id) };
+        wasm_val_vec_t results = { 0, 0 };
+        wasm_val_vec_t args_array = WASM_ARRAY_VEC(args);
+
+        trap = runtime->wasm_func_call(exit_func, &args_array, &results);
+    }
+
+    runtime->wasm_store_delete(wasm_store);
+
+    return 0;
+}
+
+ONYX_DEF(__spawn_thread, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    if (threads == NULL) bh_arr_new(bh_heap_allocator(), threads, 128);
+    bh_arr_insert_end(threads, 1);
+    OnyxThread *thread = &bh_arr_last(threads);
+
+    thread->id       = params->data[0].of.i32;
+    thread->tls_base = params->data[1].of.i32;
+    thread->funcidx  = params->data[2].of.i32;
+    thread->dataptr  = params->data[3].of.i32;
+
+    #ifdef _BH_LINUX
+        pthread_create(&thread->thread, NULL, onyx_run_thread, thread);
+    #endif
+
+    #ifdef _BH_WINDOWS
+        // thread->thread_handle = CreateThread(NULL, 0, onyx_run_thread, thread, 0, &thread->thread_id);
+        thread->thread_handle = (HANDLE) _beginthreadex(NULL, 0, onyx_run_thread, thread, 0, &thread->thread_id);
+    #endif
+
+    results->data[0] = WASM_I32_VAL(1);
+    return NULL;
+}
+
+ONYX_DEF(__kill_thread, (WASM_I32), (WASM_I32)) {
+    i32 thread_id = params->data[0].of.i32;
+
+    i32 i = 0;
+    bh_arr_each(OnyxThread, thread, threads) {
+        if (thread->id == thread_id) {
+            #ifdef _BH_LINUX
+            // This leads to some weirdness and bugs...
+            //
+            pthread_kill(thread->thread, SIGKILL);
+            #endif
+
+            #ifdef _BH_WINDOWS
+            TerminateThread(thread->thread_handle, 0);
+            CloseHandle(thread->thread_handle);
+            #endif
+
+            bh_arr_deleten(threads, i, 1);
+            results->data[0] = WASM_I32_VAL(1);
+            return NULL;
+        }
+
+        i++;
+    }
+
+    results->data[0] = WASM_I32_VAL(0);
+    return NULL;
+}
+
diff --git a/runtime/src/ort_time.h b/runtime/src/ort_time.h
new file mode 100644 (file)
index 0000000..998e9f9
--- /dev/null
@@ -0,0 +1,32 @@
+
+//
+// Dates and Times
+//
+ONYX_DEF(__time_localtime, (WASM_I64, WASM_I32), ()) {
+    u64 t = params->data[0].of.i64;
+    *(struct tm *) ONYX_PTR(params->data[1].of.i32) = *localtime(&t);
+    return NULL;
+}
+
+ONYX_DEF(__time_gmtime, (WASM_I64, WASM_I32), ()) {
+    u64 t = params->data[0].of.i64;
+    *(struct tm *) ONYX_PTR(params->data[1].of.i32) = *gmtime(&t);
+    return NULL;
+}
+
+ONYX_DEF(__time_strftime, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    u32 len = strftime(ONYX_PTR(params->data[0].of.i32), params->data[1].of.i32, ONYX_PTR(params->data[2].of.i32), ONYX_PTR(params->data[3].of.i32));
+    results->data[0] = WASM_I32_VAL(len); 
+    return NULL;
+}
+
+ONYX_DEF(__time_strptime, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    #if defined(_BH_LINUX)
+    char *rem = strptime(ONYX_PTR(params->data[0].of.i32), params->data[1].of.i32, ONYX_PTR(params->data[2].of.i32), ONYX_PTR(params->data[3].of.i32));
+    results->data[0] = WASM_I32_VAL(rem != NULL); 
+    #else
+    results->data[0] = WASM_I32_VAL(0);
+    #endif
+    return NULL;
+}
+