mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-31 18:32:12 +00:00
153 lines
3.2 KiB
Odin
153 lines
3.2 KiB
Odin
#+private
|
|
#+build darwin
|
|
package sync
|
|
|
|
import "core:c"
|
|
import "core:sys/darwin"
|
|
import "core:time"
|
|
|
|
foreign import System "system:System"
|
|
|
|
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 ---
|
|
}
|
|
|
|
|
|
UL_COMPARE_AND_WAIT :: 1
|
|
ULF_WAKE_ALL :: 0x00000100
|
|
ULF_NO_ERRNO :: 0x01000000
|
|
|
|
ENOENT :: -2
|
|
EINTR :: -4
|
|
EFAULT :: -14
|
|
ETIMEDOUT :: -60
|
|
|
|
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
|
return _futex_wait_with_timeout(f, expected, 0)
|
|
}
|
|
|
|
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
|
when darwin.WAIT_ON_ADDRESS_AVAILABLE {
|
|
s: i32
|
|
if duration > 0 {
|
|
s = darwin.os_sync_wait_on_address_with_timeout(f, u64(expected), size_of(Futex), {}, .MACH_ABSOLUTE_TIME, u64(duration))
|
|
} else {
|
|
s = darwin.os_sync_wait_on_address(f, u64(expected), size_of(Futex), {})
|
|
}
|
|
|
|
if s >= 0 {
|
|
return true
|
|
}
|
|
|
|
switch darwin.errno() {
|
|
case -EINTR, -EFAULT:
|
|
return true
|
|
case -ETIMEDOUT:
|
|
return false
|
|
case:
|
|
panic_contextless("darwin.os_sync_wait_on_address_with_timeout failure")
|
|
}
|
|
} else {
|
|
|
|
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_contextless("futex_wait failure")
|
|
}
|
|
return true
|
|
|
|
}
|
|
}
|
|
|
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
|
when darwin.WAIT_ON_ADDRESS_AVAILABLE {
|
|
loop: for {
|
|
s := darwin.os_sync_wake_by_address_any(f, size_of(Futex), {})
|
|
if s >= 0 {
|
|
return
|
|
}
|
|
switch darwin.errno() {
|
|
case -EINTR, -EFAULT:
|
|
continue loop
|
|
case -ENOENT:
|
|
return
|
|
case:
|
|
panic_contextless("darwin.os_sync_wake_by_address_any failure")
|
|
}
|
|
}
|
|
} else {
|
|
|
|
loop: for {
|
|
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
|
|
if s >= 0 {
|
|
return
|
|
}
|
|
switch s {
|
|
case EINTR, EFAULT:
|
|
continue loop
|
|
case ENOENT:
|
|
return
|
|
case:
|
|
panic_contextless("futex_wake_single failure")
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
|
when darwin.WAIT_ON_ADDRESS_AVAILABLE {
|
|
loop: for {
|
|
s := darwin.os_sync_wake_by_address_all(f, size_of(Futex), {})
|
|
if s >= 0 {
|
|
return
|
|
}
|
|
switch darwin.errno() {
|
|
case -EINTR, -EFAULT:
|
|
continue loop
|
|
case -ENOENT:
|
|
return
|
|
case:
|
|
panic_contextless("darwin.os_sync_wake_by_address_all failure")
|
|
}
|
|
}
|
|
} else {
|
|
|
|
loop: for {
|
|
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
|
|
if s >= 0 {
|
|
return
|
|
}
|
|
switch s {
|
|
case EINTR, EFAULT:
|
|
continue loop
|
|
case ENOENT:
|
|
return
|
|
case:
|
|
panic_contextless("futex_wake_all failure")
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|