Make sync calls contextless where possible

This commit is contained in:
gingerBill
2022-12-08 15:55:53 +00:00
parent 9cb9964c2d
commit 20943a81c1
11 changed files with 171 additions and 155 deletions
+28 -28
View File
@@ -11,7 +11,7 @@ Wait_Group :: struct {
cond: Cond, cond: Cond,
} }
wait_group_add :: proc(wg: ^Wait_Group, delta: int) { wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) {
if delta == 0 { if delta == 0 {
return return
} }
@@ -20,32 +20,32 @@ wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
atomic_add(&wg.counter, delta) atomic_add(&wg.counter, delta)
if wg.counter < 0 { if wg.counter < 0 {
panic("sync.Wait_Group negative counter") _panic("sync.Wait_Group negative counter")
} }
if wg.counter == 0 { if wg.counter == 0 {
cond_broadcast(&wg.cond) cond_broadcast(&wg.cond)
if wg.counter != 0 { 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_done :: proc "contextless" (wg: ^Wait_Group) {
wait_group_add(wg, -1) wait_group_add(wg, -1)
} }
wait_group_wait :: proc(wg: ^Wait_Group) { wait_group_wait :: proc "contextless" (wg: ^Wait_Group) {
guard(&wg.mutex) guard(&wg.mutex)
if wg.counter != 0 { if wg.counter != 0 {
cond_wait(&wg.cond, &wg.mutex) cond_wait(&wg.cond, &wg.mutex)
if wg.counter != 0 { 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_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -> bool { wait_group_wait_with_timeout :: proc "contextless" (wg: ^Wait_Group, duration: time.Duration) -> bool {
if duration <= 0 { if duration <= 0 {
return false return false
} }
@@ -56,7 +56,7 @@ wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -
return false return false
} }
if wg.counter != 0 { 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")
} }
} }
return true return true
@@ -76,7 +76,7 @@ Example:
barrier := &sync.Barrier{} barrier := &sync.Barrier{}
main :: proc() { main :: proc "contextless" () {
fmt.println("Start") fmt.println("Start")
THREAD_COUNT :: 4 THREAD_COUNT :: 4
@@ -107,7 +107,7 @@ Barrier :: struct {
thread_count: int, thread_count: int,
} }
barrier_init :: proc(b: ^Barrier, thread_count: int) { barrier_init :: proc "contextless" (b: ^Barrier, thread_count: int) {
b.index = 0 b.index = 0
b.generation_id = 0 b.generation_id = 0
b.thread_count = thread_count b.thread_count = thread_count
@@ -115,7 +115,7 @@ barrier_init :: proc(b: ^Barrier, thread_count: int) {
// Block the current thread until all threads have rendezvoused // Block the current thread until all threads have rendezvoused
// Barrier can be reused after all threads rendezvoused once, and can be used continuously // Barrier can be reused after all threads rendezvoused once, and can be used continuously
barrier_wait :: proc(b: ^Barrier) -> (is_leader: bool) { barrier_wait :: proc "contextless" (b: ^Barrier) -> (is_leader: bool) {
guard(&b.mutex) guard(&b.mutex)
local_gen := b.generation_id local_gen := b.generation_id
b.index += 1 b.index += 1
@@ -141,7 +141,7 @@ Auto_Reset_Event :: struct {
sema: Sema, sema: Sema,
} }
auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) { auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) {
old_status := atomic_load_explicit(&e.status, .Relaxed) old_status := atomic_load_explicit(&e.status, .Relaxed)
for { for {
new_status := old_status + 1 if old_status < 1 else 1 new_status := old_status + 1 if old_status < 1 else 1
@@ -155,7 +155,7 @@ auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) {
} }
} }
auto_reset_event_wait :: proc(e: ^Auto_Reset_Event) { auto_reset_event_wait :: proc "contextless" (e: ^Auto_Reset_Event) {
old_status := atomic_sub_explicit(&e.status, 1, .Acquire) old_status := atomic_sub_explicit(&e.status, 1, .Acquire)
if old_status < 1 { if old_status < 1 {
sema_wait(&e.sema) sema_wait(&e.sema)
@@ -169,18 +169,18 @@ Ticket_Mutex :: struct {
serving: uint, serving: uint,
} }
ticket_mutex_lock :: #force_inline proc(m: ^Ticket_Mutex) { ticket_mutex_lock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
ticket := atomic_add_explicit(&m.ticket, 1, .Relaxed) ticket := atomic_add_explicit(&m.ticket, 1, .Relaxed)
for ticket != atomic_load_explicit(&m.serving, .Acquire) { for ticket != atomic_load_explicit(&m.serving, .Acquire) {
cpu_relax() cpu_relax()
} }
} }
ticket_mutex_unlock :: #force_inline proc(m: ^Ticket_Mutex) { ticket_mutex_unlock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
atomic_add_explicit(&m.serving, 1, .Relaxed) atomic_add_explicit(&m.serving, 1, .Relaxed)
} }
@(deferred_in=ticket_mutex_unlock) @(deferred_in=ticket_mutex_unlock)
ticket_mutex_guard :: proc(m: ^Ticket_Mutex) -> bool { ticket_mutex_guard :: proc "contextless" (m: ^Ticket_Mutex) -> bool {
ticket_mutex_lock(m) ticket_mutex_lock(m)
return true return true
} }
@@ -191,25 +191,25 @@ Benaphore :: struct {
sema: Sema, sema: Sema,
} }
benaphore_lock :: proc(b: ^Benaphore) { benaphore_lock :: proc "contextless" (b: ^Benaphore) {
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 { if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
sema_wait(&b.sema) sema_wait(&b.sema)
} }
} }
benaphore_try_lock :: proc(b: ^Benaphore) -> bool { benaphore_try_lock :: proc "contextless" (b: ^Benaphore) -> bool {
v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire) v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire)
return v == 0 return v == 0
} }
benaphore_unlock :: proc(b: ^Benaphore) { benaphore_unlock :: proc "contextless" (b: ^Benaphore) {
if atomic_sub_explicit(&b.counter, 1, .Release) > 0 { if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
sema_post(&b.sema) sema_post(&b.sema)
} }
} }
@(deferred_in=benaphore_unlock) @(deferred_in=benaphore_unlock)
benaphore_guard :: proc(m: ^Benaphore) -> bool { benaphore_guard :: proc "contextless" (m: ^Benaphore) -> bool {
benaphore_lock(m) benaphore_lock(m)
return true return true
} }
@@ -221,7 +221,7 @@ Recursive_Benaphore :: struct {
sema: Sema, sema: Sema,
} }
recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) { recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) {
tid := current_thread_id() tid := current_thread_id()
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 { if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
if tid != b.owner { if tid != b.owner {
@@ -233,7 +233,7 @@ recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
b.recursion += 1 b.recursion += 1
} }
recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool { recursive_benaphore_try_lock :: proc "contextless" (b: ^Recursive_Benaphore) -> bool {
tid := current_thread_id() tid := current_thread_id()
if b.owner == tid { if b.owner == tid {
atomic_add_explicit(&b.counter, 1, .Acquire) atomic_add_explicit(&b.counter, 1, .Acquire)
@@ -248,9 +248,9 @@ recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
return true return true
} }
recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) { recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) {
tid := current_thread_id() tid := current_thread_id()
assert(tid == b.owner) _assert(tid == b.owner, "tid != b.owner")
b.recursion -= 1 b.recursion -= 1
recursion := b.recursion recursion := b.recursion
if recursion == 0 { if recursion == 0 {
@@ -265,7 +265,7 @@ recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
} }
@(deferred_in=recursive_benaphore_unlock) @(deferred_in=recursive_benaphore_unlock)
recursive_benaphore_guard :: proc(m: ^Recursive_Benaphore) -> bool { recursive_benaphore_guard :: proc "contextless" (m: ^Recursive_Benaphore) -> bool {
recursive_benaphore_lock(m) recursive_benaphore_lock(m)
return true return true
} }
@@ -314,7 +314,7 @@ Parker :: struct {
// Blocks the current thread until the token is made available. // Blocks the current thread until the token is made available.
// //
// Assumes this is only called by the thread that owns the Parker. // Assumes this is only called by the thread that owns the Parker.
park :: proc(p: ^Parker) { park :: proc "contextless" (p: ^Parker) {
EMPTY :: 0 EMPTY :: 0
NOTIFIED :: 1 NOTIFIED :: 1
PARKED :: max(u32) PARKED :: max(u32)
@@ -333,7 +333,7 @@ park :: proc(p: ^Parker) {
// for a limited duration. // for a limited duration.
// //
// Assumes this is only called by the thread that owns the Parker // Assumes this is only called by the thread that owns the Parker
park_with_timeout :: proc(p: ^Parker, duration: time.Duration) { park_with_timeout :: proc "contextless" (p: ^Parker, duration: time.Duration) {
EMPTY :: 0 EMPTY :: 0
NOTIFIED :: 1 NOTIFIED :: 1
PARKED :: max(u32) PARKED :: max(u32)
@@ -345,7 +345,7 @@ park_with_timeout :: proc(p: ^Parker, duration: time.Duration) {
} }
// Automatically makes thee token available if it was not already. // Automatically makes thee token available if it was not already.
unpark :: proc(p: ^Parker) { unpark :: proc "contextless" (p: ^Parker) {
EMPTY :: 0 EMPTY :: 0
NOTIFIED :: 1 NOTIFIED :: 1
PARKED :: max(Futex) PARKED :: max(Futex)
+7 -7
View File
@@ -24,11 +24,11 @@ EINTR :: -4
EFAULT :: -14 EFAULT :: -14
ETIMEDOUT :: -60 ETIMEDOUT :: -60
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool { _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
return _futex_wait_with_timeout(f, expected, 0) return _futex_wait_with_timeout(f, expected, 0)
} }
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
timeout_ns := u32(duration) * 1000 timeout_ns := u32(duration) * 1000
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns) s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
@@ -41,13 +41,13 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
case ETIMEDOUT: case ETIMEDOUT:
return false return false
case: case:
panic("futex_wait failure") _panic("futex_wait failure")
} }
return true return true
} }
_futex_signal :: proc(f: ^Futex) { _futex_signal :: proc "contextless" (f: ^Futex) {
loop: for { loop: for {
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0) s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
if s >= 0 { if s >= 0 {
@@ -59,12 +59,12 @@ _futex_signal :: proc(f: ^Futex) {
case ENOENT: case ENOENT:
return return
case: case:
panic("futex_wake_single failure") _panic("futex_wake_single failure")
} }
} }
} }
_futex_broadcast :: proc(f: ^Futex) { _futex_broadcast :: proc "contextless" (f: ^Futex) {
loop: for { loop: for {
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0) s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
if s >= 0 { if s >= 0 {
@@ -76,7 +76,7 @@ _futex_broadcast :: proc(f: ^Futex) {
case ENOENT: case ENOENT:
return return
case: case:
panic("futex_wake_all failure") _panic("futex_wake_all failure")
} }
} }
} }
+8 -8
View File
@@ -17,7 +17,7 @@ foreign libc {
__error :: proc "c" () -> ^c.int --- __error :: proc "c" () -> ^c.int ---
} }
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool { _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
timeout := [2]i64{14400, 0} // 4 hours timeout := [2]i64{14400, 0} // 4 hours
for { for {
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout) res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
@@ -30,12 +30,12 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
continue continue
} }
panic("_futex_wait failure") _panic("_futex_wait failure")
} }
unreachable() unreachable()
} }
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
if duration <= 0 { if duration <= 0 {
return false return false
} }
@@ -51,21 +51,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
return false return false
} }
panic("_futex_wait_with_timeout failure") _panic("_futex_wait_with_timeout failure")
} }
_futex_signal :: proc(f: ^Futex) { _futex_signal :: proc "contextless" (f: ^Futex) {
res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil) res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil)
if res == -1 { if res == -1 {
panic("_futex_signal failure") _panic("_futex_signal failure")
} }
} }
_futex_broadcast :: proc(f: ^Futex) { _futex_broadcast :: proc "contextless" (f: ^Futex) {
res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil) res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil)
if res == -1 { if res == -1 {
panic("_futex_broadcast failure") _panic("_futex_broadcast failure")
} }
} }
+10 -10
View File
@@ -21,20 +21,20 @@ EFAULT :: -14
EINVAL :: -22 EINVAL :: -22
ETIMEDOUT :: -110 ETIMEDOUT :: -110
get_errno :: proc(r: int) -> int { get_errno :: proc "contextless" (r: int) -> int {
if -4096 < r && r < 0 { if -4096 < r && r < 0 {
return r return r
} }
return 0 return 0
} }
internal_futex :: proc(f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int { internal_futex :: proc "contextless" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int {
code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0)) code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0))
return get_errno(code) return get_errno(code)
} }
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool { _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil) err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil)
switch err { switch err {
case ESUCCESS, EINTR, EAGAIN, EINVAL: case ESUCCESS, EINTR, EAGAIN, EINVAL:
@@ -44,12 +44,12 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
case EFAULT: case EFAULT:
fallthrough fallthrough
case: case:
panic("futex_wait failure") _panic("futex_wait failure")
} }
return true return true
} }
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
if duration <= 0 { if duration <= 0 {
return false return false
} }
@@ -71,27 +71,27 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
case EFAULT: case EFAULT:
fallthrough fallthrough
case: case:
panic("futex_wait_with_timeout failure") _panic("futex_wait_with_timeout failure")
} }
return true return true
} }
_futex_signal :: proc(f: ^Futex) { _futex_signal :: proc "contextless" (f: ^Futex) {
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil) err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil)
switch err { switch err {
case ESUCCESS, EINVAL, EFAULT: case ESUCCESS, EINVAL, EFAULT:
// okay // okay
case: case:
panic("futex_wake_single failure") _panic("futex_wake_single failure")
} }
} }
_futex_broadcast :: proc(f: ^Futex) { _futex_broadcast :: proc "contextless" (f: ^Futex) {
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil) err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil)
switch err { switch err {
case ESUCCESS, EINVAL, EFAULT: case ESUCCESS, EINVAL, EFAULT:
// okay // okay
case: case:
panic("_futex_wake_all failure") _panic("_futex_wake_all failure")
} }
} }
+8 -8
View File
@@ -21,7 +21,7 @@ foreign libc {
_unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int --- _unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
} }
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool { _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil) res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil)
if res != -1 { if res != -1 {
@@ -32,10 +32,10 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
return false return false
} }
panic("futex_wait failure") _panic("futex_wait failure")
} }
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
if duration <= 0 { if duration <= 0 {
return false return false
} }
@@ -58,21 +58,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
return false return false
} }
panic("futex_wait_with_timeout failure") _panic("futex_wait_with_timeout failure")
} }
_futex_signal :: proc(f: ^Futex) { _futex_signal :: proc "contextless" (f: ^Futex) {
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil) res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
if res == -1 { if res == -1 {
panic("futex_wake_single failure") _panic("futex_wake_single failure")
} }
} }
_futex_broadcast :: proc(f: ^Futex) { _futex_broadcast :: proc "contextless" (f: ^Futex) {
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil) res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
if res == -1 { if res == -1 {
panic("_futex_wake_all failure") _panic("_futex_wake_all failure")
} }
} }
+4 -4
View File
@@ -5,18 +5,18 @@ package sync
import "core:intrinsics" import "core:intrinsics"
import "core:time" import "core:time"
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool { _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1) s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
return s != 0 return s != 0
} }
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration)) s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
return s != 0 return s != 0
} }
_futex_signal :: proc(f: ^Futex) { _futex_signal :: proc "contextless" (f: ^Futex) {
loop: for { loop: for {
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1) s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
if s >= 1 { if s >= 1 {
@@ -25,7 +25,7 @@ _futex_signal :: proc(f: ^Futex) {
} }
} }
_futex_broadcast :: proc(f: ^Futex) { _futex_broadcast :: proc "contextless" (f: ^Futex) {
loop: for { loop: for {
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0)) s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
if s >= 0 { if s >= 0 {
+4 -4
View File
@@ -39,22 +39,22 @@ CustomWaitOnAddress :: proc "stdcall" (Address: rawptr, CompareAddress: rawptr,
} }
_futex_wait :: proc(f: ^Futex, expect: u32) -> bool { _futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> bool {
expect := expect expect := expect
return CustomWaitOnAddress(f, &expect, size_of(expect), nil) return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
} }
_futex_wait_with_timeout :: proc(f: ^Futex, expect: u32, duration: time.Duration) -> bool { _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> bool {
expect := expect expect := expect
// NOTE(bill): for some bizarre reason, this has be a negative number // NOTE(bill): for some bizarre reason, this has be a negative number
timeout := -i64(duration / 100) timeout := -i64(duration / 100)
return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout) return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
} }
_futex_signal :: proc(f: ^Futex) { _futex_signal :: proc "contextless" (f: ^Futex) {
WakeByAddressSingle(f) WakeByAddressSingle(f)
} }
_futex_broadcast :: proc(f: ^Futex) { _futex_broadcast :: proc "contextless" (f: ^Futex) {
WakeByAddressAll(f) WakeByAddressAll(f)
} }
+44 -28
View File
@@ -1,5 +1,6 @@
package sync package sync
import "core:runtime"
import "core:time" import "core:time"
current_thread_id :: proc "contextless" () -> int { current_thread_id :: proc "contextless" () -> int {
@@ -15,17 +16,17 @@ Mutex :: struct {
} }
// mutex_lock locks m // mutex_lock locks m
mutex_lock :: proc(m: ^Mutex) { mutex_lock :: proc "contextless" (m: ^Mutex) {
_mutex_lock(m) _mutex_lock(m)
} }
// mutex_unlock unlocks m // mutex_unlock unlocks m
mutex_unlock :: proc(m: ^Mutex) { mutex_unlock :: proc "contextless" (m: ^Mutex) {
_mutex_unlock(m) _mutex_unlock(m)
} }
// mutex_try_lock tries to lock m, will return true on success, and false on failure // mutex_try_lock tries to lock m, will return true on success, and false on failure
mutex_try_lock :: proc(m: ^Mutex) -> bool { mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
return _mutex_try_lock(m) return _mutex_try_lock(m)
} }
@@ -36,7 +37,7 @@ Example:
} }
*/ */
@(deferred_in=mutex_unlock) @(deferred_in=mutex_unlock)
mutex_guard :: proc(m: ^Mutex) -> bool { mutex_guard :: proc "contextless" (m: ^Mutex) -> bool {
mutex_lock(m) mutex_lock(m)
return true return true
} }
@@ -52,32 +53,32 @@ RW_Mutex :: struct {
// rw_mutex_lock locks rw for writing (with a single writer) // 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. // 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 :: proc "contextless" (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 unlocks rw for writing (with a single writer)
rw_mutex_unlock :: proc(rw: ^RW_Mutex) { rw_mutex_unlock :: proc "contextless" (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 tries to lock rw for writing (with a single writer)
rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool { rw_mutex_try_lock :: proc "contextless" (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 locks rw for reading (with arbitrary number of readers)
rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) { rw_mutex_shared_lock :: proc "contextless" (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 unlocks rw for reading (with arbitrary number of readers)
rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) { rw_mutex_shared_unlock :: proc "contextless" (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 tries to lock rw for reading (with arbitrary number of readers)
rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool { rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return _rw_mutex_try_shared_lock(rw) return _rw_mutex_try_shared_lock(rw)
} }
/* /*
@@ -87,7 +88,7 @@ Example:
} }
*/ */
@(deferred_in=rw_mutex_unlock) @(deferred_in=rw_mutex_unlock)
rw_mutex_guard :: proc(m: ^RW_Mutex) -> bool { rw_mutex_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {
rw_mutex_lock(m) rw_mutex_lock(m)
return true return true
} }
@@ -99,7 +100,7 @@ Example:
} }
*/ */
@(deferred_in=rw_mutex_shared_unlock) @(deferred_in=rw_mutex_shared_unlock)
rw_mutex_shared_guard :: proc(m: ^RW_Mutex) -> bool { rw_mutex_shared_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {
rw_mutex_shared_lock(m) rw_mutex_shared_lock(m)
return true return true
} }
@@ -114,15 +115,15 @@ Recursive_Mutex :: struct {
impl: _Recursive_Mutex, impl: _Recursive_Mutex,
} }
recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {
_recursive_mutex_lock(m) _recursive_mutex_lock(m)
} }
recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) { recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) {
_recursive_mutex_unlock(m) _recursive_mutex_unlock(m)
} }
recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool { recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
return _recursive_mutex_try_lock(m) return _recursive_mutex_try_lock(m)
} }
@@ -133,7 +134,7 @@ Example:
} }
*/ */
@(deferred_in=recursive_mutex_unlock) @(deferred_in=recursive_mutex_unlock)
recursive_mutex_guard :: proc(m: ^Recursive_Mutex) -> bool { recursive_mutex_guard :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
recursive_mutex_lock(m) recursive_mutex_lock(m)
return true return true
} }
@@ -147,22 +148,22 @@ Cond :: struct {
impl: _Cond, impl: _Cond,
} }
cond_wait :: proc(c: ^Cond, m: ^Mutex) { cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
_cond_wait(c, m) _cond_wait(c, m)
} }
cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
if duration <= 0 { if duration <= 0 {
return false return false
} }
return _cond_wait_with_timeout(c, m, duration) return _cond_wait_with_timeout(c, m, duration)
} }
cond_signal :: proc(c: ^Cond) { cond_signal :: proc "contextless" (c: ^Cond) {
_cond_signal(c) _cond_signal(c)
} }
cond_broadcast :: proc(c: ^Cond) { cond_broadcast :: proc "contextless" (c: ^Cond) {
_cond_broadcast(c) _cond_broadcast(c)
} }
@@ -175,15 +176,15 @@ Sema :: struct {
impl: _Sema, impl: _Sema,
} }
sema_post :: proc(s: ^Sema, count := 1) { sema_post :: proc "contextless" (s: ^Sema, count := 1) {
_sema_post(s, count) _sema_post(s, count)
} }
sema_wait :: proc(s: ^Sema) { sema_wait :: proc "contextless" (s: ^Sema) {
_sema_wait(s) _sema_wait(s)
} }
sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool { sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {
return _sema_wait_with_timeout(s, duration) return _sema_wait_with_timeout(s, duration)
} }
@@ -194,16 +195,16 @@ sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
// An Futex must not be copied after first use // An Futex must not be copied after first use
Futex :: distinct u32 Futex :: distinct u32
futex_wait :: proc(f: ^Futex, expected: u32) { futex_wait :: proc "contextless" (f: ^Futex, expected: u32) {
if u32(atomic_load_explicit(f, .Acquire)) != expected { if u32(atomic_load_explicit(f, .Acquire)) != expected {
return return
} }
assert(_futex_wait(f, expected), "futex_wait failure") _assert(_futex_wait(f, expected), "futex_wait failure")
} }
// returns true if the wait happened within the duration, false if it exceeded the time duration // returns true if the wait happened within the duration, false if it exceeded the time duration
futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
if u32(atomic_load_explicit(f, .Acquire)) != expected { if u32(atomic_load_explicit(f, .Acquire)) != expected {
return true return true
} }
@@ -214,10 +215,25 @@ futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duratio
return _futex_wait_with_timeout(f, expected, duration) return _futex_wait_with_timeout(f, expected, duration)
} }
futex_signal :: proc(f: ^Futex) { futex_signal :: proc "contextless" (f: ^Futex) {
_futex_signal(f) _futex_signal(f)
} }
futex_broadcast :: proc(f: ^Futex) { futex_broadcast :: proc "contextless" (f: ^Futex) {
_futex_broadcast(f) _futex_broadcast(f)
} }
@(private)
_assert :: proc "contextless" (cond: bool, msg: string) {
if !cond {
_panic(msg)
}
}
@(private)
_panic :: proc "contextless" (msg: string) -> ! {
runtime.print_string(msg)
runtime.print_byte('\n')
runtime.trap()
}
+26 -26
View File
@@ -18,9 +18,9 @@ Atomic_Mutex :: struct {
} }
// atomic_mutex_lock locks m // atomic_mutex_lock locks m
atomic_mutex_lock :: proc(m: ^Atomic_Mutex) { atomic_mutex_lock :: proc "contextless" (m: ^Atomic_Mutex) {
@(cold) @(cold)
lock_slow :: proc(m: ^Atomic_Mutex, curr_state: Atomic_Mutex_State) { lock_slow :: proc "contextless" (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) { spin_lock: for spin in 0..<i32(100) {
@@ -58,9 +58,9 @@ atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
} }
// atomic_mutex_unlock unlocks m // atomic_mutex_unlock unlocks m
atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) { atomic_mutex_unlock :: proc "contextless" (m: ^Atomic_Mutex) {
@(cold) @(cold)
unlock_slow :: proc(m: ^Atomic_Mutex) { unlock_slow :: proc "contextless" (m: ^Atomic_Mutex) {
futex_signal((^Futex)(&m.state)) futex_signal((^Futex)(&m.state))
} }
@@ -76,7 +76,7 @@ atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) {
} }
// atomic_mutex_try_lock tries to lock m, will return true on success, and false on failure // 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 { atomic_mutex_try_lock :: proc "contextless" (m: ^Atomic_Mutex) -> bool {
_, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .Acquire, .Consume) _, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .Acquire, .Consume)
return ok return ok
} }
@@ -88,7 +88,7 @@ Example:
} }
*/ */
@(deferred_in=atomic_mutex_unlock) @(deferred_in=atomic_mutex_unlock)
atomic_mutex_guard :: proc(m: ^Atomic_Mutex) -> bool { atomic_mutex_guard :: proc "contextless" (m: ^Atomic_Mutex) -> bool {
atomic_mutex_lock(m) atomic_mutex_lock(m)
return true return true
} }
@@ -117,7 +117,7 @@ Atomic_RW_Mutex :: struct {
// atomic_rw_mutex_lock locks rw for writing (with a single writer) // 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. // 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_rw_mutex_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Writer) _ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Writer)
atomic_mutex_lock(&rw.mutex) atomic_mutex_lock(&rw.mutex)
@@ -128,13 +128,13 @@ atomic_rw_mutex_lock :: proc(rw: ^Atomic_RW_Mutex) {
} }
// atomic_rw_mutex_unlock unlocks rw for writing (with a single writer) // atomic_rw_mutex_unlock unlocks rw for writing (with a single writer)
atomic_rw_mutex_unlock :: proc(rw: ^Atomic_RW_Mutex) { atomic_rw_mutex_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
_ = atomic_and(&rw.state, ~Atomic_RW_Mutex_State_Is_Writing) _ = atomic_and(&rw.state, ~Atomic_RW_Mutex_State_Is_Writing)
atomic_mutex_unlock(&rw.mutex) 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 tries to lock rw for writing (with a single writer)
atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool { atomic_rw_mutex_try_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
if atomic_mutex_try_lock(&rw.mutex) { 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 { if state & Atomic_RW_Mutex_State_Reader_Mask == 0 {
@@ -148,7 +148,7 @@ atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
} }
// atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers) // atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex) { atomic_rw_mutex_shared_lock :: proc "contextless" (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 { for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
ok: bool ok: bool
@@ -164,7 +164,7 @@ atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex) {
} }
// atomic_rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers) // atomic_rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex) { atomic_rw_mutex_shared_unlock :: proc "contextless" (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) && if (state & Atomic_RW_Mutex_State_Reader_Mask == Atomic_RW_Mutex_State_Reader) &&
@@ -174,7 +174,7 @@ atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex) {
} }
// atomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers) // 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 { atomic_rw_mutex_try_shared_lock :: proc "contextless" (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 { 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)
@@ -198,7 +198,7 @@ Example:
} }
*/ */
@(deferred_in=atomic_rw_mutex_unlock) @(deferred_in=atomic_rw_mutex_unlock)
atomic_rw_mutex_guard :: proc(m: ^Atomic_RW_Mutex) -> bool { atomic_rw_mutex_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {
atomic_rw_mutex_lock(m) atomic_rw_mutex_lock(m)
return true return true
} }
@@ -210,7 +210,7 @@ Example:
} }
*/ */
@(deferred_in=atomic_rw_mutex_shared_unlock) @(deferred_in=atomic_rw_mutex_shared_unlock)
atomic_rw_mutex_shared_guard :: proc(m: ^Atomic_RW_Mutex) -> bool { atomic_rw_mutex_shared_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {
atomic_rw_mutex_shared_lock(m) atomic_rw_mutex_shared_lock(m)
return true return true
} }
@@ -228,7 +228,7 @@ Atomic_Recursive_Mutex :: struct {
mutex: Mutex, mutex: Mutex,
} }
atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) { atomic_recursive_mutex_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
tid := current_thread_id() tid := current_thread_id()
if tid != m.owner { if tid != m.owner {
mutex_lock(&m.mutex) mutex_lock(&m.mutex)
@@ -238,9 +238,9 @@ atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) {
m.recursion += 1 m.recursion += 1
} }
atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex) { atomic_recursive_mutex_unlock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
tid := current_thread_id() tid := current_thread_id()
assert(tid == m.owner) _assert(tid == m.owner, "tid != m.owner")
m.recursion -= 1 m.recursion -= 1
recursion := m.recursion recursion := m.recursion
if recursion == 0 { if recursion == 0 {
@@ -253,7 +253,7 @@ atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex) {
} }
atomic_recursive_mutex_try_lock :: proc(m: ^Atomic_Recursive_Mutex) -> bool { atomic_recursive_mutex_try_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {
tid := current_thread_id() tid := current_thread_id()
if m.owner == tid { if m.owner == tid {
return mutex_try_lock(&m.mutex) return mutex_try_lock(&m.mutex)
@@ -274,7 +274,7 @@ Example:
} }
*/ */
@(deferred_in=atomic_recursive_mutex_unlock) @(deferred_in=atomic_recursive_mutex_unlock)
atomic_recursive_mutex_guard :: proc(m: ^Atomic_Recursive_Mutex) -> bool { atomic_recursive_mutex_guard :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {
atomic_recursive_mutex_lock(m) atomic_recursive_mutex_lock(m)
return true return true
} }
@@ -289,7 +289,7 @@ Atomic_Cond :: struct {
state: Futex, state: Futex,
} }
atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) { atomic_cond_wait :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex) {
state := u32(atomic_load_explicit(&c.state, .Relaxed)) state := u32(atomic_load_explicit(&c.state, .Relaxed))
unlock(m) unlock(m)
futex_wait(&c.state, state) futex_wait(&c.state, state)
@@ -297,7 +297,7 @@ atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) {
} }
atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) { atomic_cond_wait_with_timeout :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) {
state := u32(atomic_load_explicit(&c.state, .Relaxed)) state := u32(atomic_load_explicit(&c.state, .Relaxed))
unlock(m) unlock(m)
ok = futex_wait_with_timeout(&c.state, state, duration) ok = futex_wait_with_timeout(&c.state, state, duration)
@@ -306,12 +306,12 @@ atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duratio
} }
atomic_cond_signal :: proc(c: ^Atomic_Cond) { atomic_cond_signal :: proc "contextless" (c: ^Atomic_Cond) {
atomic_add_explicit(&c.state, 1, .Release) atomic_add_explicit(&c.state, 1, .Release)
futex_signal(&c.state) futex_signal(&c.state)
} }
atomic_cond_broadcast :: proc(c: ^Atomic_Cond) { atomic_cond_broadcast :: proc "contextless" (c: ^Atomic_Cond) {
atomic_add_explicit(&c.state, 1, .Release) atomic_add_explicit(&c.state, 1, .Release)
futex_broadcast(&c.state) futex_broadcast(&c.state)
} }
@@ -324,7 +324,7 @@ Atomic_Sema :: struct {
count: Futex, count: Futex,
} }
atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) { atomic_sema_post :: proc "contextless" (s: ^Atomic_Sema, count := 1) {
atomic_add_explicit(&s.count, Futex(count), .Release) atomic_add_explicit(&s.count, Futex(count), .Release)
if count == 1 { if count == 1 {
futex_signal(&s.count) futex_signal(&s.count)
@@ -333,7 +333,7 @@ atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) {
} }
} }
atomic_sema_wait :: proc(s: ^Atomic_Sema) { atomic_sema_wait :: proc "contextless" (s: ^Atomic_Sema) {
for { for {
original_count := atomic_load_explicit(&s.count, .Relaxed) original_count := atomic_load_explicit(&s.count, .Relaxed)
for original_count == 0 { for original_count == 0 {
@@ -346,7 +346,7 @@ atomic_sema_wait :: proc(s: ^Atomic_Sema) {
} }
} }
atomic_sema_wait_with_timeout :: proc(s: ^Atomic_Sema, duration: time.Duration) -> bool { atomic_sema_wait_with_timeout :: proc "contextless" (s: ^Atomic_Sema, duration: time.Duration) -> bool {
if duration <= 0 { if duration <= 0 {
return false return false
} }
+19 -19
View File
@@ -7,15 +7,15 @@ _Sema :: struct {
atomic: Atomic_Sema, atomic: Atomic_Sema,
} }
_sema_post :: proc(s: ^Sema, count := 1) { _sema_post :: proc "contextless" (s: ^Sema, count := 1) {
atomic_sema_post(&s.impl.atomic, count) atomic_sema_post(&s.impl.atomic, count)
} }
_sema_wait :: proc(s: ^Sema) { _sema_wait :: proc "contextless" (s: ^Sema) {
atomic_sema_wait(&s.impl.atomic) atomic_sema_wait(&s.impl.atomic)
} }
_sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool { _sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {
return atomic_sema_wait_with_timeout(&s.impl.atomic, duration) return atomic_sema_wait_with_timeout(&s.impl.atomic, duration)
} }
@@ -25,7 +25,7 @@ _Recursive_Mutex :: struct {
recursion: i32, recursion: i32,
} }
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { _recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {
tid := Futex(current_thread_id()) tid := Futex(current_thread_id())
for { for {
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire) prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
@@ -40,7 +40,7 @@ _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
} }
} }
_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) { _recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) {
m.impl.recursion -= 1 m.impl.recursion -= 1
if m.impl.recursion != 0 { if m.impl.recursion != 0 {
return return
@@ -52,7 +52,7 @@ _recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
} }
_recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool { _recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
tid := Futex(current_thread_id()) tid := Futex(current_thread_id())
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire) prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
switch prev_owner { switch prev_owner {
@@ -70,15 +70,15 @@ when ODIN_OS != .Windows {
mutex: Atomic_Mutex, mutex: Atomic_Mutex,
} }
_mutex_lock :: proc(m: ^Mutex) { _mutex_lock :: proc "contextless" (m: ^Mutex) {
atomic_mutex_lock(&m.impl.mutex) atomic_mutex_lock(&m.impl.mutex)
} }
_mutex_unlock :: proc(m: ^Mutex) { _mutex_unlock :: proc "contextless" (m: ^Mutex) {
atomic_mutex_unlock(&m.impl.mutex) atomic_mutex_unlock(&m.impl.mutex)
} }
_mutex_try_lock :: proc(m: ^Mutex) -> bool { _mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
return atomic_mutex_try_lock(&m.impl.mutex) return atomic_mutex_try_lock(&m.impl.mutex)
} }
@@ -86,19 +86,19 @@ when ODIN_OS != .Windows {
cond: Atomic_Cond, cond: Atomic_Cond,
} }
_cond_wait :: proc(c: ^Cond, m: ^Mutex) { _cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
atomic_cond_wait(&c.impl.cond, &m.impl.mutex) atomic_cond_wait(&c.impl.cond, &m.impl.mutex)
} }
_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { _cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration) return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration)
} }
_cond_signal :: proc(c: ^Cond) { _cond_signal :: proc "contextless" (c: ^Cond) {
atomic_cond_signal(&c.impl.cond) atomic_cond_signal(&c.impl.cond)
} }
_cond_broadcast :: proc(c: ^Cond) { _cond_broadcast :: proc "contextless" (c: ^Cond) {
atomic_cond_broadcast(&c.impl.cond) atomic_cond_broadcast(&c.impl.cond)
} }
@@ -107,27 +107,27 @@ when ODIN_OS != .Windows {
mutex: Atomic_RW_Mutex, mutex: Atomic_RW_Mutex,
} }
_rw_mutex_lock :: proc(rw: ^RW_Mutex) { _rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
atomic_rw_mutex_lock(&rw.impl.mutex) atomic_rw_mutex_lock(&rw.impl.mutex)
} }
_rw_mutex_unlock :: proc(rw: ^RW_Mutex) { _rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
atomic_rw_mutex_unlock(&rw.impl.mutex) atomic_rw_mutex_unlock(&rw.impl.mutex)
} }
_rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool { _rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return atomic_rw_mutex_try_lock(&rw.impl.mutex) return atomic_rw_mutex_try_lock(&rw.impl.mutex)
} }
_rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) { _rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
atomic_rw_mutex_shared_lock(&rw.impl.mutex) atomic_rw_mutex_shared_lock(&rw.impl.mutex)
} }
_rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) { _rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
atomic_rw_mutex_shared_unlock(&rw.impl.mutex) atomic_rw_mutex_shared_unlock(&rw.impl.mutex)
} }
_rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool { _rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return atomic_rw_mutex_try_shared_lock(&rw.impl.mutex) return atomic_rw_mutex_try_shared_lock(&rw.impl.mutex)
} }
} }
+13 -13
View File
@@ -13,15 +13,15 @@ _Mutex :: struct {
srwlock: win32.SRWLOCK, srwlock: win32.SRWLOCK,
} }
_mutex_lock :: proc(m: ^Mutex) { _mutex_lock :: proc "contextless" (m: ^Mutex) {
win32.AcquireSRWLockExclusive(&m.impl.srwlock) win32.AcquireSRWLockExclusive(&m.impl.srwlock)
} }
_mutex_unlock :: proc(m: ^Mutex) { _mutex_unlock :: proc "contextless" (m: ^Mutex) {
win32.ReleaseSRWLockExclusive(&m.impl.srwlock) win32.ReleaseSRWLockExclusive(&m.impl.srwlock)
} }
_mutex_try_lock :: proc(m: ^Mutex) -> bool { _mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
return bool(win32.TryAcquireSRWLockExclusive(&m.impl.srwlock)) return bool(win32.TryAcquireSRWLockExclusive(&m.impl.srwlock))
} }
@@ -29,27 +29,27 @@ _RW_Mutex :: struct {
srwlock: win32.SRWLOCK, srwlock: win32.SRWLOCK,
} }
_rw_mutex_lock :: proc(rw: ^RW_Mutex) { _rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
win32.AcquireSRWLockExclusive(&rw.impl.srwlock) win32.AcquireSRWLockExclusive(&rw.impl.srwlock)
} }
_rw_mutex_unlock :: proc(rw: ^RW_Mutex) { _rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
win32.ReleaseSRWLockExclusive(&rw.impl.srwlock) win32.ReleaseSRWLockExclusive(&rw.impl.srwlock)
} }
_rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool { _rw_mutex_try_lock :: proc "contextless" (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) { _rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
win32.AcquireSRWLockShared(&rw.impl.srwlock) win32.AcquireSRWLockShared(&rw.impl.srwlock)
} }
_rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) { _rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
win32.ReleaseSRWLockShared(&rw.impl.srwlock) win32.ReleaseSRWLockShared(&rw.impl.srwlock)
} }
_rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool { _rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return bool(win32.TryAcquireSRWLockShared(&rw.impl.srwlock)) return bool(win32.TryAcquireSRWLockShared(&rw.impl.srwlock))
} }
@@ -58,22 +58,22 @@ _Cond :: struct {
cond: win32.CONDITION_VARIABLE, cond: win32.CONDITION_VARIABLE,
} }
_cond_wait :: proc(c: ^Cond, m: ^Mutex) { _cond_wait :: proc "contextless" (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, duration: time.Duration) -> bool { _cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
duration := u32(duration / time.Millisecond) duration := u32(duration / time.Millisecond)
ok := win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, duration, 0) ok := win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, duration, 0)
return bool(ok) return bool(ok)
} }
_cond_signal :: proc(c: ^Cond) { _cond_signal :: proc "contextless" (c: ^Cond) {
win32.WakeConditionVariable(&c.impl.cond) win32.WakeConditionVariable(&c.impl.cond)
} }
_cond_broadcast :: proc(c: ^Cond) { _cond_broadcast :: proc "contextless" (c: ^Cond) {
win32.WakeAllConditionVariable(&c.impl.cond) win32.WakeAllConditionVariable(&c.impl.cond)
} }