1 //go:build none
2 3 // This file is manually included, to avoid CGo which would cause a circular
4 // import.
5 6 #include <stdint.h>
7 8 // This API isn't documented by Apple, but it is used by LLVM libc++ (so should
9 // be stable) and has been documented extensively here:
10 // https://outerproduct.net/futex-dictionary.html
11 12 int __ulock_wait(uint32_t operation, void *addr, uint64_t value, uint32_t timeout_us);
13 int __ulock_wait2(uint32_t operation, void *addr, uint64_t value, uint64_t timeout_ns, uint64_t value2);
14 int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value);
15 16 // Operation code.
17 #define UL_COMPARE_AND_WAIT 1
18 19 // Flags to the operation value.
20 #define ULF_WAKE_ALL 0x00000100
21 #define ULF_NO_ERRNO 0x01000000
22 23 void moxie_futex_wait(uint32_t *addr, uint32_t cmp) {
24 __ulock_wait(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO, addr, (uint64_t)cmp, 0);
25 }
26 27 void moxie_futex_wait_timeout(uint32_t *addr, uint32_t cmp, uint64_t timeout) {
28 // Make sure that an accidental use of a zero timeout is not treated as an
29 // infinite timeout. Return if it's zero since it wouldn't be waiting for
30 // any significant time anyway.
31 // Probably unnecessary, but guards against potential bugs.
32 if (timeout == 0) {
33 return;
34 }
35 36 // Note: __ulock_wait2 is available since MacOS 11.
37 // I think that's fine, since the version before that (MacOS 10.15) is EOL
38 // since 2022. Though if needed, we could certainly use __ulock_wait instead
39 // and deal with the smaller timeout value.
40 __ulock_wait2(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO, addr, (uint64_t)cmp, timeout, 0);
41 }
42 43 void moxie_futex_wake(uint32_t *addr) {
44 __ulock_wake(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO, addr, 0);
45 }
46 47 void moxie_futex_wake_all(uint32_t *addr) {
48 __ulock_wake(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO|ULF_WAKE_ALL, addr, 0);
49 }
50