From: Brendan Hansen Date: Tue, 27 Jun 2023 14:31:35 +0000 (-0500) Subject: added: futexes to platform layer X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=b2d2e8b7bc1844044f1db8c41eb1d3a11d736e00;p=onyx.git added: futexes to platform layer --- diff --git a/CHANGELOG b/CHANGELOG index 17af67ba..baee3acb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,9 @@ Not released Additions: - Added ability to control the size of the tag type for tagged unions. - `union #tag_type u8` +- Infrastructure to have custom sub-commands. + - Any `*.wasm` file in `$ONYX_PATH/tools` is available to run with `onyx ` +- Added `--skip-native` flag to `onyx pkg sync` to skip compiling native libraries. Removals: diff --git a/core/runtime/platform/js/platform.onyx b/core/runtime/platform/js/platform.onyx index fe919cfa..e60d205b 100644 --- a/core/runtime/platform/js/platform.onyx +++ b/core/runtime/platform/js/platform.onyx @@ -19,6 +19,7 @@ Supports_Networking :: false Supports_Type_Info :: true Supports_Threads :: true Supports_Env_Vars :: false +Supports_Futexes :: true __output_string :: (s: str) -> u32 #foreign "host" "print_str" --- __output_error :: (s: str) -> u32 #foreign "host" "print_str" --- @@ -29,6 +30,18 @@ __time :: () -> i64 #foreign "host" "time" --- __read_from_input :: (buf: [] u8) -> u32 do return 0; } +__futex_wait :: (addr: rawptr, expected: i32, timeout: i32) -> i32 { + use core.intrinsics.atomics {__atomic_wait} + if context.thread_id != 0 { + __atomic_wait(addr, expected, ~~timeout); + } +} + +__futex_wake :: (addr: rawptr, maximum: i32) -> i32 { + use core.intrinsics.atomics {__atomic_notify} + __atomic_notify(addr, maximum); +} + // Sets up everything needed for execution. __start :: () { __runtime_initialize(); diff --git a/core/runtime/platform/onyx/platform.onyx b/core/runtime/platform/onyx/platform.onyx index b413b391..70592a9f 100644 --- a/core/runtime/platform/onyx/platform.onyx +++ b/core/runtime/platform/onyx/platform.onyx @@ -27,6 +27,7 @@ Supports_Networking :: true Supports_Type_Info :: true Supports_Threads :: true Supports_Env_Vars :: true +Supports_Futexes :: true #library "onyx_runtime" @@ -65,6 +66,8 @@ ProcessData :: #distinct u64 // OS __exit :: (status: i32) -> void --- __sleep :: (milliseconds: i32) -> void --- + __futex_wait :: (addr: rawptr, expected: i32, timeout: i32) -> i32 --- + __futex_wake :: (addr: rawptr, maximum: i32) -> i32 --- // Time and sleep __time :: () -> u64 --- diff --git a/core/runtime/platform/wasi/platform.onyx b/core/runtime/platform/wasi/platform.onyx index e11ddbe2..f6fe6716 100644 --- a/core/runtime/platform/wasi/platform.onyx +++ b/core/runtime/platform/wasi/platform.onyx @@ -36,6 +36,7 @@ Supports_Networking :: false Supports_Type_Info :: true Supports_Threads :: true Supports_Env_Vars :: true +Supports_Futexes :: false __output_string :: (s: str) -> u32 { diff --git a/core/sync/mutex.onyx b/core/sync/mutex.onyx index 6651d3a4..2c6dfc9b 100644 --- a/core/sync/mutex.onyx +++ b/core/sync/mutex.onyx @@ -54,14 +54,8 @@ mutex_lock :: (m: &Mutex) { while __atomic_cmpxchg(&m.lock, 0, 1) == 1 { if m.owner == context.thread_id do return; - #if runtime.Wait_Notify_Available { - // @ThreadingCleanup // You cannot wait on the main thread in - // a web browser, for kind of obvious reasons. However, this - // makes waiting for a mutex expensive because the only option - // is to do a spin-lock. Ugh. - if context.thread_id != 0 { - __atomic_wait(&m.lock, 1); - } + #if runtime.platform.Supports_Futexes { + runtime.platform.__futex_wait(&m.lock, 1, -1); } else { while (m.lock == 1) --- } @@ -81,8 +75,8 @@ mutex_unlock :: (m: &Mutex) { m.owner = -1; __atomic_store(&m.lock, 0); - #if runtime.Wait_Notify_Available { - __atomic_notify(&m.lock, maximum = 1); + #if runtime.platform.Supports_Futexes { + runtime.platform.__futex_wake(&m.lock, 1); } } diff --git a/core/sync/semaphore.onyx b/core/sync/semaphore.onyx index fffbca45..100454f7 100644 --- a/core/sync/semaphore.onyx +++ b/core/sync/semaphore.onyx @@ -53,8 +53,8 @@ semaphore_post :: (s: &Semaphore, count := 1) { // @Bug // This is susceptible to starvation. Semaphores should have a queue // or something like that. - #if runtime.Wait_Notify_Available { - __atomic_notify(&s.counter, maximum = count); + #if runtime.platform.Supports_Futexes { + runtime.platform.__futex_wake(&s.counter, count); } } @@ -71,8 +71,8 @@ semaphore_wait :: (s: &Semaphore) { } else { mutex_unlock(&s.mutex); - #if runtime.Wait_Notify_Available { - __atomic_wait(&s.counter, 0); + #if runtime.platform.Supports_Futexes { + runtime.platform.__futex_wait(&s.counter, 0, -1); } } } diff --git a/runtime/onyx_runtime.c b/runtime/onyx_runtime.c index 7f4b023d..9be0bf3d 100644 --- a/runtime/onyx_runtime.c +++ b/runtime/onyx_runtime.c @@ -18,6 +18,8 @@ #include #include #include + #include + #include #include #endif @@ -71,6 +73,8 @@ ONYX_LIBRARY { ONYX_FUNC(__time) ONYX_FUNC(__lookup_env) ONYX_FUNC(__random_get) + ONYX_FUNC(__futex_wait) + ONYX_FUNC(__futex_wake) ONYX_FUNC(__register_cleanup) ONYX_FUNC(__net_create_socket) diff --git a/runtime/src/ort_os.h b/runtime/src/ort_os.h index af5292cd..3e73dc8b 100644 --- a/runtime/src/ort_os.h +++ b/runtime/src/ort_os.h @@ -100,6 +100,59 @@ ONYX_DEF(__random_get, (WASM_PTR, WASM_I32), ()) { } +ONYX_DEF(__futex_wait, (WASM_PTR, WASM_I32, WASM_I32), (WASM_I32)) { + int *addr = ONYX_PTR(params->data[0].of.i32); + + #ifdef _BH_LINUX + struct timespec delay; + + struct timespec *t = NULL; + if (params->data[2].of.i32 >= 0) { + delay.tv_sec = params->data[2].of.i32 / 1000; + delay.tv_nsec = params->data[2].of.i32 * 1000000; + t = &delay; + } + + int res = syscall(SYS_futex, addr, FUTEX_WAIT, params->data[1].of.i32, t, NULL, 0); + + if (res == 0) { + if (*addr == params->data[1].of.i32) results->data[0] = WASM_I32_VAL(0); + else results->data[0] = WASM_I32_VAL(1); + } + if (res == -1) { + if (errno == EAGAIN) results->data[0] = WASM_I32_VAL(2); + else results->data[0] = WASM_I32_VAL(1); + } + #endif + + #ifdef _BH_WINDOWS + results->data[0] = WaitOnAddress(addr, ¶ms->data[1].of.i32, 4, params->data[2].of.i32); + #endif + + return NULL; +} + +ONYX_DEF(__futex_wake, (WASM_PTR, WASM_I32), (WASM_I32)) { + int *addr = ONYX_PTR(params->data[0].of.i32); + + #ifdef _BH_LINUX + int res = syscall(SYS_futex, addr, FUTEX_WAKE, params->data[1].of.i32, NULL, NULL, 0); + + results->data[0] = WASM_I32_VAL(res); + #endif + + #ifdef _BH_WINDOWS + for (int i=0; idata[1].of.i32; i++) { + WakeByAddressSingle(addr); + } + + results->data[0] = WASM_I32_VAL(params->data[1].of.i32); + #endif + + return NULL; +} + + #ifdef _BH_LINUX static wasm_func_t *wasm_cleanup_func; diff --git a/shared/include/small_windows.h b/shared/include/small_windows.h index 052e6b1b..f1a0769d 100644 --- a/shared/include/small_windows.h +++ b/shared/include/small_windows.h @@ -463,3 +463,7 @@ GB_DLL_IMPORT int BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE hAlgorithm, unsigned long dwFlags ); + +GB_DLL_IMPORT void WakeByAddressSingle(PVOID Address); +GB_DLL_IMPORT BOOL WaitOnAddress(volatile PVOID Address, PVOID compareAddress, size_t addressSize, DWORD milliseconds); +