123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- #+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")
- }
- }
- }
- }
|