}
// __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 ---
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
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);
+ }
}
}
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) {
package core.sync
use package core.intrinsics.atomics
+#local runtime :: package runtime
Semaphore :: struct {
mutex : Mutex;
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) {
} 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
}
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 {
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);
}
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);
}