From 005460d650737aa902a38fb75c8c4d7068921a75 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sun, 21 Nov 2021 22:31:09 -0600 Subject: [PATCH] added test for availability of wait and notify --- core/intrinsics/atomics.onyx | 6 ++++-- core/sync/mutex.onyx | 21 ++++++++++++++------- core/sync/semaphore.onyx | 12 ++++++++++-- core/threads/thread.onyx | 10 ++++++++-- src/builtins.c | 4 ++++ 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/core/intrinsics/atomics.onyx b/core/intrinsics/atomics.onyx index 542513bd..70d5b01d 100644 --- a/core/intrinsics/atomics.onyx +++ b/core/intrinsics/atomics.onyx @@ -9,8 +9,10 @@ package core.intrinsics.atomics } // __atomic_wait is only valid for i32 and i64 -__atomic_wait :: (addr: ^$T, value: T, timeout: i64 = -1) -> i32 #intrinsic --- -__atomic_notify :: (addr: rawptr, maximum: i32 = 1) -> i32 #intrinsic --- +#if runtime.Wait_Notify_Available { + __atomic_wait :: (addr: ^$T, value: T, timeout: i64 = -1) -> i32 #intrinsic --- + __atomic_notify :: (addr: rawptr, maximum: i32 = 1) -> i32 #intrinsic --- +} __atomic_fence :: () -> void #intrinsic --- diff --git a/core/sync/mutex.onyx b/core/sync/mutex.onyx index 19cc3894..5fb23160 100644 --- a/core/sync/mutex.onyx +++ b/core/sync/mutex.onyx @@ -3,6 +3,8 @@ package core.sync use package core.intrinsics.atomics use package core.thread { Thread_ID } +#local runtime :: package runtime + // `lock` has two states: 0, and 1. // 0 means unlocked // 1 means locked @@ -32,12 +34,14 @@ mutex_lock :: (m: ^Mutex) { while __atomic_cmpxchg(^m.lock, 0, 1) == 1 { if m.owner == context.thread_id do return; - @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.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); + } } } @@ -49,7 +53,10 @@ mutex_unlock :: (m: ^Mutex) { m.owner = -1; __atomic_store(^m.lock, 0); - __atomic_notify(^m.lock, maximum = 1); + + #if runtime.Wait_Notify_Available { + __atomic_notify(^m.lock, maximum = 1); + } } scoped_mutex :: macro (m: ^Mutex) { diff --git a/core/sync/semaphore.onyx b/core/sync/semaphore.onyx index 26f061e1..88de3b24 100644 --- a/core/sync/semaphore.onyx +++ b/core/sync/semaphore.onyx @@ -1,6 +1,7 @@ package core.sync use package core.intrinsics.atomics +#local runtime :: package runtime Semaphore :: struct { mutex : Mutex; @@ -22,7 +23,12 @@ semaphore_post :: (s: ^Semaphore, count := 1) { scoped_mutex(^s.mutex); s.counter += count; - __atomic_notify(^s.counter, maximum = count); + + @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); + } } semaphore_wait :: (s: ^Semaphore) { @@ -37,7 +43,9 @@ semaphore_wait :: (s: ^Semaphore) { } else { mutex_unlock(^s.mutex); - __atomic_wait(^s.counter, 0); + #if runtime.Wait_Notify_Available { + __atomic_wait(^s.counter, 0); + } } } } \ No newline at end of file diff --git a/core/threads/thread.onyx b/core/threads/thread.onyx index 2f1d8b65..632bd1df 100644 --- a/core/threads/thread.onyx +++ b/core/threads/thread.onyx @@ -31,7 +31,11 @@ spawn :: (t: ^Thread, data: rawptr, func: (rawptr) -> void) { } join :: (t: ^Thread) { - while t.alive do __atomic_wait(^t.id, t.id); + while t.alive { + #if runtime.Wait_Notify_Available { + __atomic_wait(^t.id, t.id); + } + } } kill :: (t: ^Thread) -> i32 { @@ -53,7 +57,9 @@ __exited :: (id: i32) { thread := thread_map->get(id); if thread != null { thread.alive = false; - __atomic_notify(^thread.id); + #if runtime.Wait_Notify_Available { + __atomic_notify(^thread.id); + } thread_map->delete(id); } diff --git a/src/builtins.c b/src/builtins.c index 8ddfa417..f86a63fa 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -474,4 +474,8 @@ void introduce_build_options(bh_allocator a) { AstNumLit* multi_threaded = make_int_literal(a, context.options->use_multi_threading); multi_threaded->type_node = (AstType *) &basic_type_bool; symbol_builtin_introduce(p->scope, "Multi_Threading_Enabled", (AstNode *) multi_threaded); + + AstNumLit* wait_notify_available = make_int_literal(a, context.options->use_multi_threading && context.options->runtime == Runtime_Js); + wait_notify_available->type_node = (AstType *) &basic_type_bool; + symbol_builtin_introduce(p->scope, "Wait_Notify_Available", (AstNode *) wait_notify_available); } -- 2.25.1