Reimplement sync2.Sema on windows with WaitOnAddress primitives

This commit is contained in:
gingerBill
2021-04-27 16:56:11 +01:00
parent 24f2d97c0e
commit 96b60d8779
4 changed files with 94 additions and 22 deletions

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}