1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
//+private
//+build darwin
package sync
import "core:c"
import "core:time"
foreign import System "system:System.framework"
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 ---
__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 {
timeout_ns := u32(duration) * 1000
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
if s >= 0 {
return true
}
switch s {
case EINTR, EFAULT:
return true
case ETIMEDOUT:
return false
case:
_panic("futex_wait failure")
}
return true
}
_futex_signal :: proc "contextless" (f: ^Futex) {
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("futex_wake_single failure")
}
}
}
_futex_broadcast :: proc "contextless" (f: ^Futex) {
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("futex_wake_all failure")
}
}
}
|