mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-27 18:00:05 +00:00
Merge branch 'master' into file-tags-without-comments
This commit is contained in:
+42
-41
@@ -22,19 +22,17 @@ Raw_Chan :: struct {
|
||||
allocator: runtime.Allocator,
|
||||
allocation_size: int,
|
||||
msg_size: u16,
|
||||
closed: b16, // atomic
|
||||
closed: b16, // guarded by `mutex`
|
||||
mutex: sync.Mutex,
|
||||
r_cond: sync.Cond,
|
||||
w_cond: sync.Cond,
|
||||
r_waiting: int, // atomic
|
||||
w_waiting: int, // atomic
|
||||
r_waiting: int, // guarded by `mutex`
|
||||
w_waiting: int, // guarded by `mutex`
|
||||
|
||||
// Buffered
|
||||
queue: ^Raw_Queue,
|
||||
|
||||
// Unbuffered
|
||||
r_mutex: sync.Mutex,
|
||||
w_mutex: sync.Mutex,
|
||||
unbuffered_data: rawptr,
|
||||
}
|
||||
|
||||
@@ -164,27 +162,30 @@ send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool) {
|
||||
}
|
||||
if c.queue != nil { // buffered
|
||||
sync.guard(&c.mutex)
|
||||
for c.queue.len == c.queue.cap {
|
||||
sync.atomic_add(&c.w_waiting, 1)
|
||||
for !c.closed && c.queue.len == c.queue.cap {
|
||||
c.w_waiting += 1
|
||||
sync.wait(&c.w_cond, &c.mutex)
|
||||
sync.atomic_sub(&c.w_waiting, 1)
|
||||
c.w_waiting -= 1
|
||||
}
|
||||
|
||||
if c.closed {
|
||||
return false
|
||||
}
|
||||
|
||||
ok = raw_queue_push(c.queue, msg_in)
|
||||
if sync.atomic_load(&c.r_waiting) > 0 {
|
||||
if c.r_waiting > 0 {
|
||||
sync.signal(&c.r_cond)
|
||||
}
|
||||
} else if c.unbuffered_data != nil { // unbuffered
|
||||
sync.guard(&c.w_mutex)
|
||||
sync.guard(&c.mutex)
|
||||
|
||||
if sync.atomic_load(&c.closed) {
|
||||
if c.closed {
|
||||
return false
|
||||
}
|
||||
|
||||
mem.copy(c.unbuffered_data, msg_in, int(c.msg_size))
|
||||
sync.atomic_add(&c.w_waiting, 1)
|
||||
if sync.atomic_load(&c.r_waiting) > 0 {
|
||||
c.w_waiting += 1
|
||||
if c.r_waiting > 0 {
|
||||
sync.signal(&c.r_cond)
|
||||
}
|
||||
sync.wait(&c.w_cond, &c.mutex)
|
||||
@@ -201,13 +202,13 @@ recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) {
|
||||
if c.queue != nil { // buffered
|
||||
sync.guard(&c.mutex)
|
||||
for c.queue.len == 0 {
|
||||
if sync.atomic_load(&c.closed) {
|
||||
if c.closed {
|
||||
return
|
||||
}
|
||||
|
||||
sync.atomic_add(&c.r_waiting, 1)
|
||||
c.r_waiting += 1
|
||||
sync.wait(&c.r_cond, &c.mutex)
|
||||
sync.atomic_sub(&c.r_waiting, 1)
|
||||
c.r_waiting -= 1
|
||||
}
|
||||
|
||||
msg := raw_queue_pop(c.queue)
|
||||
@@ -215,27 +216,26 @@ recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) {
|
||||
mem.copy(msg_out, msg, int(c.msg_size))
|
||||
}
|
||||
|
||||
if sync.atomic_load(&c.w_waiting) > 0 {
|
||||
if c.w_waiting > 0 {
|
||||
sync.signal(&c.w_cond)
|
||||
}
|
||||
ok = true
|
||||
} else if c.unbuffered_data != nil { // unbuffered
|
||||
sync.guard(&c.r_mutex)
|
||||
sync.guard(&c.mutex)
|
||||
|
||||
for !sync.atomic_load(&c.closed) &&
|
||||
sync.atomic_load(&c.w_waiting) == 0 {
|
||||
sync.atomic_add(&c.r_waiting, 1)
|
||||
for !c.closed &&
|
||||
c.w_waiting == 0 {
|
||||
c.r_waiting += 1
|
||||
sync.wait(&c.r_cond, &c.mutex)
|
||||
sync.atomic_sub(&c.r_waiting, 1)
|
||||
c.r_waiting -= 1
|
||||
}
|
||||
|
||||
if sync.atomic_load(&c.closed) {
|
||||
if c.closed {
|
||||
return
|
||||
}
|
||||
|
||||
mem.copy(msg_out, c.unbuffered_data, int(c.msg_size))
|
||||
sync.atomic_sub(&c.w_waiting, 1)
|
||||
c.w_waiting -= 1
|
||||
|
||||
sync.signal(&c.w_cond)
|
||||
ok = true
|
||||
@@ -255,21 +255,24 @@ try_send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool)
|
||||
return false
|
||||
}
|
||||
|
||||
if c.closed {
|
||||
return false
|
||||
}
|
||||
|
||||
ok = raw_queue_push(c.queue, msg_in)
|
||||
if sync.atomic_load(&c.r_waiting) > 0 {
|
||||
if c.r_waiting > 0 {
|
||||
sync.signal(&c.r_cond)
|
||||
}
|
||||
} else if c.unbuffered_data != nil { // unbuffered
|
||||
sync.guard(&c.w_mutex)
|
||||
sync.guard(&c.mutex)
|
||||
|
||||
if sync.atomic_load(&c.closed) {
|
||||
if c.closed {
|
||||
return false
|
||||
}
|
||||
|
||||
mem.copy(c.unbuffered_data, msg_in, int(c.msg_size))
|
||||
sync.atomic_add(&c.w_waiting, 1)
|
||||
if sync.atomic_load(&c.r_waiting) > 0 {
|
||||
c.w_waiting += 1
|
||||
if c.r_waiting > 0 {
|
||||
sync.signal(&c.r_cond)
|
||||
}
|
||||
sync.wait(&c.w_cond, &c.mutex)
|
||||
@@ -294,21 +297,19 @@ try_recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> bool {
|
||||
mem.copy(msg_out, msg, int(c.msg_size))
|
||||
}
|
||||
|
||||
if sync.atomic_load(&c.w_waiting) > 0 {
|
||||
if c.w_waiting > 0 {
|
||||
sync.signal(&c.w_cond)
|
||||
}
|
||||
return true
|
||||
} else if c.unbuffered_data != nil { // unbuffered
|
||||
sync.guard(&c.r_mutex)
|
||||
sync.guard(&c.mutex)
|
||||
|
||||
if sync.atomic_load(&c.closed) ||
|
||||
sync.atomic_load(&c.w_waiting) == 0 {
|
||||
if c.closed || c.w_waiting == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
mem.copy(msg_out, c.unbuffered_data, int(c.msg_size))
|
||||
sync.atomic_sub(&c.w_waiting, 1)
|
||||
c.w_waiting -= 1
|
||||
|
||||
sync.signal(&c.w_cond)
|
||||
return true
|
||||
@@ -351,10 +352,10 @@ close :: proc "contextless" (c: ^Raw_Chan) -> bool {
|
||||
return false
|
||||
}
|
||||
sync.guard(&c.mutex)
|
||||
if sync.atomic_load(&c.closed) {
|
||||
if c.closed {
|
||||
return false
|
||||
}
|
||||
sync.atomic_store(&c.closed, true)
|
||||
c.closed = true
|
||||
sync.broadcast(&c.r_cond)
|
||||
sync.broadcast(&c.w_cond)
|
||||
return true
|
||||
@@ -366,7 +367,7 @@ is_closed :: proc "contextless" (c: ^Raw_Chan) -> bool {
|
||||
return true
|
||||
}
|
||||
sync.guard(&c.mutex)
|
||||
return bool(sync.atomic_load(&c.closed))
|
||||
return bool(c.closed)
|
||||
}
|
||||
|
||||
|
||||
@@ -423,9 +424,9 @@ raw_queue_pop :: proc "contextless" (q: ^Raw_Queue) -> (data: rawptr) {
|
||||
can_recv :: proc "contextless" (c: ^Raw_Chan) -> bool {
|
||||
sync.guard(&c.mutex)
|
||||
if is_buffered(c) {
|
||||
return len(c) > 0
|
||||
return c.queue.len > 0
|
||||
}
|
||||
return sync.atomic_load(&c.w_waiting) > 0
|
||||
return c.w_waiting > 0
|
||||
}
|
||||
|
||||
|
||||
@@ -435,7 +436,7 @@ can_send :: proc "contextless" (c: ^Raw_Chan) -> bool {
|
||||
if is_buffered(c) {
|
||||
return c.queue.len < c.queue.cap
|
||||
}
|
||||
return sync.atomic_load(&c.r_waiting) > 0
|
||||
return c.w_waiting == 0
|
||||
}
|
||||
|
||||
|
||||
@@ -484,4 +485,4 @@ select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs: []
|
||||
ok = send_raw(sends[sel.idx], send_msgs[sel.idx])
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
+38
-37
@@ -8,7 +8,7 @@ _ :: vg
|
||||
Wait group.
|
||||
|
||||
Wait group is a synchronization primitive used by the waiting thread to wait,
|
||||
until a all working threads finish work.
|
||||
until all working threads finish work.
|
||||
|
||||
The waiting thread first sets the number of working threads it will expect to
|
||||
wait for using `wait_group_add` call, and start waiting using `wait_group_wait`
|
||||
@@ -35,7 +35,7 @@ Wait_Group :: struct #no_copy {
|
||||
/*
|
||||
Increment an internal counter of a wait group.
|
||||
|
||||
This procedure atomicaly increments a number to the specified wait group's
|
||||
This procedure atomically increments a number to the specified wait group's
|
||||
internal counter by a specified amount. This operation can be done on any
|
||||
thread.
|
||||
*/
|
||||
@@ -48,12 +48,12 @@ wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) {
|
||||
|
||||
atomic_add(&wg.counter, delta)
|
||||
if wg.counter < 0 {
|
||||
_panic("sync.Wait_Group negative counter")
|
||||
panic_contextless("sync.Wait_Group negative counter")
|
||||
}
|
||||
if wg.counter == 0 {
|
||||
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_contextless("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ wait_group_wait :: proc "contextless" (wg: ^Wait_Group) {
|
||||
if wg.counter != 0 {
|
||||
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_contextless("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ wait_group_wait_with_timeout :: proc "contextless" (wg: ^Wait_Group, duration: t
|
||||
return false
|
||||
}
|
||||
if wg.counter != 0 {
|
||||
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
panic_contextless("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
return true
|
||||
@@ -121,7 +121,7 @@ When `barrier_wait` procedure is called by any thread, that thread will block
|
||||
the execution, until all threads associated with the barrier reach the same
|
||||
point of execution and also call `barrier_wait`.
|
||||
|
||||
when barrier is initialized, a `thread_count` parameter is passed, signifying
|
||||
When a barrier is initialized, a `thread_count` parameter is passed, signifying
|
||||
the amount of participant threads of the barrier. The barrier also keeps track
|
||||
of an internal atomic counter. When a thread calls `barrier_wait`, the internal
|
||||
counter is incremented. When the internal counter reaches `thread_count`, it is
|
||||
@@ -208,7 +208,7 @@ Represents a thread synchronization primitive that, when signalled, releases one
|
||||
single waiting thread and then resets automatically to a state where it can be
|
||||
signalled again.
|
||||
|
||||
When a thread calls `auto_reset_event_wait`, it's execution will be blocked,
|
||||
When a thread calls `auto_reset_event_wait`, its execution will be blocked,
|
||||
until the event is signalled by another thread. The call to
|
||||
`auto_reset_event_signal` wakes up exactly one thread waiting for the event.
|
||||
*/
|
||||
@@ -228,15 +228,15 @@ thread.
|
||||
*/
|
||||
auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) {
|
||||
old_status := atomic_load_explicit(&e.status, .Relaxed)
|
||||
new_status := old_status + 1 if old_status < 1 else 1
|
||||
for {
|
||||
new_status := old_status + 1 if old_status < 1 else 1
|
||||
if _, ok := atomic_compare_exchange_weak_explicit(&e.status, old_status, new_status, .Release, .Relaxed); ok {
|
||||
break
|
||||
}
|
||||
|
||||
if old_status < 0 {
|
||||
sema_post(&e.sema)
|
||||
}
|
||||
cpu_relax()
|
||||
}
|
||||
if old_status < 0 {
|
||||
sema_post(&e.sema)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ waiting to acquire the lock, exactly one of those threads is unblocked and
|
||||
allowed into the critical section.
|
||||
*/
|
||||
ticket_mutex_unlock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
|
||||
atomic_add_explicit(&m.serving, 1, .Relaxed)
|
||||
atomic_add_explicit(&m.serving, 1, .Release)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -331,8 +331,8 @@ Benaphore.
|
||||
|
||||
A benaphore is a combination of an atomic variable and a semaphore that can
|
||||
improve locking efficiency in a no-contention system. Acquiring a benaphore
|
||||
lock doesn't call into an internal semaphore, if no other thread in a middle of
|
||||
a critical section.
|
||||
lock doesn't call into an internal semaphore, if no other thread is in the
|
||||
middle of a critical section.
|
||||
|
||||
Once a lock on a benaphore is acquired by a thread, no other thread is allowed
|
||||
into any critical sections, associted with the same benaphore, until the lock
|
||||
@@ -355,7 +355,7 @@ from entering any critical sections associated with the same benaphore, until
|
||||
until the lock is released.
|
||||
*/
|
||||
benaphore_lock :: proc "contextless" (b: ^Benaphore) {
|
||||
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
||||
if atomic_add_explicit(&b.counter, 1, .Acquire) > 0 {
|
||||
sema_wait(&b.sema)
|
||||
}
|
||||
}
|
||||
@@ -381,10 +381,10 @@ Release a lock on a benaphore.
|
||||
|
||||
This procedure releases a lock on the specified benaphore. If any of the threads
|
||||
are waiting on the lock, exactly one thread is allowed into a critical section
|
||||
associated with the same banaphore.
|
||||
associated with the same benaphore.
|
||||
*/
|
||||
benaphore_unlock :: proc "contextless" (b: ^Benaphore) {
|
||||
if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
|
||||
if atomic_sub_explicit(&b.counter, 1, .Release) > 1 {
|
||||
sema_post(&b.sema)
|
||||
}
|
||||
}
|
||||
@@ -418,8 +418,8 @@ benaphore_guard :: proc "contextless" (m: ^Benaphore) -> bool {
|
||||
/*
|
||||
Recursive benaphore.
|
||||
|
||||
Recurisve benaphore is just like a plain benaphore, except it allows reentrancy
|
||||
into the critical section.
|
||||
A recursive benaphore is just like a plain benaphore, except it allows
|
||||
reentrancy into the critical section.
|
||||
|
||||
When a lock is acquired on a benaphore, all other threads attempting to
|
||||
acquire a lock on the same benaphore will be blocked from any critical sections,
|
||||
@@ -449,13 +449,15 @@ recursive benaphore, until the lock is released.
|
||||
*/
|
||||
recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) {
|
||||
tid := current_thread_id()
|
||||
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
||||
if tid != b.owner {
|
||||
sema_wait(&b.sema)
|
||||
check_owner: if tid != atomic_load_explicit(&b.owner, .Acquire) {
|
||||
atomic_add_explicit(&b.counter, 1, .Relaxed)
|
||||
if _, ok := atomic_compare_exchange_strong_explicit(&b.owner, 0, tid, .Release, .Relaxed); ok {
|
||||
break check_owner
|
||||
}
|
||||
sema_wait(&b.sema)
|
||||
atomic_store_explicit(&b.owner, tid, .Release)
|
||||
}
|
||||
// inside the lock
|
||||
b.owner = tid
|
||||
b.recursion += 1
|
||||
}
|
||||
|
||||
@@ -472,15 +474,14 @@ benaphore, until the lock is released.
|
||||
*/
|
||||
recursive_benaphore_try_lock :: proc "contextless" (b: ^Recursive_Benaphore) -> bool {
|
||||
tid := current_thread_id()
|
||||
if b.owner == tid {
|
||||
atomic_add_explicit(&b.counter, 1, .Acquire)
|
||||
}
|
||||
|
||||
if v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire); v != 0 {
|
||||
check_owner: if tid != atomic_load_explicit(&b.owner, .Acquire) {
|
||||
if _, ok := atomic_compare_exchange_strong_explicit(&b.owner, 0, tid, .Release, .Relaxed); ok {
|
||||
atomic_add_explicit(&b.counter, 1, .Relaxed)
|
||||
break check_owner
|
||||
}
|
||||
return false
|
||||
}
|
||||
// inside the lock
|
||||
b.owner = tid
|
||||
b.recursion += 1
|
||||
return true
|
||||
}
|
||||
@@ -494,14 +495,14 @@ for other threads for entering.
|
||||
*/
|
||||
recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) {
|
||||
tid := current_thread_id()
|
||||
_assert(tid == b.owner, "tid != b.owner")
|
||||
assert_contextless(tid == atomic_load_explicit(&b.owner, .Relaxed), "tid != b.owner")
|
||||
b.recursion -= 1
|
||||
recursion := b.recursion
|
||||
|
||||
if recursion == 0 {
|
||||
b.owner = 0
|
||||
}
|
||||
if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
|
||||
if recursion == 0 {
|
||||
if atomic_sub_explicit(&b.counter, 1, .Relaxed) == 1 {
|
||||
atomic_store_explicit(&b.owner, 0, .Release)
|
||||
} else {
|
||||
sema_post(&b.sema)
|
||||
}
|
||||
}
|
||||
@@ -740,4 +741,4 @@ Make event available.
|
||||
one_shot_event_signal :: proc "contextless" (e: ^One_Shot_Event) {
|
||||
atomic_store_explicit(&e.state, 1, .Release)
|
||||
futex_broadcast(&e.state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ foreign System {
|
||||
// __ulock_wait is not available on 10.15
|
||||
// See https://github.com/odin-lang/Odin/issues/1959
|
||||
__ulock_wait :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_us: u32) -> c.int ---
|
||||
// >= MacOS 11.
|
||||
__ulock_wait2 :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_ns: u64, value2: u64) -> c.int ---
|
||||
__ulock_wake :: proc "c" (operation: u32, addr: rawptr, wake_value: u64) -> c.int ---
|
||||
}
|
||||
|
||||
@@ -48,22 +50,29 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
|
||||
case -ETIMEDOUT:
|
||||
return false
|
||||
case:
|
||||
_panic("darwin.os_sync_wait_on_address_with_timeout failure")
|
||||
panic_contextless("darwin.os_sync_wait_on_address_with_timeout failure")
|
||||
}
|
||||
} else {
|
||||
|
||||
timeout_ns := u32(duration)
|
||||
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
|
||||
when darwin.ULOCK_WAIT_2_AVAILABLE {
|
||||
timeout_ns := u64(duration)
|
||||
s := __ulock_wait2(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns, 0)
|
||||
} else {
|
||||
timeout_us := u32(duration / time.Microsecond)
|
||||
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_us)
|
||||
}
|
||||
|
||||
if s >= 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
switch s {
|
||||
case EINTR, EFAULT:
|
||||
return true
|
||||
case ETIMEDOUT:
|
||||
return false
|
||||
case:
|
||||
_panic("futex_wait failure")
|
||||
panic_contextless("futex_wait failure")
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -83,7 +92,7 @@ _futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
case -ENOENT:
|
||||
return
|
||||
case:
|
||||
_panic("darwin.os_sync_wake_by_address_any failure")
|
||||
panic_contextless("darwin.os_sync_wake_by_address_any failure")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -99,7 +108,7 @@ _futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
case ENOENT:
|
||||
return
|
||||
case:
|
||||
_panic("futex_wake_single failure")
|
||||
panic_contextless("futex_wake_single failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +128,7 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
case -ENOENT:
|
||||
return
|
||||
case:
|
||||
_panic("darwin.os_sync_wake_by_address_all failure")
|
||||
panic_contextless("darwin.os_sync_wake_by_address_all failure")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -135,7 +144,7 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
case ENOENT:
|
||||
return
|
||||
case:
|
||||
_panic("futex_wake_all failure")
|
||||
panic_contextless("futex_wake_all failure")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
continue
|
||||
}
|
||||
|
||||
_panic("_futex_wait failure")
|
||||
panic_contextless("_futex_wait failure")
|
||||
}
|
||||
|
||||
unreachable()
|
||||
@@ -44,14 +44,14 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
|
||||
return false
|
||||
}
|
||||
|
||||
_panic("_futex_wait_with_timeout failure")
|
||||
panic_contextless("_futex_wait_with_timeout failure")
|
||||
}
|
||||
|
||||
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
errno := freebsd._umtx_op(f, .WAKE, 1, nil, nil)
|
||||
|
||||
if errno != nil {
|
||||
_panic("_futex_signal failure")
|
||||
panic_contextless("_futex_signal failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,6 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
errno := freebsd._umtx_op(f, .WAKE, cast(c.ulong)max(i32), nil, nil)
|
||||
|
||||
if errno != nil {
|
||||
_panic("_futex_broadcast failure")
|
||||
panic_contextless("_futex_broadcast failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ _futex_wait :: proc "contextless" (futex: ^Futex, expected: u32) -> bool {
|
||||
return true
|
||||
case:
|
||||
// TODO(flysand): More descriptive panic messages based on the vlaue of `errno`
|
||||
_panic("futex_wait failure")
|
||||
panic_contextless("futex_wait failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ _futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, du
|
||||
case .NONE, .EINTR, .EAGAIN:
|
||||
return true
|
||||
case:
|
||||
_panic("futex_wait_with_timeout failure")
|
||||
panic_contextless("futex_wait_with_timeout failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ _futex_signal :: proc "contextless" (futex: ^Futex) {
|
||||
case .NONE:
|
||||
return
|
||||
case:
|
||||
_panic("futex_wake_single failure")
|
||||
panic_contextless("futex_wake_single failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,6 @@ _futex_broadcast :: proc "contextless" (futex: ^Futex) {
|
||||
case .NONE:
|
||||
return
|
||||
case:
|
||||
_panic("_futex_wake_all failure")
|
||||
panic_contextless("_futex_wake_all failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ _futex_wait :: proc "contextless" (futex: ^Futex, expected: u32) -> bool {
|
||||
case EINTR, EAGAIN:
|
||||
return true
|
||||
case:
|
||||
_panic("futex_wait failure")
|
||||
panic_contextless("futex_wait failure")
|
||||
}
|
||||
}
|
||||
return true
|
||||
@@ -55,7 +55,7 @@ _futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, du
|
||||
case ETIMEDOUT:
|
||||
return false
|
||||
case:
|
||||
_panic("futex_wait_with_timeout failure")
|
||||
panic_contextless("futex_wait_with_timeout failure")
|
||||
}
|
||||
}
|
||||
return true
|
||||
@@ -63,12 +63,12 @@ _futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, du
|
||||
|
||||
_futex_signal :: proc "contextless" (futex: ^Futex) {
|
||||
if _, ok := intrinsics.syscall_bsd(unix.SYS___futex, uintptr(futex), FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); !ok {
|
||||
_panic("futex_wake_single failure")
|
||||
panic_contextless("futex_wake_single failure")
|
||||
}
|
||||
}
|
||||
|
||||
_futex_broadcast :: proc "contextless" (futex: ^Futex) {
|
||||
if _, ok := intrinsics.syscall_bsd(unix.SYS___futex, uintptr(futex), FUTEX_WAKE_PRIVATE, uintptr(max(i32)), 0, 0, 0); !ok {
|
||||
_panic("_futex_wake_all failure")
|
||||
panic_contextless("_futex_wake_all failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_panic("futex_wait failure")
|
||||
panic_contextless("futex_wait failure")
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
@@ -62,14 +62,14 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
|
||||
return false
|
||||
}
|
||||
|
||||
_panic("futex_wait_with_timeout failure")
|
||||
panic_contextless("futex_wait_with_timeout failure")
|
||||
}
|
||||
|
||||
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
|
||||
|
||||
if res == -1 {
|
||||
_panic("futex_wake_single failure")
|
||||
panic_contextless("futex_wake_single failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,6 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
|
||||
|
||||
if res == -1 {
|
||||
_panic("_futex_wake_all failure")
|
||||
panic_contextless("_futex_wake_all failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import "core:time"
|
||||
|
||||
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
when !intrinsics.has_target_feature("atomics") {
|
||||
_panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
} else {
|
||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
||||
return s != 0
|
||||
@@ -19,7 +19,7 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
|
||||
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
when !intrinsics.has_target_feature("atomics") {
|
||||
_panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
} else {
|
||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
|
||||
return s != 0
|
||||
@@ -28,7 +28,7 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
|
||||
|
||||
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
when !intrinsics.has_target_feature("atomics") {
|
||||
_panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
} else {
|
||||
loop: for {
|
||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
||||
@@ -41,7 +41,7 @@ _futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
|
||||
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
when !intrinsics.has_target_feature("atomics") {
|
||||
_panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
} else {
|
||||
loop: for {
|
||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package sync
|
||||
|
||||
import "base:runtime"
|
||||
import "core:time"
|
||||
|
||||
/*
|
||||
@@ -390,7 +389,7 @@ recursive_mutex_guard :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
|
||||
A condition variable.
|
||||
|
||||
`Cond` implements a condition variable, a rendezvous point for threads waiting
|
||||
for signalling the occurence of an event. Condition variables are used on
|
||||
for signalling the occurence of an event. Condition variables are used in
|
||||
conjuction with mutexes to provide a shared access to one or more shared
|
||||
variable.
|
||||
|
||||
@@ -560,7 +559,7 @@ futex_wait :: proc "contextless" (f: ^Futex, expected: u32) {
|
||||
return
|
||||
}
|
||||
ok := _futex_wait(f, expected)
|
||||
_assert(ok, "futex_wait failure")
|
||||
assert_contextless(ok, "futex_wait failure")
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -597,18 +596,3 @@ Wake up multiple threads waiting on a futex.
|
||||
futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
_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()
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ atomic_recursive_mutex_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
|
||||
|
||||
atomic_recursive_mutex_unlock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
|
||||
tid := current_thread_id()
|
||||
_assert(tid == m.owner, "tid != m.owner")
|
||||
assert_contextless(tid == m.owner, "tid != m.owner")
|
||||
m.recursion -= 1
|
||||
recursion := m.recursion
|
||||
if recursion == 0 {
|
||||
@@ -361,7 +361,7 @@ atomic_sema_wait_with_timeout :: proc "contextless" (s: ^Atomic_Sema, duration:
|
||||
if !futex_wait_with_timeout(&s.count, u32(original_count), remaining) {
|
||||
return false
|
||||
}
|
||||
original_count = s.count
|
||||
original_count = atomic_load_explicit(&s.count, .Relaxed)
|
||||
}
|
||||
if original_count == atomic_compare_exchange_strong_explicit(&s.count, original_count, original_count-1, .Acquire, .Acquire) {
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user