From 96b60d8779c150842a3e36ffb7b733938dd7a8f6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 27 Apr 2021 16:56:11 +0100 Subject: [PATCH] Reimplement sync2.Sema on windows with WaitOnAddress primitives --- core/sync/sync2/primitives.odin | 25 +++--------------- core/sync/sync2/primitives_atomic.odin | 30 ++++++++++++++++++++++ core/sync/sync2/primitives_pthreads.odin | 29 +++++++++++++++++++++ core/sync/sync2/primitives_windows.odin | 32 ++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 22 deletions(-) diff --git a/core/sync/sync2/primitives.odin b/core/sync/sync2/primitives.odin index dd6688a50..e7c29afc8 100644 --- a/core/sync/sync2/primitives.odin +++ b/core/sync/sync2/primitives.odin @@ -153,33 +153,14 @@ cond_broadcast :: proc(c: ^Cond) { // // A Sema must not be copied after first use Sema :: struct { - // TODO(bill): Is this implementation too lazy? - // Can this be made to work on all OSes without construction and destruction, i.e. Zero is Initialized - - mutex: Mutex, - cond: Cond, - count: int, + impl: _Sema, } sema_wait :: proc(s: ^Sema) { - mutex_lock(&s.mutex); - defer mutex_unlock(&s.mutex); - - for s.count == 0 { - cond_wait(&s.cond, &s.mutex); - } - - s.count -= 1; - if s.count > 0 { - cond_signal(&s.cond); - } + _sema_wait(s); } sema_post :: proc(s: ^Sema, count := 1) { - mutex_lock(&s.mutex); - defer mutex_unlock(&s.mutex); - - s.count += count; - cond_signal(&s.cond); + _sema_post(s, count); } diff --git a/core/sync/sync2/primitives_atomic.odin b/core/sync/sync2/primitives_atomic.odin index 610ab7ee0..0d6b14987 100644 --- a/core/sync/sync2/primitives_atomic.odin +++ b/core/sync/sync2/primitives_atomic.odin @@ -240,5 +240,35 @@ _cond_broadcast :: proc(c: ^Cond) { } } +_Sema :: struct { + mutex: Mutex, + cond: Cond, + count: int, +} + +_sema_wait :: proc(s: ^Sema) { + mutex_lock(&s.impl.mutex); + defer mutex_unlock(&s.impl.mutex); + + for s.impl.count == 0 { + cond_wait(&s.impl.cond, &s.impl.mutex); + } + + s.impl.count -= 1; + if s.impl.count > 0 { + cond_signal(&s.impl.cond); + } +} + +_sema_post :: proc(s: ^Sema, count := 1) { + mutex_lock(&s.impl.mutex); + defer mutex_unlock(&s.impl.mutex); + + s.impl.count += count; + cond_signal(&s.impl.cond); +} + + + } // !ODIN_SYNC_USE_PTHREADS diff --git a/core/sync/sync2/primitives_pthreads.odin b/core/sync/sync2/primitives_pthreads.odin index e85cff7fc..17940c991 100644 --- a/core/sync/sync2/primitives_pthreads.odin +++ b/core/sync/sync2/primitives_pthreads.odin @@ -150,5 +150,34 @@ _cond_broadcast :: proc(c: ^Cond) { assert(err == 0); } +_Sema :: struct { + mutex: Mutex, + cond: Cond, + count: int, +} + +_sema_wait :: proc(s: ^Sema) { + mutex_lock(&s.impl.mutex); + defer mutex_unlock(&s.impl.mutex); + + for s.impl.count == 0 { + cond_wait(&s.impl.cond, &s.impl.mutex); + } + + s.impl.count -= 1; + if s.impl.count > 0 { + cond_signal(&s.impl.cond); + } +} + +_sema_post :: proc(s: ^Sema, count := 1) { + mutex_lock(&s.impl.mutex); + defer mutex_unlock(&s.impl.mutex); + + s.impl.count += count; + cond_signal(&s.impl.cond); +} + + } // ODIN_SYNC_USE_PTHREADS diff --git a/core/sync/sync2/primitives_windows.odin b/core/sync/sync2/primitives_windows.odin index 02b6cd733..0f8bce5ca 100644 --- a/core/sync/sync2/primitives_windows.odin +++ b/core/sync/sync2/primitives_windows.odin @@ -71,3 +71,35 @@ _cond_signal :: proc(c: ^Cond) { _cond_broadcast :: proc(c: ^Cond) { win32.WakeAllConditionVariable(&c.impl.cond); } + + +_Sema :: struct { + count: int, +} + +_sema_wait :: proc(s: ^Sema) { + for { + original_count := s.impl.count; + for original_count == 0 { + win32.WaitOnAddress( + &s.impl.count, + &original_count, + size_of(original_count), + win32.INFINITE, + ); + original_count = s.impl.count; + } + if original_count == atomic_cxchg(&s.impl.count, original_count-1, original_count) { + return; + } + } +} + +_sema_post :: proc(s: ^Sema, count := 1) { + atomic_add(&s.impl.count, count); + if count == 1 { + win32.WakeByAddressSingle(&s.impl.count); + } else { + win32.WakeByAddressAll(&s.impl.count); + } +}