From: Brendan Hansen Date: Tue, 6 Sep 2022 02:58:24 +0000 (-0500) Subject: separated onyx runtime parts X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=205b420a9845ae59c355709bbdd8b6d56c624a0d;p=onyx.git separated onyx runtime parts --- diff --git a/runtime/onyx_runtime.c b/runtime/onyx_runtime.c index 88a13553..cdcf83e1 100644 --- a/runtime/onyx_runtime.c +++ b/runtime/onyx_runtime.c @@ -23,1353 +23,15 @@ #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; ihndl = 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) -> 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; iargc; 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; iargc; 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 *) ¶ms->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; idata[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; idata[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 index 00000000..f9d5185d --- /dev/null +++ b/runtime/src/ort_cptr.h @@ -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 index 00000000..3cc8d355 --- /dev/null +++ b/runtime/src/ort_directories.h @@ -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; ihndl = 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) -> 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 index 00000000..de6e3e0b --- /dev/null +++ b/runtime/src/ort_files.h @@ -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 index 00000000..9b2e4c5d --- /dev/null +++ b/runtime/src/ort_net.h @@ -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 *) ¶ms->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; idata[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; idata[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 index 00000000..05fbf652 --- /dev/null +++ b/runtime/src/ort_os.h @@ -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; iargc; 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; iargc; 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 index 00000000..600deca1 --- /dev/null +++ b/runtime/src/ort_processes.h @@ -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 index 00000000..75cf4710 --- /dev/null +++ b/runtime/src/ort_threads.h @@ -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 index 00000000..998e9f91 --- /dev/null +++ b/runtime/src/ort_time.h @@ -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; +} +