mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Implement sync2.Recursive_Mutex using WaitOnAddress and friends on Windows
This commit is contained in:
@@ -72,52 +72,19 @@ rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
|||||||
//
|
//
|
||||||
// A Recursive_Mutex must not be copied after first use
|
// A Recursive_Mutex must not be copied after first use
|
||||||
Recursive_Mutex :: struct {
|
Recursive_Mutex :: struct {
|
||||||
// TODO(bill): Is this implementation too lazy?
|
impl: _Recursive_Mutex,
|
||||||
// Can this be made to work on all OSes without construction and destruction, i.e. Zero is Initialized
|
|
||||||
// CRITICAL_SECTION would be a perfect candidate for this on Windows but that cannot be "dumb"
|
|
||||||
|
|
||||||
owner: int,
|
|
||||||
recursion: int,
|
|
||||||
mutex: Mutex,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||||
tid := runtime.current_thread_id();
|
_recursive_mutex_lock(m);
|
||||||
if tid != m.owner {
|
|
||||||
mutex_lock(&m.mutex);
|
|
||||||
}
|
|
||||||
// inside the lock
|
|
||||||
m.owner = tid;
|
|
||||||
m.recursion += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
||||||
tid := runtime.current_thread_id();
|
_recursive_mutex_unlock(m);
|
||||||
assert(tid == m.owner);
|
|
||||||
m.recursion -= 1;
|
|
||||||
recursion := m.recursion;
|
|
||||||
if recursion == 0 {
|
|
||||||
m.owner = 0;
|
|
||||||
}
|
|
||||||
if recursion == 0 {
|
|
||||||
mutex_unlock(&m.mutex);
|
|
||||||
}
|
|
||||||
// outside the lock
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
||||||
tid := runtime.current_thread_id();
|
return _recursive_mutex_try_lock(m);
|
||||||
if m.owner == tid {
|
|
||||||
return mutex_try_lock(&m.mutex);
|
|
||||||
}
|
|
||||||
if !mutex_try_lock(&m.mutex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// inside the lock
|
|
||||||
m.owner = tid;
|
|
||||||
m.recursion += 1;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package sync2
|
|||||||
when !#config(ODIN_SYNC_USE_PTHREADS, true) {
|
when !#config(ODIN_SYNC_USE_PTHREADS, true) {
|
||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import "core:runtime"
|
||||||
|
|
||||||
_Mutex_State :: enum i32 {
|
_Mutex_State :: enum i32 {
|
||||||
Unlocked = 0,
|
Unlocked = 0,
|
||||||
@@ -160,6 +161,54 @@ _rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_Recursive_Mutex :: struct {
|
||||||
|
owner: int,
|
||||||
|
recursion: int,
|
||||||
|
mutex: Mutex,
|
||||||
|
}
|
||||||
|
|
||||||
|
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||||
|
tid := runtime.current_thread_id();
|
||||||
|
if tid != m.impl.owner {
|
||||||
|
mutex_lock(&m.impl.mutex);
|
||||||
|
}
|
||||||
|
// inside the lock
|
||||||
|
m.impl.owner = tid;
|
||||||
|
m.impl.recursion += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
||||||
|
tid := runtime.current_thread_id();
|
||||||
|
assert(tid == m.impl.owner);
|
||||||
|
m.impl.recursion -= 1;
|
||||||
|
recursion := m.impl.recursion;
|
||||||
|
if recursion == 0 {
|
||||||
|
m.impl.owner = 0;
|
||||||
|
}
|
||||||
|
if recursion == 0 {
|
||||||
|
mutex_unlock(&m.impl.mutex);
|
||||||
|
}
|
||||||
|
// outside the lock
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
||||||
|
tid := runtime.current_thread_id();
|
||||||
|
if m.impl.owner == tid {
|
||||||
|
return mutex_try_lock(&m.impl.mutex);
|
||||||
|
}
|
||||||
|
if !mutex_try_lock(&m.impl.mutex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// inside the lock
|
||||||
|
m.impl.owner = tid;
|
||||||
|
m.impl.recursion += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Queue_Item :: struct {
|
Queue_Item :: struct {
|
||||||
next: ^Queue_Item,
|
next: ^Queue_Item,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package sync2
|
|||||||
when #config(ODIN_SYNC_USE_PTHREADS, true) {
|
when #config(ODIN_SYNC_USE_PTHREADS, true) {
|
||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import "core:runtime"
|
||||||
import "core:sys/unix"
|
import "core:sys/unix"
|
||||||
|
|
||||||
_Mutex_State :: enum i32 {
|
_Mutex_State :: enum i32 {
|
||||||
@@ -120,6 +121,53 @@ _rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_Recursive_Mutex :: struct {
|
||||||
|
owner: int,
|
||||||
|
recursion: int,
|
||||||
|
mutex: Mutex,
|
||||||
|
}
|
||||||
|
|
||||||
|
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||||
|
tid := runtime.current_thread_id();
|
||||||
|
if tid != m.impl.owner {
|
||||||
|
mutex_lock(&m.impl.mutex);
|
||||||
|
}
|
||||||
|
// inside the lock
|
||||||
|
m.impl.owner = tid;
|
||||||
|
m.impl.recursion += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
||||||
|
tid := runtime.current_thread_id();
|
||||||
|
assert(tid == m.impl.owner);
|
||||||
|
m.impl.recursion -= 1;
|
||||||
|
recursion := m.impl.recursion;
|
||||||
|
if recursion == 0 {
|
||||||
|
m.impl.owner = 0;
|
||||||
|
}
|
||||||
|
if recursion == 0 {
|
||||||
|
mutex_unlock(&m.impl.mutex);
|
||||||
|
}
|
||||||
|
// outside the lock
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
||||||
|
tid := runtime.current_thread_id();
|
||||||
|
if m.impl.owner == tid {
|
||||||
|
return mutex_try_lock(&m.impl.mutex);
|
||||||
|
}
|
||||||
|
if !mutex_try_lock(&m.impl.mutex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// inside the lock
|
||||||
|
m.impl.owner = tid;
|
||||||
|
m.impl.recursion += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_Cond :: struct {
|
_Cond :: struct {
|
||||||
pthread_cond: unix.pthread_cond_t,
|
pthread_cond: unix.pthread_cond_t,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,56 @@ _rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_Recursive_Mutex :: struct {
|
||||||
|
owner: u32,
|
||||||
|
claim_count: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||||
|
tid := win32.GetCurrentThreadId();
|
||||||
|
for {
|
||||||
|
prev_owner := atomic_cxchg_acq(&m.impl.owner, tid, 0);
|
||||||
|
switch prev_owner {
|
||||||
|
case 0, tid:
|
||||||
|
m.impl.claim_count += 1;
|
||||||
|
// inside the lock
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
win32.WaitOnAddress(
|
||||||
|
&m.impl.owner,
|
||||||
|
&prev_owner,
|
||||||
|
size_of(prev_owner),
|
||||||
|
win32.INFINITE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
||||||
|
m.impl.claim_count -= 1;
|
||||||
|
if m.impl.claim_count != 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
atomic_xchg_rel(&m.impl.owner, 0);
|
||||||
|
win32.WakeByAddressSingle(&m.impl.owner);
|
||||||
|
// outside the lock
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
||||||
|
tid := win32.GetCurrentThreadId();
|
||||||
|
prev_owner := atomic_cxchg_acq(&m.impl.owner, tid, 0);
|
||||||
|
switch prev_owner {
|
||||||
|
case 0, tid:
|
||||||
|
m.impl.claim_count += 1;
|
||||||
|
// inside the lock
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_Cond :: struct {
|
_Cond :: struct {
|
||||||
cond: win32.CONDITION_VARIABLE,
|
cond: win32.CONDITION_VARIABLE,
|
||||||
|
|||||||
Reference in New Issue
Block a user