added: futexes to platform layer
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 27 Jun 2023 14:31:35 +0000 (09:31 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 27 Jun 2023 14:31:35 +0000 (09:31 -0500)
CHANGELOG
core/runtime/platform/js/platform.onyx
core/runtime/platform/onyx/platform.onyx
core/runtime/platform/wasi/platform.onyx
core/sync/mutex.onyx
core/sync/semaphore.onyx
runtime/onyx_runtime.c
runtime/src/ort_os.h
shared/include/small_windows.h

index 17af67ba5801f061a495555b218d85b9bb57b3bb..baee3acbda98fee55bfd45583530e8afceac162c 100644 (file)
--- 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 <cmd>`
+- Added `--skip-native` flag to `onyx pkg sync` to skip compiling native libraries.
 
 Removals:
 
index fe919cfa8b801aeeb979688c5fee323217cc3c41..e60d205b8776cf62a48dd4b3c1dc779608118256 100644 (file)
@@ -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();
index b413b391fec3330953ebcfcb5ef7d274dc62a70c..70592a9f476e9759c234d77da9bcebf7f1536e61 100644 (file)
@@ -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 ---
index e11ddbe2295f1ba72b768e76ceeff56b2fd5007a..f6fe6716a489ef6bdaaf992ebaf7acc0e7e63c0a 100644 (file)
@@ -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 {
index 6651d3a48001bce0ae7d3b3fc37ebaed6776e485..2c6dfc9bed09c1b8e56c27ca693c155d0ca538de 100644 (file)
@@ -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);
     }
 }
 
index fffbca452f42449eb5a93c2f257662f6ab0d2c1f..100454f7cb38f87660cfab57ce64a6ff990693bf 100644 (file)
@@ -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);
             }
         }
     }
index 7f4b023d241ed9c2b3883f8a737cad8109e25482..9be0bf3d8e911d0ac2860773783d3403123e58ca 100644 (file)
@@ -18,6 +18,8 @@
     #include <netinet/in.h>
     #include <sys/socket.h>
     #include <sys/un.h>
+    #include <linux/futex.h>
+    #include <sys/syscall.h>
     #include <poll.h>
 #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)
index af5292cd21f8a3ed810e94f93f27fd8d643a014f..3e73dc8b0a888205afc3adedea57737c6843a425 100644 (file)
@@ -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, &params->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; i<params->data[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;
index 052e6b1b91c308b66d5ab25dd9c6def13899ce78..f1a0769d77e052904661f24ceb520bda4bd49af2 100644 (file)
@@ -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);
+