mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-01 12:18:15 +00:00
Remove unneeded semicolons from the core library
This commit is contained in:
@@ -16,10 +16,10 @@ strongest_failure_ordering_table := [Ordering]Ordering{
|
||||
.Acquire = .Acquire,
|
||||
.Acquire_Release = .Acquire,
|
||||
.Sequentially_Consistent = .Sequentially_Consistent,
|
||||
};
|
||||
}
|
||||
|
||||
strongest_failure_ordering :: #force_inline proc(order: Ordering) -> Ordering {
|
||||
return strongest_failure_ordering_table[order];
|
||||
return strongest_failure_ordering_table[order]
|
||||
}
|
||||
|
||||
fence :: #force_inline proc($order: Ordering) {
|
||||
@@ -80,7 +80,7 @@ atomic_compare_exchange :: #force_inline proc(dst: ^$T, old, new: T, $success, $
|
||||
when success == .Acquire { return instrinsics.atomic_cxchg_failacq(dst, old, new); }
|
||||
else { #panic("an unknown ordering combination"); }
|
||||
} else {
|
||||
return T{}, false;
|
||||
return T{}, false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -106,7 +106,7 @@ atomic_compare_exchange_weak :: #force_inline proc(dst: ^$T, old, new: T, $succe
|
||||
when success == .Acquire { return intrinsics.atomic_cxchgweak_failacq(dst, old, new); }
|
||||
else { #panic("an unknown ordering combination"); }
|
||||
} else {
|
||||
return T{}, false;
|
||||
return T{}, false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
-17
@@ -48,34 +48,34 @@ Barrier :: struct {
|
||||
}
|
||||
|
||||
barrier_init :: proc(b: ^Barrier, thread_count: int) {
|
||||
blocking_mutex_init(&b.mutex);
|
||||
condition_init(&b.cond, &b.mutex);
|
||||
b.index = 0;
|
||||
b.generation_id = 0;
|
||||
b.thread_count = thread_count;
|
||||
blocking_mutex_init(&b.mutex)
|
||||
condition_init(&b.cond, &b.mutex)
|
||||
b.index = 0
|
||||
b.generation_id = 0
|
||||
b.thread_count = thread_count
|
||||
}
|
||||
|
||||
barrier_destroy :: proc(b: ^Barrier) {
|
||||
blocking_mutex_destroy(&b.mutex);
|
||||
condition_destroy(&b.cond);
|
||||
blocking_mutex_destroy(&b.mutex)
|
||||
condition_destroy(&b.cond)
|
||||
}
|
||||
|
||||
// Block the current thread until all threads have rendezvoused
|
||||
// Barrier can be reused after all threads rendezvoused once, and can be used continuously
|
||||
barrier_wait :: proc(b: ^Barrier) -> (is_leader: bool) {
|
||||
blocking_mutex_lock(&b.mutex);
|
||||
defer blocking_mutex_unlock(&b.mutex);
|
||||
local_gen := b.generation_id;
|
||||
b.index += 1;
|
||||
blocking_mutex_lock(&b.mutex)
|
||||
defer blocking_mutex_unlock(&b.mutex)
|
||||
local_gen := b.generation_id
|
||||
b.index += 1
|
||||
if b.index < b.thread_count {
|
||||
for local_gen == b.generation_id && b.index < b.thread_count {
|
||||
condition_wait_for(&b.cond);
|
||||
condition_wait_for(&b.cond)
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
b.index = 0;
|
||||
b.generation_id += 1;
|
||||
condition_broadcast(&b.cond);
|
||||
return true;
|
||||
b.index = 0
|
||||
b.generation_id += 1
|
||||
condition_broadcast(&b.cond)
|
||||
return true
|
||||
}
|
||||
|
||||
+363
-363
File diff suppressed because it is too large
Load Diff
@@ -5,29 +5,29 @@ import win32 "core:sys/windows"
|
||||
import "core:time"
|
||||
|
||||
raw_channel_wait_queue_wait_on :: proc(state: ^uintptr, timeout: time.Duration) {
|
||||
ms: win32.DWORD = win32.INFINITE;
|
||||
ms: win32.DWORD = win32.INFINITE
|
||||
if max(time.Duration) != SELECT_MAX_TIMEOUT {
|
||||
ms = win32.DWORD((max(time.duration_nanoseconds(timeout), 0) + 999999)/1000000);
|
||||
ms = win32.DWORD((max(time.duration_nanoseconds(timeout), 0) + 999999)/1000000)
|
||||
}
|
||||
|
||||
v := intrinsics.atomic_load(state);
|
||||
v := intrinsics.atomic_load(state)
|
||||
for v == 0 {
|
||||
win32.WaitOnAddress(state, &v, size_of(state^), ms);
|
||||
v = intrinsics.atomic_load(state);
|
||||
win32.WaitOnAddress(state, &v, size_of(state^), ms)
|
||||
v = intrinsics.atomic_load(state)
|
||||
}
|
||||
intrinsics.atomic_store(state, 0);
|
||||
intrinsics.atomic_store(state, 0)
|
||||
}
|
||||
|
||||
raw_channel_wait_queue_signal :: proc(q: ^Raw_Channel_Wait_Queue) {
|
||||
for x := q; x != nil; x = x.next {
|
||||
intrinsics.atomic_add(x.state, 1);
|
||||
win32.WakeByAddressSingle(x.state);
|
||||
intrinsics.atomic_add(x.state, 1)
|
||||
win32.WakeByAddressSingle(x.state)
|
||||
}
|
||||
}
|
||||
|
||||
raw_channel_wait_queue_broadcast :: proc(q: ^Raw_Channel_Wait_Queue) {
|
||||
for x := q; x != nil; x = x.next {
|
||||
intrinsics.atomic_add(x.state, 1);
|
||||
win32.WakeByAddressAll(x.state);
|
||||
intrinsics.atomic_add(x.state, 1)
|
||||
win32.WakeByAddressAll(x.state)
|
||||
}
|
||||
}
|
||||
|
||||
+34
-34
@@ -3,10 +3,10 @@ package sync
|
||||
import "core:intrinsics"
|
||||
|
||||
cpu_relax :: #force_inline proc "contextless" () {
|
||||
intrinsics.cpu_relax();
|
||||
intrinsics.cpu_relax()
|
||||
}
|
||||
|
||||
Condition_Mutex_Ptr :: union{^Mutex, ^Blocking_Mutex};
|
||||
Condition_Mutex_Ptr :: union{^Mutex, ^Blocking_Mutex}
|
||||
|
||||
|
||||
Ticket_Mutex :: struct {
|
||||
@@ -15,19 +15,19 @@ Ticket_Mutex :: struct {
|
||||
}
|
||||
|
||||
ticket_mutex_init :: proc(m: ^Ticket_Mutex) {
|
||||
atomic_store(&m.ticket, 0, .Relaxed);
|
||||
atomic_store(&m.serving, 0, .Relaxed);
|
||||
atomic_store(&m.ticket, 0, .Relaxed)
|
||||
atomic_store(&m.serving, 0, .Relaxed)
|
||||
}
|
||||
|
||||
ticket_mutex_lock :: #force_inline proc(m: ^Ticket_Mutex) {
|
||||
ticket := atomic_add(&m.ticket, 1, .Relaxed);
|
||||
ticket := atomic_add(&m.ticket, 1, .Relaxed)
|
||||
for ticket != atomic_load(&m.serving, .Acquire) {
|
||||
intrinsics.cpu_relax();
|
||||
intrinsics.cpu_relax()
|
||||
}
|
||||
}
|
||||
|
||||
ticket_mutex_unlock :: #force_inline proc(m: ^Ticket_Mutex) {
|
||||
atomic_add(&m.serving, 1, .Relaxed);
|
||||
atomic_add(&m.serving, 1, .Relaxed)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,28 +37,28 @@ Benaphore :: struct {
|
||||
}
|
||||
|
||||
benaphore_init :: proc(b: ^Benaphore) {
|
||||
intrinsics.atomic_store(&b.counter, 0);
|
||||
semaphore_init(&b.sema);
|
||||
intrinsics.atomic_store(&b.counter, 0)
|
||||
semaphore_init(&b.sema)
|
||||
}
|
||||
|
||||
benaphore_destroy :: proc(b: ^Benaphore) {
|
||||
semaphore_destroy(&b.sema);
|
||||
semaphore_destroy(&b.sema)
|
||||
}
|
||||
|
||||
benaphore_lock :: proc(b: ^Benaphore) {
|
||||
if intrinsics.atomic_add_acq(&b.counter, 1) > 1 {
|
||||
semaphore_wait_for(&b.sema);
|
||||
semaphore_wait_for(&b.sema)
|
||||
}
|
||||
}
|
||||
|
||||
benaphore_try_lock :: proc(b: ^Benaphore) -> bool {
|
||||
v, _ := intrinsics.atomic_cxchg_acq(&b.counter, 1, 0);
|
||||
return v == 0;
|
||||
v, _ := intrinsics.atomic_cxchg_acq(&b.counter, 1, 0)
|
||||
return v == 0
|
||||
}
|
||||
|
||||
benaphore_unlock :: proc(b: ^Benaphore) {
|
||||
if intrinsics.atomic_sub_rel(&b.counter, 1) > 0 {
|
||||
semaphore_post(&b.sema);
|
||||
semaphore_post(&b.sema)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,53 +70,53 @@ Recursive_Benaphore :: struct {
|
||||
}
|
||||
|
||||
recursive_benaphore_init :: proc(b: ^Recursive_Benaphore) {
|
||||
intrinsics.atomic_store(&b.counter, 0);
|
||||
semaphore_init(&b.sema);
|
||||
intrinsics.atomic_store(&b.counter, 0)
|
||||
semaphore_init(&b.sema)
|
||||
}
|
||||
|
||||
recursive_benaphore_destroy :: proc(b: ^Recursive_Benaphore) {
|
||||
semaphore_destroy(&b.sema);
|
||||
semaphore_destroy(&b.sema)
|
||||
}
|
||||
|
||||
recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
|
||||
tid := current_thread_id();
|
||||
tid := current_thread_id()
|
||||
if intrinsics.atomic_add_acq(&b.counter, 1) > 1 {
|
||||
if tid != b.owner {
|
||||
semaphore_wait_for(&b.sema);
|
||||
semaphore_wait_for(&b.sema)
|
||||
}
|
||||
}
|
||||
// inside the lock
|
||||
b.owner = tid;
|
||||
b.recursion += 1;
|
||||
b.owner = tid
|
||||
b.recursion += 1
|
||||
}
|
||||
|
||||
recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
|
||||
tid := current_thread_id();
|
||||
tid := current_thread_id()
|
||||
if b.owner == tid {
|
||||
intrinsics.atomic_add_acq(&b.counter, 1);
|
||||
intrinsics.atomic_add_acq(&b.counter, 1)
|
||||
} else {
|
||||
v, _ := intrinsics.atomic_cxchg_acq(&b.counter, 1, 0);
|
||||
v, _ := intrinsics.atomic_cxchg_acq(&b.counter, 1, 0)
|
||||
if v != 0 {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
// inside the lock
|
||||
b.owner = tid;
|
||||
b.owner = tid
|
||||
}
|
||||
b.recursion += 1;
|
||||
return true;
|
||||
b.recursion += 1
|
||||
return true
|
||||
}
|
||||
|
||||
recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
|
||||
tid := current_thread_id();
|
||||
assert(tid == b.owner);
|
||||
b.recursion -= 1;
|
||||
recursion := b.recursion;
|
||||
tid := current_thread_id()
|
||||
assert(tid == b.owner)
|
||||
b.recursion -= 1
|
||||
recursion := b.recursion
|
||||
if recursion == 0 {
|
||||
b.owner = 0;
|
||||
b.owner = 0
|
||||
}
|
||||
if intrinsics.atomic_sub_rel(&b.counter, 1) > 0 {
|
||||
if recursion == 0 {
|
||||
semaphore_post(&b.sema);
|
||||
semaphore_post(&b.sema)
|
||||
}
|
||||
}
|
||||
// outside the lock
|
||||
|
||||
+66
-66
@@ -2,78 +2,78 @@ package sync2
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
cpu_relax :: intrinsics.cpu_relax;
|
||||
cpu_relax :: intrinsics.cpu_relax
|
||||
|
||||
atomic_fence :: intrinsics.atomic_fence;
|
||||
atomic_fence_acquire :: intrinsics.atomic_fence_acq;
|
||||
atomic_fence_release :: intrinsics.atomic_fence_rel;
|
||||
atomic_fence_acqrel :: intrinsics.atomic_fence_acqrel;
|
||||
atomic_fence :: intrinsics.atomic_fence
|
||||
atomic_fence_acquire :: intrinsics.atomic_fence_acq
|
||||
atomic_fence_release :: intrinsics.atomic_fence_rel
|
||||
atomic_fence_acqrel :: intrinsics.atomic_fence_acqrel
|
||||
|
||||
atomic_store :: intrinsics.atomic_store;
|
||||
atomic_store_release :: intrinsics.atomic_store_rel;
|
||||
atomic_store_relaxed :: intrinsics.atomic_store_relaxed;
|
||||
atomic_store_unordered :: intrinsics.atomic_store_unordered;
|
||||
atomic_store :: intrinsics.atomic_store
|
||||
atomic_store_release :: intrinsics.atomic_store_rel
|
||||
atomic_store_relaxed :: intrinsics.atomic_store_relaxed
|
||||
atomic_store_unordered :: intrinsics.atomic_store_unordered
|
||||
|
||||
atomic_load :: intrinsics.atomic_load;
|
||||
atomic_load_acquire :: intrinsics.atomic_load_acq;
|
||||
atomic_load_relaxed :: intrinsics.atomic_load_relaxed;
|
||||
atomic_load_unordered :: intrinsics.atomic_load_unordered;
|
||||
atomic_load :: intrinsics.atomic_load
|
||||
atomic_load_acquire :: intrinsics.atomic_load_acq
|
||||
atomic_load_relaxed :: intrinsics.atomic_load_relaxed
|
||||
atomic_load_unordered :: intrinsics.atomic_load_unordered
|
||||
|
||||
atomic_add :: intrinsics.atomic_add;
|
||||
atomic_add_acquire :: intrinsics.atomic_add_acq;
|
||||
atomic_add_release :: intrinsics.atomic_add_rel;
|
||||
atomic_add_acqrel :: intrinsics.atomic_add_acqrel;
|
||||
atomic_add_relaxed :: intrinsics.atomic_add_relaxed;
|
||||
atomic_sub :: intrinsics.atomic_sub;
|
||||
atomic_sub_acquire :: intrinsics.atomic_sub_acq;
|
||||
atomic_sub_release :: intrinsics.atomic_sub_rel;
|
||||
atomic_sub_acqrel :: intrinsics.atomic_sub_acqrel;
|
||||
atomic_sub_relaxed :: intrinsics.atomic_sub_relaxed;
|
||||
atomic_and :: intrinsics.atomic_and;
|
||||
atomic_and_acquire :: intrinsics.atomic_and_acq;
|
||||
atomic_and_release :: intrinsics.atomic_and_rel;
|
||||
atomic_and_acqrel :: intrinsics.atomic_and_acqrel;
|
||||
atomic_and_relaxed :: intrinsics.atomic_and_relaxed;
|
||||
atomic_nand :: intrinsics.atomic_nand;
|
||||
atomic_nand_acquire :: intrinsics.atomic_nand_acq;
|
||||
atomic_nand_release :: intrinsics.atomic_nand_rel;
|
||||
atomic_nand_acqrel :: intrinsics.atomic_nand_acqrel;
|
||||
atomic_nand_relaxed :: intrinsics.atomic_nand_relaxed;
|
||||
atomic_or :: intrinsics.atomic_or;
|
||||
atomic_or_acquire :: intrinsics.atomic_or_acq;
|
||||
atomic_or_release :: intrinsics.atomic_or_rel;
|
||||
atomic_or_acqrel :: intrinsics.atomic_or_acqrel;
|
||||
atomic_or_relaxed :: intrinsics.atomic_or_relaxed;
|
||||
atomic_xor :: intrinsics.atomic_xor;
|
||||
atomic_xor_acquire :: intrinsics.atomic_xor_acq;
|
||||
atomic_xor_release :: intrinsics.atomic_xor_rel;
|
||||
atomic_xor_acqrel :: intrinsics.atomic_xor_acqrel;
|
||||
atomic_xor_relaxed :: intrinsics.atomic_xor_relaxed;
|
||||
atomic_add :: intrinsics.atomic_add
|
||||
atomic_add_acquire :: intrinsics.atomic_add_acq
|
||||
atomic_add_release :: intrinsics.atomic_add_rel
|
||||
atomic_add_acqrel :: intrinsics.atomic_add_acqrel
|
||||
atomic_add_relaxed :: intrinsics.atomic_add_relaxed
|
||||
atomic_sub :: intrinsics.atomic_sub
|
||||
atomic_sub_acquire :: intrinsics.atomic_sub_acq
|
||||
atomic_sub_release :: intrinsics.atomic_sub_rel
|
||||
atomic_sub_acqrel :: intrinsics.atomic_sub_acqrel
|
||||
atomic_sub_relaxed :: intrinsics.atomic_sub_relaxed
|
||||
atomic_and :: intrinsics.atomic_and
|
||||
atomic_and_acquire :: intrinsics.atomic_and_acq
|
||||
atomic_and_release :: intrinsics.atomic_and_rel
|
||||
atomic_and_acqrel :: intrinsics.atomic_and_acqrel
|
||||
atomic_and_relaxed :: intrinsics.atomic_and_relaxed
|
||||
atomic_nand :: intrinsics.atomic_nand
|
||||
atomic_nand_acquire :: intrinsics.atomic_nand_acq
|
||||
atomic_nand_release :: intrinsics.atomic_nand_rel
|
||||
atomic_nand_acqrel :: intrinsics.atomic_nand_acqrel
|
||||
atomic_nand_relaxed :: intrinsics.atomic_nand_relaxed
|
||||
atomic_or :: intrinsics.atomic_or
|
||||
atomic_or_acquire :: intrinsics.atomic_or_acq
|
||||
atomic_or_release :: intrinsics.atomic_or_rel
|
||||
atomic_or_acqrel :: intrinsics.atomic_or_acqrel
|
||||
atomic_or_relaxed :: intrinsics.atomic_or_relaxed
|
||||
atomic_xor :: intrinsics.atomic_xor
|
||||
atomic_xor_acquire :: intrinsics.atomic_xor_acq
|
||||
atomic_xor_release :: intrinsics.atomic_xor_rel
|
||||
atomic_xor_acqrel :: intrinsics.atomic_xor_acqrel
|
||||
atomic_xor_relaxed :: intrinsics.atomic_xor_relaxed
|
||||
|
||||
atomic_exchange :: intrinsics.atomic_xchg;
|
||||
atomic_exchange_acquire :: intrinsics.atomic_xchg_acq;
|
||||
atomic_exchange_release :: intrinsics.atomic_xchg_rel;
|
||||
atomic_exchange_acqrel :: intrinsics.atomic_xchg_acqrel;
|
||||
atomic_exchange_relaxed :: intrinsics.atomic_xchg_relaxed;
|
||||
atomic_exchange :: intrinsics.atomic_xchg
|
||||
atomic_exchange_acquire :: intrinsics.atomic_xchg_acq
|
||||
atomic_exchange_release :: intrinsics.atomic_xchg_rel
|
||||
atomic_exchange_acqrel :: intrinsics.atomic_xchg_acqrel
|
||||
atomic_exchange_relaxed :: intrinsics.atomic_xchg_relaxed
|
||||
|
||||
// Returns value and optional ok boolean
|
||||
atomic_compare_exchange_strong :: intrinsics.atomic_cxchg;
|
||||
atomic_compare_exchange_strong_acquire :: intrinsics.atomic_cxchg_acq;
|
||||
atomic_compare_exchange_strong_release :: intrinsics.atomic_cxchg_rel;
|
||||
atomic_compare_exchange_strong_acqrel :: intrinsics.atomic_cxchg_acqrel;
|
||||
atomic_compare_exchange_strong_relaxed :: intrinsics.atomic_cxchg_relaxed;
|
||||
atomic_compare_exchange_strong_failrelaxed :: intrinsics.atomic_cxchg_failrelaxed;
|
||||
atomic_compare_exchange_strong_failacquire :: intrinsics.atomic_cxchg_failacq;
|
||||
atomic_compare_exchange_strong_acquire_failrelaxed :: intrinsics.atomic_cxchg_acq_failrelaxed;
|
||||
atomic_compare_exchange_strong_acqrel_failrelaxed :: intrinsics.atomic_cxchg_acqrel_failrelaxed;
|
||||
atomic_compare_exchange_strong :: intrinsics.atomic_cxchg
|
||||
atomic_compare_exchange_strong_acquire :: intrinsics.atomic_cxchg_acq
|
||||
atomic_compare_exchange_strong_release :: intrinsics.atomic_cxchg_rel
|
||||
atomic_compare_exchange_strong_acqrel :: intrinsics.atomic_cxchg_acqrel
|
||||
atomic_compare_exchange_strong_relaxed :: intrinsics.atomic_cxchg_relaxed
|
||||
atomic_compare_exchange_strong_failrelaxed :: intrinsics.atomic_cxchg_failrelaxed
|
||||
atomic_compare_exchange_strong_failacquire :: intrinsics.atomic_cxchg_failacq
|
||||
atomic_compare_exchange_strong_acquire_failrelaxed :: intrinsics.atomic_cxchg_acq_failrelaxed
|
||||
atomic_compare_exchange_strong_acqrel_failrelaxed :: intrinsics.atomic_cxchg_acqrel_failrelaxed
|
||||
|
||||
// Returns value and optional ok boolean
|
||||
atomic_compare_exchange_weak :: intrinsics.atomic_cxchgweak;
|
||||
atomic_compare_exchange_weak_acquire :: intrinsics.atomic_cxchgweak_acq;
|
||||
atomic_compare_exchange_weak_release :: intrinsics.atomic_cxchgweak_rel;
|
||||
atomic_compare_exchange_weak_acqrel :: intrinsics.atomic_cxchgweak_acqrel;
|
||||
atomic_compare_exchange_weak_relaxed :: intrinsics.atomic_cxchgweak_relaxed;
|
||||
atomic_compare_exchange_weak_failrelaxed :: intrinsics.atomic_cxchgweak_failrelaxed;
|
||||
atomic_compare_exchange_weak_failacquire :: intrinsics.atomic_cxchgweak_failacq;
|
||||
atomic_compare_exchange_weak_acquire_failrelaxed :: intrinsics.atomic_cxchgweak_acq_failrelaxed;
|
||||
atomic_compare_exchange_weak_acqrel_failrelaxed :: intrinsics.atomic_cxchgweak_acqrel_failrelaxed;
|
||||
atomic_compare_exchange_weak :: intrinsics.atomic_cxchgweak
|
||||
atomic_compare_exchange_weak_acquire :: intrinsics.atomic_cxchgweak_acq
|
||||
atomic_compare_exchange_weak_release :: intrinsics.atomic_cxchgweak_rel
|
||||
atomic_compare_exchange_weak_acqrel :: intrinsics.atomic_cxchgweak_acqrel
|
||||
atomic_compare_exchange_weak_relaxed :: intrinsics.atomic_cxchgweak_relaxed
|
||||
atomic_compare_exchange_weak_failrelaxed :: intrinsics.atomic_cxchgweak_failrelaxed
|
||||
atomic_compare_exchange_weak_failacquire :: intrinsics.atomic_cxchgweak_failacq
|
||||
atomic_compare_exchange_weak_acquire_failrelaxed :: intrinsics.atomic_cxchgweak_acq_failrelaxed
|
||||
atomic_compare_exchange_weak_acqrel_failrelaxed :: intrinsics.atomic_cxchgweak_acqrel_failrelaxed
|
||||
|
||||
@@ -11,36 +11,36 @@ Wait_Group :: struct {
|
||||
|
||||
wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
|
||||
if delta == 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
mutex_lock(&wg.mutex);
|
||||
defer mutex_unlock(&wg.mutex);
|
||||
mutex_lock(&wg.mutex)
|
||||
defer mutex_unlock(&wg.mutex)
|
||||
|
||||
atomic_add(&wg.counter, delta);
|
||||
atomic_add(&wg.counter, delta)
|
||||
if wg.counter < 0 {
|
||||
panic("sync.Wait_Group negative counter");
|
||||
panic("sync.Wait_Group negative counter")
|
||||
}
|
||||
if wg.counter == 0 {
|
||||
cond_broadcast(&wg.cond);
|
||||
cond_broadcast(&wg.cond)
|
||||
if wg.counter != 0 {
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait");
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wait_group_done :: proc(wg: ^Wait_Group) {
|
||||
wait_group_add(wg, -1);
|
||||
wait_group_add(wg, -1)
|
||||
}
|
||||
|
||||
wait_group_wait :: proc(wg: ^Wait_Group) {
|
||||
mutex_lock(&wg.mutex);
|
||||
defer mutex_unlock(&wg.mutex);
|
||||
mutex_lock(&wg.mutex)
|
||||
defer mutex_unlock(&wg.mutex)
|
||||
|
||||
if wg.counter != 0 {
|
||||
cond_wait(&wg.cond, &wg.mutex);
|
||||
cond_wait(&wg.cond, &wg.mutex)
|
||||
if wg.counter != 0 {
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait");
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,29 +94,29 @@ Barrier :: struct {
|
||||
}
|
||||
|
||||
barrier_init :: proc(b: ^Barrier, thread_count: int) {
|
||||
b.index = 0;
|
||||
b.generation_id = 0;
|
||||
b.thread_count = thread_count;
|
||||
b.index = 0
|
||||
b.generation_id = 0
|
||||
b.thread_count = thread_count
|
||||
}
|
||||
|
||||
// Block the current thread until all threads have rendezvoused
|
||||
// Barrier can be reused after all threads rendezvoused once, and can be used continuously
|
||||
barrier_wait :: proc(b: ^Barrier) -> (is_leader: bool) {
|
||||
mutex_lock(&b.mutex);
|
||||
defer mutex_unlock(&b.mutex);
|
||||
local_gen := b.generation_id;
|
||||
b.index += 1;
|
||||
mutex_lock(&b.mutex)
|
||||
defer mutex_unlock(&b.mutex)
|
||||
local_gen := b.generation_id
|
||||
b.index += 1
|
||||
if b.index < b.thread_count {
|
||||
for local_gen == b.generation_id && b.index < b.thread_count {
|
||||
cond_wait(&b.cond, &b.mutex);
|
||||
cond_wait(&b.cond, &b.mutex)
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
b.index = 0;
|
||||
b.generation_id += 1;
|
||||
cond_broadcast(&b.cond);
|
||||
return true;
|
||||
b.index = 0
|
||||
b.generation_id += 1
|
||||
cond_broadcast(&b.cond)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -129,23 +129,23 @@ Auto_Reset_Event :: struct {
|
||||
}
|
||||
|
||||
auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) {
|
||||
old_status := atomic_load_relaxed(&e.status);
|
||||
old_status := atomic_load_relaxed(&e.status)
|
||||
for {
|
||||
new_status := old_status + 1 if old_status < 1 else 1;
|
||||
new_status := old_status + 1 if old_status < 1 else 1
|
||||
if _, ok := atomic_compare_exchange_weak_release(&e.status, old_status, new_status); ok {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
if old_status < 0 {
|
||||
sema_post(&e.sema);
|
||||
sema_post(&e.sema)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto_reset_event_wait :: proc(e: ^Auto_Reset_Event) {
|
||||
old_status := atomic_sub_acquire(&e.status, 1);
|
||||
old_status := atomic_sub_acquire(&e.status, 1)
|
||||
if old_status < 1 {
|
||||
sema_wait(&e.sema);
|
||||
sema_wait(&e.sema)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,14 +157,14 @@ Ticket_Mutex :: struct {
|
||||
}
|
||||
|
||||
ticket_mutex_lock :: #force_inline proc(m: ^Ticket_Mutex) {
|
||||
ticket := atomic_add_relaxed(&m.ticket, 1);
|
||||
ticket := atomic_add_relaxed(&m.ticket, 1)
|
||||
for ticket != atomic_load_acquire(&m.serving) {
|
||||
cpu_relax();
|
||||
cpu_relax()
|
||||
}
|
||||
}
|
||||
|
||||
ticket_mutex_unlock :: #force_inline proc(m: ^Ticket_Mutex) {
|
||||
atomic_add_relaxed(&m.serving, 1);
|
||||
atomic_add_relaxed(&m.serving, 1)
|
||||
}
|
||||
|
||||
|
||||
@@ -176,18 +176,18 @@ Benaphore :: struct {
|
||||
|
||||
benaphore_lock :: proc(b: ^Benaphore) {
|
||||
if atomic_add_acquire(&b.counter, 1) > 1 {
|
||||
sema_wait(&b.sema);
|
||||
sema_wait(&b.sema)
|
||||
}
|
||||
}
|
||||
|
||||
benaphore_try_lock :: proc(b: ^Benaphore) -> bool {
|
||||
v, _ := atomic_compare_exchange_strong_acquire(&b.counter, 1, 0);
|
||||
return v == 0;
|
||||
v, _ := atomic_compare_exchange_strong_acquire(&b.counter, 1, 0)
|
||||
return v == 0
|
||||
}
|
||||
|
||||
benaphore_unlock :: proc(b: ^Benaphore) {
|
||||
if atomic_sub_release(&b.counter, 1) > 0 {
|
||||
sema_post(&b.sema);
|
||||
sema_post(&b.sema)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,43 +199,43 @@ Recursive_Benaphore :: struct {
|
||||
}
|
||||
|
||||
recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
|
||||
tid := current_thread_id();
|
||||
tid := current_thread_id()
|
||||
if atomic_add_acquire(&b.counter, 1) > 1 {
|
||||
if tid != b.owner {
|
||||
sema_wait(&b.sema);
|
||||
sema_wait(&b.sema)
|
||||
}
|
||||
}
|
||||
// inside the lock
|
||||
b.owner = tid;
|
||||
b.recursion += 1;
|
||||
b.owner = tid
|
||||
b.recursion += 1
|
||||
}
|
||||
|
||||
recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
|
||||
tid := current_thread_id();
|
||||
tid := current_thread_id()
|
||||
if b.owner == tid {
|
||||
atomic_add_acquire(&b.counter, 1);
|
||||
atomic_add_acquire(&b.counter, 1)
|
||||
}
|
||||
|
||||
if v, _ := atomic_compare_exchange_strong_acquire(&b.counter, 1, 0); v != 0 {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
// inside the lock
|
||||
b.owner = tid;
|
||||
b.recursion += 1;
|
||||
return true;
|
||||
b.owner = tid
|
||||
b.recursion += 1
|
||||
return true
|
||||
}
|
||||
|
||||
recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
|
||||
tid := current_thread_id();
|
||||
assert(tid == b.owner);
|
||||
b.recursion -= 1;
|
||||
recursion := b.recursion;
|
||||
tid := current_thread_id()
|
||||
assert(tid == b.owner)
|
||||
b.recursion -= 1
|
||||
recursion := b.recursion
|
||||
if recursion == 0 {
|
||||
b.owner = 0;
|
||||
b.owner = 0
|
||||
}
|
||||
if atomic_sub_release(&b.counter, 1) > 0 {
|
||||
if recursion == 0 {
|
||||
sema_post(&b.sema);
|
||||
sema_post(&b.sema)
|
||||
}
|
||||
}
|
||||
// outside the lock
|
||||
@@ -252,16 +252,16 @@ Once :: struct {
|
||||
|
||||
once_do :: proc(o: ^Once, fn: proc()) {
|
||||
if atomic_load_acquire(&o.done) == false {
|
||||
_once_do_slow(o, fn);
|
||||
_once_do_slow(o, fn)
|
||||
}
|
||||
}
|
||||
|
||||
@(cold)
|
||||
_once_do_slow :: proc(o: ^Once, fn: proc()) {
|
||||
mutex_lock(&o.m);
|
||||
defer mutex_unlock(&o.m);
|
||||
mutex_lock(&o.m)
|
||||
defer mutex_unlock(&o.m)
|
||||
if !o.done {
|
||||
fn();
|
||||
atomic_store_release(&o.done, true);
|
||||
fn()
|
||||
atomic_store_release(&o.done, true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package sync2
|
||||
import "core:time"
|
||||
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
return _current_thread_id();
|
||||
return _current_thread_id()
|
||||
}
|
||||
|
||||
// A Mutex is a mutual exclusion lock
|
||||
@@ -16,17 +16,17 @@ Mutex :: struct {
|
||||
|
||||
// mutex_lock locks m
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
_mutex_lock(m);
|
||||
_mutex_lock(m)
|
||||
}
|
||||
|
||||
// mutex_unlock unlocks m
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
_mutex_unlock(m);
|
||||
_mutex_unlock(m)
|
||||
}
|
||||
|
||||
// mutex_lock tries to lock m, will return true on success, and false on failure
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
return _mutex_try_lock(m);
|
||||
return _mutex_try_lock(m)
|
||||
}
|
||||
|
||||
// Example:
|
||||
@@ -37,8 +37,8 @@ mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
//
|
||||
@(deferred_in=mutex_unlock)
|
||||
mutex_guard :: proc(m: ^Mutex) -> bool {
|
||||
mutex_lock(m);
|
||||
return true;
|
||||
mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
// A RW_Mutex is a reader/writer mutual exclusion lock
|
||||
@@ -53,32 +53,32 @@ RW_Mutex :: struct {
|
||||
// rw_mutex_lock locks rw for writing (with a single writer)
|
||||
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
|
||||
rw_mutex_lock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_lock(rw);
|
||||
_rw_mutex_lock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_unlock unlocks rw for writing (with a single writer)
|
||||
rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_unlock(rw);
|
||||
_rw_mutex_unlock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_try_lock tries to lock rw for writing (with a single writer)
|
||||
rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
return _rw_mutex_try_lock(rw);
|
||||
return _rw_mutex_try_lock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
||||
rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_shared_lock(rw);
|
||||
_rw_mutex_shared_lock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
|
||||
rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_shared_unlock(rw);
|
||||
_rw_mutex_shared_unlock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
||||
rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
return _rw_mutex_try_shared_lock(rw);
|
||||
return _rw_mutex_try_shared_lock(rw)
|
||||
}
|
||||
|
||||
// Example:
|
||||
@@ -89,8 +89,8 @@ rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
//
|
||||
@(deferred_in=rw_mutex_unlock)
|
||||
rw_mutex_guard :: proc(m: ^RW_Mutex) -> bool {
|
||||
rw_mutex_lock(m);
|
||||
return true;
|
||||
rw_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
// Example:
|
||||
@@ -101,8 +101,8 @@ rw_mutex_guard :: proc(m: ^RW_Mutex) -> bool {
|
||||
//
|
||||
@(deferred_in=rw_mutex_shared_unlock)
|
||||
rw_mutex_shared_guard :: proc(m: ^RW_Mutex) -> bool {
|
||||
rw_mutex_shared_lock(m);
|
||||
return true;
|
||||
rw_mutex_shared_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -116,15 +116,15 @@ Recursive_Mutex :: struct {
|
||||
}
|
||||
|
||||
recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||
_recursive_mutex_lock(m);
|
||||
_recursive_mutex_lock(m)
|
||||
}
|
||||
|
||||
recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
||||
_recursive_mutex_unlock(m);
|
||||
_recursive_mutex_unlock(m)
|
||||
}
|
||||
|
||||
recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
||||
return _recursive_mutex_try_lock(m);
|
||||
return _recursive_mutex_try_lock(m)
|
||||
}
|
||||
|
||||
|
||||
@@ -136,8 +136,8 @@ recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
||||
//
|
||||
@(deferred_in=recursive_mutex_unlock)
|
||||
recursive_mutex_guard :: proc(m: ^Recursive_Mutex) -> bool {
|
||||
recursive_mutex_lock(m);
|
||||
return true;
|
||||
recursive_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -150,19 +150,19 @@ Cond :: struct {
|
||||
}
|
||||
|
||||
cond_wait :: proc(c: ^Cond, m: ^Mutex) {
|
||||
_cond_wait(c, m);
|
||||
_cond_wait(c, m)
|
||||
}
|
||||
|
||||
cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, timeout: time.Duration) -> bool {
|
||||
return _cond_wait_with_timeout(c, m, timeout);
|
||||
return _cond_wait_with_timeout(c, m, timeout)
|
||||
}
|
||||
|
||||
cond_signal :: proc(c: ^Cond) {
|
||||
_cond_signal(c);
|
||||
_cond_signal(c)
|
||||
}
|
||||
|
||||
cond_broadcast :: proc(c: ^Cond) {
|
||||
_cond_broadcast(c);
|
||||
_cond_broadcast(c)
|
||||
}
|
||||
|
||||
|
||||
@@ -177,9 +177,9 @@ Sema :: struct {
|
||||
|
||||
|
||||
sema_wait :: proc(s: ^Sema) {
|
||||
_sema_wait(s);
|
||||
_sema_wait(s)
|
||||
}
|
||||
|
||||
sema_post :: proc(s: ^Sema, count := 1) {
|
||||
_sema_post(s, count);
|
||||
_sema_post(s, count)
|
||||
}
|
||||
|
||||
@@ -21,30 +21,30 @@ Atomic_Mutex :: struct {
|
||||
atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
|
||||
@(cold)
|
||||
lock_slow :: proc(m: ^Atomic_Mutex, curr_state: Atomic_Mutex_State) {
|
||||
new_state := curr_state; // Make a copy of it
|
||||
new_state := curr_state // Make a copy of it
|
||||
|
||||
spin_lock: for spin in 0..<i32(100) {
|
||||
state, ok := atomic_compare_exchange_weak_acquire(&m.state, .Unlocked, new_state);
|
||||
state, ok := atomic_compare_exchange_weak_acquire(&m.state, .Unlocked, new_state)
|
||||
if ok {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
if state == .Waiting {
|
||||
break spin_lock;
|
||||
break spin_lock
|
||||
}
|
||||
|
||||
for i := min(spin+1, 32); i > 0; i -= 1 {
|
||||
cpu_relax();
|
||||
cpu_relax()
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
if atomic_exchange_acquire(&m.state, .Waiting) == .Unlocked {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(bill): Use a Futex here for Linux to improve performance and error handling
|
||||
cpu_relax();
|
||||
cpu_relax()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
|
||||
switch v := atomic_exchange_acquire(&m.state, .Locked); v {
|
||||
case .Unlocked:
|
||||
// Okay
|
||||
case: fallthrough;
|
||||
case: fallthrough
|
||||
case .Locked, .Waiting:
|
||||
lock_slow(m, v);
|
||||
lock_slow(m, v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,18 +68,18 @@ atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) {
|
||||
|
||||
switch atomic_exchange_release(&m.state, .Unlocked) {
|
||||
case .Unlocked:
|
||||
unreachable();
|
||||
unreachable()
|
||||
case .Locked:
|
||||
// Okay
|
||||
case .Waiting:
|
||||
unlock_slow(m);
|
||||
unlock_slow(m)
|
||||
}
|
||||
}
|
||||
|
||||
// atomic_mutex_try_lock tries to lock m, will return true on success, and false on failure
|
||||
atomic_mutex_try_lock :: proc(m: ^Atomic_Mutex) -> bool {
|
||||
_, ok := atomic_compare_exchange_strong_acquire(&m.state, .Unlocked, .Locked);
|
||||
return ok;
|
||||
_, ok := atomic_compare_exchange_strong_acquire(&m.state, .Unlocked, .Locked)
|
||||
return ok
|
||||
}
|
||||
|
||||
|
||||
@@ -91,19 +91,19 @@ atomic_mutex_try_lock :: proc(m: ^Atomic_Mutex) -> bool {
|
||||
//
|
||||
@(deferred_in=atomic_mutex_unlock)
|
||||
atomic_mutex_guard :: proc(m: ^Atomic_Mutex) -> bool {
|
||||
atomic_mutex_lock(m);
|
||||
return true;
|
||||
atomic_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
Atomic_RW_Mutex_State :: distinct uint;
|
||||
Atomic_RW_Mutex_State_Half_Width :: size_of(Atomic_RW_Mutex_State)*8/2;
|
||||
Atomic_RW_Mutex_State_Is_Writing :: Atomic_RW_Mutex_State(1);
|
||||
Atomic_RW_Mutex_State_Writer :: Atomic_RW_Mutex_State(1)<<1;
|
||||
Atomic_RW_Mutex_State_Reader :: Atomic_RW_Mutex_State(1)<<Atomic_RW_Mutex_State_Half_Width;
|
||||
Atomic_RW_Mutex_State :: distinct uint
|
||||
Atomic_RW_Mutex_State_Half_Width :: size_of(Atomic_RW_Mutex_State)*8/2
|
||||
Atomic_RW_Mutex_State_Is_Writing :: Atomic_RW_Mutex_State(1)
|
||||
Atomic_RW_Mutex_State_Writer :: Atomic_RW_Mutex_State(1)<<1
|
||||
Atomic_RW_Mutex_State_Reader :: Atomic_RW_Mutex_State(1)<<Atomic_RW_Mutex_State_Half_Width
|
||||
|
||||
Atomic_RW_Mutex_State_Writer_Mask :: Atomic_RW_Mutex_State(1<<(Atomic_RW_Mutex_State_Half_Width-1) - 1) << 1;
|
||||
Atomic_RW_Mutex_State_Reader_Mask :: Atomic_RW_Mutex_State(1<<(Atomic_RW_Mutex_State_Half_Width-1) - 1) << Atomic_RW_Mutex_State_Half_Width;
|
||||
Atomic_RW_Mutex_State_Writer_Mask :: Atomic_RW_Mutex_State(1<<(Atomic_RW_Mutex_State_Half_Width-1) - 1) << 1
|
||||
Atomic_RW_Mutex_State_Reader_Mask :: Atomic_RW_Mutex_State(1<<(Atomic_RW_Mutex_State_Half_Width-1) - 1) << Atomic_RW_Mutex_State_Half_Width
|
||||
|
||||
|
||||
// An Atomic_RW_Mutex is a reader/writer mutual exclusion lock
|
||||
@@ -120,77 +120,77 @@ Atomic_RW_Mutex :: struct {
|
||||
// atomic_rw_mutex_lock locks rw for writing (with a single writer)
|
||||
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
|
||||
atomic_rw_mutex_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Writer);
|
||||
atomic_mutex_lock(&rw.mutex);
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Writer)
|
||||
atomic_mutex_lock(&rw.mutex)
|
||||
|
||||
state := atomic_or(&rw.state, Atomic_RW_Mutex_State_Writer);
|
||||
state := atomic_or(&rw.state, Atomic_RW_Mutex_State_Writer)
|
||||
if state & Atomic_RW_Mutex_State_Reader_Mask != 0 {
|
||||
atomic_sema_wait(&rw.sema);
|
||||
atomic_sema_wait(&rw.sema)
|
||||
}
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_unlock unlocks rw for writing (with a single writer)
|
||||
atomic_rw_mutex_unlock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
_ = atomic_and(&rw.state, ~Atomic_RW_Mutex_State_Is_Writing);
|
||||
atomic_mutex_unlock(&rw.mutex);
|
||||
_ = atomic_and(&rw.state, ~Atomic_RW_Mutex_State_Is_Writing)
|
||||
atomic_mutex_unlock(&rw.mutex)
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_try_lock tries to lock rw for writing (with a single writer)
|
||||
atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
||||
if atomic_mutex_try_lock(&rw.mutex) {
|
||||
state := atomic_load(&rw.state);
|
||||
state := atomic_load(&rw.state)
|
||||
if state & Atomic_RW_Mutex_State_Reader_Mask == 0 {
|
||||
_ = atomic_or(&rw.state, Atomic_RW_Mutex_State_Is_Writing);
|
||||
return true;
|
||||
_ = atomic_or(&rw.state, Atomic_RW_Mutex_State_Is_Writing)
|
||||
return true
|
||||
}
|
||||
|
||||
atomic_mutex_unlock(&rw.mutex);
|
||||
atomic_mutex_unlock(&rw.mutex)
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
||||
atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
state := atomic_load(&rw.state);
|
||||
state := atomic_load(&rw.state)
|
||||
for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
||||
ok: bool;
|
||||
state, ok = atomic_compare_exchange_weak(&rw.state, state, state + Atomic_RW_Mutex_State_Reader);
|
||||
ok: bool
|
||||
state, ok = atomic_compare_exchange_weak(&rw.state, state, state + Atomic_RW_Mutex_State_Reader)
|
||||
if ok {
|
||||
return;
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
atomic_mutex_lock(&rw.mutex);
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Reader);
|
||||
atomic_mutex_unlock(&rw.mutex);
|
||||
atomic_mutex_lock(&rw.mutex)
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Reader)
|
||||
atomic_mutex_unlock(&rw.mutex)
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
|
||||
atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
state := atomic_sub(&rw.state, Atomic_RW_Mutex_State_Reader);
|
||||
state := atomic_sub(&rw.state, Atomic_RW_Mutex_State_Reader)
|
||||
|
||||
if (state & Atomic_RW_Mutex_State_Reader_Mask == Atomic_RW_Mutex_State_Reader) &&
|
||||
(state & Atomic_RW_Mutex_State_Is_Writing != 0) {
|
||||
atomic_sema_post(&rw.sema);
|
||||
atomic_sema_post(&rw.sema)
|
||||
}
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
||||
atomic_rw_mutex_try_shared_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
||||
state := atomic_load(&rw.state);
|
||||
state := atomic_load(&rw.state)
|
||||
if state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
||||
_, ok := atomic_compare_exchange_strong(&rw.state, state, state + Atomic_RW_Mutex_State_Reader);
|
||||
_, ok := atomic_compare_exchange_strong(&rw.state, state, state + Atomic_RW_Mutex_State_Reader)
|
||||
if ok {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
}
|
||||
if atomic_mutex_try_lock(&rw.mutex) {
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Reader);
|
||||
atomic_mutex_unlock(&rw.mutex);
|
||||
return true;
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Reader)
|
||||
atomic_mutex_unlock(&rw.mutex)
|
||||
return true
|
||||
}
|
||||
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -202,8 +202,8 @@ atomic_rw_mutex_try_shared_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
||||
//
|
||||
@(deferred_in=atomic_rw_mutex_unlock)
|
||||
atomic_rw_mutex_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_lock(m);
|
||||
return true;
|
||||
atomic_rw_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
// Example:
|
||||
@@ -214,8 +214,8 @@ atomic_rw_mutex_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
|
||||
//
|
||||
@(deferred_in=atomic_rw_mutex_shared_unlock)
|
||||
atomic_rw_mutex_shared_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_shared_lock(m);
|
||||
return true;
|
||||
atomic_rw_mutex_shared_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -232,42 +232,42 @@ Atomic_Recursive_Mutex :: struct {
|
||||
}
|
||||
|
||||
atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) {
|
||||
tid := current_thread_id();
|
||||
tid := current_thread_id()
|
||||
if tid != m.owner {
|
||||
mutex_lock(&m.mutex);
|
||||
mutex_lock(&m.mutex)
|
||||
}
|
||||
// inside the lock
|
||||
m.owner = tid;
|
||||
m.recursion += 1;
|
||||
m.owner = tid
|
||||
m.recursion += 1
|
||||
}
|
||||
|
||||
atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex) {
|
||||
tid := current_thread_id();
|
||||
assert(tid == m.owner);
|
||||
m.recursion -= 1;
|
||||
recursion := m.recursion;
|
||||
tid := current_thread_id()
|
||||
assert(tid == m.owner)
|
||||
m.recursion -= 1
|
||||
recursion := m.recursion
|
||||
if recursion == 0 {
|
||||
m.owner = 0;
|
||||
m.owner = 0
|
||||
}
|
||||
if recursion == 0 {
|
||||
mutex_unlock(&m.mutex);
|
||||
mutex_unlock(&m.mutex)
|
||||
}
|
||||
// outside the lock
|
||||
|
||||
}
|
||||
|
||||
atomic_recursive_mutex_try_lock :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
|
||||
tid := current_thread_id();
|
||||
tid := current_thread_id()
|
||||
if m.owner == tid {
|
||||
return mutex_try_lock(&m.mutex);
|
||||
return mutex_try_lock(&m.mutex)
|
||||
}
|
||||
if !mutex_try_lock(&m.mutex) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
// inside the lock
|
||||
m.owner = tid;
|
||||
m.recursion += 1;
|
||||
return true;
|
||||
m.owner = tid
|
||||
m.recursion += 1
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -279,8 +279,8 @@ atomic_recursive_mutex_try_lock :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
|
||||
//
|
||||
@(deferred_in=atomic_recursive_mutex_unlock)
|
||||
atomic_recursive_mutex_guard :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
|
||||
atomic_recursive_mutex_lock(m);
|
||||
return true;
|
||||
atomic_recursive_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -296,12 +296,12 @@ Queue_Item :: struct {
|
||||
queue_item_wait :: proc(item: ^Queue_Item) {
|
||||
for atomic_load_acquire(&item.futex) == 0 {
|
||||
// TODO(bill): Use a Futex here for Linux to improve performance and error handling
|
||||
cpu_relax();
|
||||
cpu_relax()
|
||||
}
|
||||
}
|
||||
@(private="file")
|
||||
queue_item_signal :: proc(item: ^Queue_Item) {
|
||||
atomic_store_release(&item.futex, 1);
|
||||
atomic_store_release(&item.futex, 1)
|
||||
// TODO(bill): Use a Futex here for Linux to improve performance and error handling
|
||||
}
|
||||
|
||||
@@ -317,58 +317,58 @@ Atomic_Cond :: struct {
|
||||
}
|
||||
|
||||
atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) {
|
||||
waiter := &Queue_Item{};
|
||||
waiter := &Queue_Item{}
|
||||
|
||||
atomic_mutex_lock(&c.queue_mutex);
|
||||
waiter.next = c.queue_head;
|
||||
c.queue_head = waiter;
|
||||
atomic_mutex_lock(&c.queue_mutex)
|
||||
waiter.next = c.queue_head
|
||||
c.queue_head = waiter
|
||||
|
||||
atomic_store(&c.pending, true);
|
||||
atomic_mutex_unlock(&c.queue_mutex);
|
||||
atomic_store(&c.pending, true)
|
||||
atomic_mutex_unlock(&c.queue_mutex)
|
||||
|
||||
atomic_mutex_unlock(m);
|
||||
queue_item_wait(waiter);
|
||||
atomic_mutex_lock(m);
|
||||
atomic_mutex_unlock(m)
|
||||
queue_item_wait(waiter)
|
||||
atomic_mutex_lock(m)
|
||||
}
|
||||
|
||||
atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, timeout: time.Duration) -> bool {
|
||||
// TODO(bill): _cond_wait_with_timeout for unix
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
atomic_cond_signal :: proc(c: ^Atomic_Cond) {
|
||||
if !atomic_load(&c.pending) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
atomic_mutex_lock(&c.queue_mutex);
|
||||
waiter := c.queue_head;
|
||||
atomic_mutex_lock(&c.queue_mutex)
|
||||
waiter := c.queue_head
|
||||
if c.queue_head != nil {
|
||||
c.queue_head = c.queue_head.next;
|
||||
c.queue_head = c.queue_head.next
|
||||
}
|
||||
atomic_store(&c.pending, c.queue_head != nil);
|
||||
atomic_mutex_unlock(&c.queue_mutex);
|
||||
atomic_store(&c.pending, c.queue_head != nil)
|
||||
atomic_mutex_unlock(&c.queue_mutex)
|
||||
|
||||
if waiter != nil {
|
||||
queue_item_signal(waiter);
|
||||
queue_item_signal(waiter)
|
||||
}
|
||||
}
|
||||
|
||||
atomic_cond_broadcast :: proc(c: ^Atomic_Cond) {
|
||||
if !atomic_load(&c.pending) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
atomic_store(&c.pending, false);
|
||||
atomic_store(&c.pending, false)
|
||||
|
||||
atomic_mutex_lock(&c.queue_mutex);
|
||||
waiters := c.queue_head;
|
||||
c.queue_head = nil;
|
||||
atomic_mutex_unlock(&c.queue_mutex);
|
||||
atomic_mutex_lock(&c.queue_mutex)
|
||||
waiters := c.queue_head
|
||||
c.queue_head = nil
|
||||
atomic_mutex_unlock(&c.queue_mutex)
|
||||
|
||||
for waiters != nil {
|
||||
queue_item_signal(waiters);
|
||||
waiters = waiters.next;
|
||||
queue_item_signal(waiters)
|
||||
waiters = waiters.next
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,24 +383,24 @@ Atomic_Sema :: struct {
|
||||
}
|
||||
|
||||
atomic_sema_wait :: proc(s: ^Atomic_Sema) {
|
||||
atomic_mutex_lock(&s.mutex);
|
||||
defer atomic_mutex_unlock(&s.mutex);
|
||||
atomic_mutex_lock(&s.mutex)
|
||||
defer atomic_mutex_unlock(&s.mutex)
|
||||
|
||||
for s.count == 0 {
|
||||
atomic_cond_wait(&s.cond, &s.mutex);
|
||||
atomic_cond_wait(&s.cond, &s.mutex)
|
||||
}
|
||||
|
||||
s.count -= 1;
|
||||
s.count -= 1
|
||||
if s.count > 0 {
|
||||
atomic_cond_signal(&s.cond);
|
||||
atomic_cond_signal(&s.cond)
|
||||
}
|
||||
}
|
||||
|
||||
atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) {
|
||||
atomic_mutex_lock(&s.mutex);
|
||||
defer atomic_mutex_unlock(&s.mutex);
|
||||
atomic_mutex_lock(&s.mutex)
|
||||
defer atomic_mutex_unlock(&s.mutex)
|
||||
|
||||
s.count += count;
|
||||
atomic_cond_signal(&s.cond);
|
||||
s.count += count
|
||||
atomic_cond_signal(&s.cond)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import "core:time"
|
||||
import win32 "core:sys/windows"
|
||||
|
||||
_current_thread_id :: proc "contextless" () -> int {
|
||||
return int(win32.GetCurrentThreadId());
|
||||
return int(win32.GetCurrentThreadId())
|
||||
}
|
||||
|
||||
_Mutex :: struct {
|
||||
@@ -14,15 +14,15 @@ _Mutex :: struct {
|
||||
}
|
||||
|
||||
_mutex_lock :: proc(m: ^Mutex) {
|
||||
win32.AcquireSRWLockExclusive(&m.impl.srwlock);
|
||||
win32.AcquireSRWLockExclusive(&m.impl.srwlock)
|
||||
}
|
||||
|
||||
_mutex_unlock :: proc(m: ^Mutex) {
|
||||
win32.ReleaseSRWLockExclusive(&m.impl.srwlock);
|
||||
win32.ReleaseSRWLockExclusive(&m.impl.srwlock)
|
||||
}
|
||||
|
||||
_mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&m.impl.srwlock));
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&m.impl.srwlock))
|
||||
}
|
||||
|
||||
_RW_Mutex :: struct {
|
||||
@@ -30,27 +30,27 @@ _RW_Mutex :: struct {
|
||||
}
|
||||
|
||||
_rw_mutex_lock :: proc(rw: ^RW_Mutex) {
|
||||
win32.AcquireSRWLockExclusive(&rw.impl.srwlock);
|
||||
win32.AcquireSRWLockExclusive(&rw.impl.srwlock)
|
||||
}
|
||||
|
||||
_rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
|
||||
win32.ReleaseSRWLockExclusive(&rw.impl.srwlock);
|
||||
win32.ReleaseSRWLockExclusive(&rw.impl.srwlock)
|
||||
}
|
||||
|
||||
_rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&rw.impl.srwlock));
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&rw.impl.srwlock))
|
||||
}
|
||||
|
||||
_rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
|
||||
win32.AcquireSRWLockShared(&rw.impl.srwlock);
|
||||
win32.AcquireSRWLockShared(&rw.impl.srwlock)
|
||||
}
|
||||
|
||||
_rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
|
||||
win32.ReleaseSRWLockShared(&rw.impl.srwlock);
|
||||
win32.ReleaseSRWLockShared(&rw.impl.srwlock)
|
||||
}
|
||||
|
||||
_rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
return bool(win32.TryAcquireSRWLockShared(&rw.impl.srwlock));
|
||||
return bool(win32.TryAcquireSRWLockShared(&rw.impl.srwlock))
|
||||
}
|
||||
|
||||
|
||||
@@ -60,14 +60,14 @@ _Recursive_Mutex :: struct {
|
||||
}
|
||||
|
||||
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||
tid := win32.GetCurrentThreadId();
|
||||
tid := win32.GetCurrentThreadId()
|
||||
for {
|
||||
prev_owner := atomic_compare_exchange_strong_acquire(&m.impl.owner, tid, 0);
|
||||
prev_owner := atomic_compare_exchange_strong_acquire(&m.impl.owner, tid, 0)
|
||||
switch prev_owner {
|
||||
case 0, tid:
|
||||
m.impl.claim_count += 1;
|
||||
m.impl.claim_count += 1
|
||||
// inside the lock
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
win32.WaitOnAddress(
|
||||
@@ -75,31 +75,31 @@ _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||
&prev_owner,
|
||||
size_of(prev_owner),
|
||||
win32.INFINITE,
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
||||
m.impl.claim_count -= 1;
|
||||
m.impl.claim_count -= 1
|
||||
if m.impl.claim_count != 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
atomic_exchange_release(&m.impl.owner, 0);
|
||||
win32.WakeByAddressSingle(&m.impl.owner);
|
||||
atomic_exchange_release(&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_compare_exchange_strong_acquire(&m.impl.owner, tid, 0);
|
||||
tid := win32.GetCurrentThreadId()
|
||||
prev_owner := atomic_compare_exchange_strong_acquire(&m.impl.owner, tid, 0)
|
||||
switch prev_owner {
|
||||
case 0, tid:
|
||||
m.impl.claim_count += 1;
|
||||
m.impl.claim_count += 1
|
||||
// inside the lock
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -110,20 +110,20 @@ _Cond :: struct {
|
||||
}
|
||||
|
||||
_cond_wait :: proc(c: ^Cond, m: ^Mutex) {
|
||||
_ = win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, win32.INFINITE, 0);
|
||||
_ = win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, win32.INFINITE, 0)
|
||||
}
|
||||
|
||||
_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, timeout: time.Duration) -> bool {
|
||||
ms := win32.DWORD((max(time.duration_nanoseconds(timeout), 0) + 999999)/1000000);
|
||||
return cast(bool)win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, ms, 0);
|
||||
ms := win32.DWORD((max(time.duration_nanoseconds(timeout), 0) + 999999)/1000000)
|
||||
return cast(bool)win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, ms, 0)
|
||||
}
|
||||
|
||||
_cond_signal :: proc(c: ^Cond) {
|
||||
win32.WakeConditionVariable(&c.impl.cond);
|
||||
win32.WakeConditionVariable(&c.impl.cond)
|
||||
}
|
||||
|
||||
_cond_broadcast :: proc(c: ^Cond) {
|
||||
win32.WakeAllConditionVariable(&c.impl.cond);
|
||||
win32.WakeAllConditionVariable(&c.impl.cond)
|
||||
}
|
||||
|
||||
|
||||
@@ -133,27 +133,27 @@ _Sema :: struct {
|
||||
|
||||
_sema_wait :: proc(s: ^Sema) {
|
||||
for {
|
||||
original_count := s.impl.count;
|
||||
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;
|
||||
)
|
||||
original_count = s.impl.count
|
||||
}
|
||||
if original_count == atomic_compare_exchange_strong(&s.impl.count, original_count-1, original_count) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sema_post :: proc(s: ^Sema, count := 1) {
|
||||
atomic_add(&s.impl.count, i32(count));
|
||||
atomic_add(&s.impl.count, i32(count))
|
||||
if count == 1 {
|
||||
win32.WakeByAddressSingle(&s.impl.count);
|
||||
win32.WakeByAddressSingle(&s.impl.count)
|
||||
} else {
|
||||
win32.WakeByAddressAll(&s.impl.count);
|
||||
win32.WakeByAddressAll(&s.impl.count)
|
||||
}
|
||||
}
|
||||
|
||||
+40
-40
@@ -5,7 +5,7 @@ import win32 "core:sys/windows"
|
||||
import "core:time"
|
||||
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
return int(win32.GetCurrentThreadId());
|
||||
return int(win32.GetCurrentThreadId())
|
||||
}
|
||||
|
||||
|
||||
@@ -16,21 +16,21 @@ Semaphore :: struct {
|
||||
}
|
||||
|
||||
semaphore_init :: proc(s: ^Semaphore, initial_count := 0) {
|
||||
s._handle = win32.CreateSemaphoreW(nil, i32(initial_count), 1<<31-1, nil);
|
||||
s._handle = win32.CreateSemaphoreW(nil, i32(initial_count), 1<<31-1, nil)
|
||||
}
|
||||
|
||||
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||
win32.CloseHandle(s._handle);
|
||||
win32.CloseHandle(s._handle)
|
||||
}
|
||||
|
||||
semaphore_post :: proc(s: ^Semaphore, count := 1) {
|
||||
win32.ReleaseSemaphore(s._handle, i32(count), nil);
|
||||
win32.ReleaseSemaphore(s._handle, i32(count), nil)
|
||||
}
|
||||
|
||||
semaphore_wait_for :: proc(s: ^Semaphore) {
|
||||
// NOTE(tetra, 2019-10-30): wait_for_single_object decrements the count before it returns.
|
||||
result := win32.WaitForSingleObject(s._handle, win32.INFINITE);
|
||||
assert(result != win32.WAIT_FAILED);
|
||||
result := win32.WaitForSingleObject(s._handle, win32.INFINITE)
|
||||
assert(result != win32.WAIT_FAILED)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,23 +40,23 @@ Mutex :: struct {
|
||||
|
||||
|
||||
mutex_init :: proc(m: ^Mutex, spin_count := 0) {
|
||||
win32.InitializeCriticalSectionAndSpinCount(&m._critical_section, u32(spin_count));
|
||||
win32.InitializeCriticalSectionAndSpinCount(&m._critical_section, u32(spin_count))
|
||||
}
|
||||
|
||||
mutex_destroy :: proc(m: ^Mutex) {
|
||||
win32.DeleteCriticalSection(&m._critical_section);
|
||||
win32.DeleteCriticalSection(&m._critical_section)
|
||||
}
|
||||
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
win32.EnterCriticalSection(&m._critical_section);
|
||||
win32.EnterCriticalSection(&m._critical_section)
|
||||
}
|
||||
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
return bool(win32.TryEnterCriticalSection(&m._critical_section));
|
||||
return bool(win32.TryEnterCriticalSection(&m._critical_section))
|
||||
}
|
||||
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
win32.LeaveCriticalSection(&m._critical_section);
|
||||
win32.LeaveCriticalSection(&m._critical_section)
|
||||
}
|
||||
|
||||
Blocking_Mutex :: struct {
|
||||
@@ -65,7 +65,7 @@ Blocking_Mutex :: struct {
|
||||
|
||||
|
||||
blocking_mutex_init :: proc(m: ^Blocking_Mutex) {
|
||||
win32.InitializeSRWLock(&m._handle);
|
||||
win32.InitializeSRWLock(&m._handle)
|
||||
}
|
||||
|
||||
blocking_mutex_destroy :: proc(m: ^Blocking_Mutex) {
|
||||
@@ -73,15 +73,15 @@ blocking_mutex_destroy :: proc(m: ^Blocking_Mutex) {
|
||||
}
|
||||
|
||||
blocking_mutex_lock :: proc(m: ^Blocking_Mutex) {
|
||||
win32.AcquireSRWLockExclusive(&m._handle);
|
||||
win32.AcquireSRWLockExclusive(&m._handle)
|
||||
}
|
||||
|
||||
blocking_mutex_try_lock :: proc(m: ^Blocking_Mutex) -> bool {
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&m._handle));
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&m._handle))
|
||||
}
|
||||
|
||||
blocking_mutex_unlock :: proc(m: ^Blocking_Mutex) {
|
||||
win32.ReleaseSRWLockExclusive(&m._handle);
|
||||
win32.ReleaseSRWLockExclusive(&m._handle)
|
||||
}
|
||||
|
||||
|
||||
@@ -95,10 +95,10 @@ Condition :: struct {
|
||||
|
||||
|
||||
condition_init :: proc(c: ^Condition, mutex: Condition_Mutex_Ptr) -> bool {
|
||||
assert(mutex != nil);
|
||||
win32.InitializeConditionVariable(&c._handle);
|
||||
c.mutex = mutex;
|
||||
return true;
|
||||
assert(mutex != nil)
|
||||
win32.InitializeConditionVariable(&c._handle)
|
||||
c.mutex = mutex
|
||||
return true
|
||||
}
|
||||
|
||||
condition_destroy :: proc(c: ^Condition) {
|
||||
@@ -107,38 +107,38 @@ condition_destroy :: proc(c: ^Condition) {
|
||||
|
||||
condition_signal :: proc(c: ^Condition) -> bool {
|
||||
if c._handle.ptr == nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
win32.WakeConditionVariable(&c._handle);
|
||||
return true;
|
||||
win32.WakeConditionVariable(&c._handle)
|
||||
return true
|
||||
}
|
||||
|
||||
condition_broadcast :: proc(c: ^Condition) -> bool {
|
||||
if c._handle.ptr == nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
win32.WakeAllConditionVariable(&c._handle);
|
||||
return true;
|
||||
win32.WakeAllConditionVariable(&c._handle)
|
||||
return true
|
||||
}
|
||||
|
||||
condition_wait_for :: proc(c: ^Condition) -> bool {
|
||||
switch m in &c.mutex {
|
||||
case ^Mutex:
|
||||
return cast(bool)win32.SleepConditionVariableCS(&c._handle, &m._critical_section, win32.INFINITE);
|
||||
return cast(bool)win32.SleepConditionVariableCS(&c._handle, &m._critical_section, win32.INFINITE)
|
||||
case ^Blocking_Mutex:
|
||||
return cast(bool)win32.SleepConditionVariableSRW(&c._handle, &m._handle, win32.INFINITE, 0);
|
||||
return cast(bool)win32.SleepConditionVariableSRW(&c._handle, &m._handle, win32.INFINITE, 0)
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
condition_wait_for_timeout :: proc(c: ^Condition, duration: time.Duration) -> bool {
|
||||
ms := win32.DWORD((max(time.duration_nanoseconds(duration), 0) + 999999)/1000000);
|
||||
ms := win32.DWORD((max(time.duration_nanoseconds(duration), 0) + 999999)/1000000)
|
||||
switch m in &c.mutex {
|
||||
case ^Mutex:
|
||||
return cast(bool)win32.SleepConditionVariableCS(&c._handle, &m._critical_section, ms);
|
||||
return cast(bool)win32.SleepConditionVariableCS(&c._handle, &m._critical_section, ms)
|
||||
case ^Blocking_Mutex:
|
||||
return cast(bool)win32.SleepConditionVariableSRW(&c._handle, &m._handle, ms, 0);
|
||||
return cast(bool)win32.SleepConditionVariableSRW(&c._handle, &m._handle, ms, 0)
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -149,32 +149,32 @@ RW_Lock :: struct {
|
||||
}
|
||||
|
||||
rw_lock_init :: proc(l: ^RW_Lock) {
|
||||
l._handle = win32.SRWLOCK_INIT;
|
||||
l._handle = win32.SRWLOCK_INIT
|
||||
}
|
||||
rw_lock_destroy :: proc(l: ^RW_Lock) {
|
||||
//
|
||||
}
|
||||
rw_lock_read :: proc(l: ^RW_Lock) {
|
||||
win32.AcquireSRWLockShared(&l._handle);
|
||||
win32.AcquireSRWLockShared(&l._handle)
|
||||
}
|
||||
rw_lock_try_read :: proc(l: ^RW_Lock) -> bool {
|
||||
return bool(win32.TryAcquireSRWLockShared(&l._handle));
|
||||
return bool(win32.TryAcquireSRWLockShared(&l._handle))
|
||||
}
|
||||
rw_lock_write :: proc(l: ^RW_Lock) {
|
||||
win32.AcquireSRWLockExclusive(&l._handle);
|
||||
win32.AcquireSRWLockExclusive(&l._handle)
|
||||
}
|
||||
rw_lock_try_write :: proc(l: ^RW_Lock) -> bool {
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&l._handle));
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&l._handle))
|
||||
}
|
||||
rw_lock_read_unlock :: proc(l: ^RW_Lock) {
|
||||
win32.ReleaseSRWLockShared(&l._handle);
|
||||
win32.ReleaseSRWLockShared(&l._handle)
|
||||
}
|
||||
rw_lock_write_unlock :: proc(l: ^RW_Lock) {
|
||||
win32.ReleaseSRWLockExclusive(&l._handle);
|
||||
win32.ReleaseSRWLockExclusive(&l._handle)
|
||||
}
|
||||
|
||||
|
||||
thread_yield :: proc() {
|
||||
win32.SwitchToThread();
|
||||
win32.SwitchToThread()
|
||||
}
|
||||
|
||||
|
||||
+17
-17
@@ -9,49 +9,49 @@ Wait_Group :: struct {
|
||||
}
|
||||
|
||||
wait_group_init :: proc(wg: ^Wait_Group) {
|
||||
wg.counter = 0;
|
||||
blocking_mutex_init(&wg.mutex);
|
||||
condition_init(&wg.cond, &wg.mutex);
|
||||
wg.counter = 0
|
||||
blocking_mutex_init(&wg.mutex)
|
||||
condition_init(&wg.cond, &wg.mutex)
|
||||
}
|
||||
|
||||
|
||||
wait_group_destroy :: proc(wg: ^Wait_Group) {
|
||||
condition_destroy(&wg.cond);
|
||||
blocking_mutex_destroy(&wg.mutex);
|
||||
condition_destroy(&wg.cond)
|
||||
blocking_mutex_destroy(&wg.mutex)
|
||||
}
|
||||
|
||||
wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
|
||||
if delta == 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
blocking_mutex_lock(&wg.mutex);
|
||||
defer blocking_mutex_unlock(&wg.mutex);
|
||||
blocking_mutex_lock(&wg.mutex)
|
||||
defer blocking_mutex_unlock(&wg.mutex)
|
||||
|
||||
intrinsics.atomic_add(&wg.counter, delta);
|
||||
intrinsics.atomic_add(&wg.counter, delta)
|
||||
if wg.counter < 0 {
|
||||
panic("sync.Wait_Group negative counter");
|
||||
panic("sync.Wait_Group negative counter")
|
||||
}
|
||||
if wg.counter == 0 {
|
||||
condition_broadcast(&wg.cond);
|
||||
condition_broadcast(&wg.cond)
|
||||
if wg.counter != 0 {
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait");
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wait_group_done :: proc(wg: ^Wait_Group) {
|
||||
wait_group_add(wg, -1);
|
||||
wait_group_add(wg, -1)
|
||||
}
|
||||
|
||||
wait_group_wait :: proc(wg: ^Wait_Group) {
|
||||
blocking_mutex_lock(&wg.mutex);
|
||||
defer blocking_mutex_unlock(&wg.mutex);
|
||||
blocking_mutex_lock(&wg.mutex)
|
||||
defer blocking_mutex_unlock(&wg.mutex)
|
||||
|
||||
if wg.counter != 0 {
|
||||
condition_wait_for(&wg.cond);
|
||||
condition_wait_for(&wg.cond)
|
||||
if wg.counter != 0 {
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait");
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user