futex_darwin.odin 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. //+private
  2. //+build darwin
  3. package sync
  4. import "core:c"
  5. import "core:time"
  6. foreign import System "System.framework"
  7. foreign System {
  8. // __ulock_wait is not available on 10.15
  9. // See https://github.com/odin-lang/Odin/issues/1959
  10. __ulock_wait :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_us: u32) -> c.int ---
  11. __ulock_wake :: proc "c" (operation: u32, addr: rawptr, wake_value: u64) -> c.int ---
  12. }
  13. UL_COMPARE_AND_WAIT :: 1
  14. ULF_WAKE_ALL :: 0x00000100
  15. ULF_NO_ERRNO :: 0x01000000
  16. ENOENT :: -2
  17. EINTR :: -4
  18. EFAULT :: -14
  19. ETIMEDOUT :: -60
  20. _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
  21. return _futex_wait_with_timeout(f, expected, 0)
  22. }
  23. _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
  24. timeout_ns := u32(duration) * 1000
  25. s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
  26. if s >= 0 {
  27. return true
  28. }
  29. switch s {
  30. case EINTR, EFAULT:
  31. return true
  32. case ETIMEDOUT:
  33. return false
  34. case:
  35. _panic("futex_wait failure")
  36. }
  37. return true
  38. }
  39. _futex_signal :: proc "contextless" (f: ^Futex) {
  40. loop: for {
  41. s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
  42. if s >= 0 {
  43. return
  44. }
  45. switch s {
  46. case EINTR, EFAULT:
  47. continue loop
  48. case ENOENT:
  49. return
  50. case:
  51. _panic("futex_wake_single failure")
  52. }
  53. }
  54. }
  55. _futex_broadcast :: proc "contextless" (f: ^Futex) {
  56. loop: for {
  57. s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
  58. if s >= 0 {
  59. return
  60. }
  61. switch s {
  62. case EINTR, EFAULT:
  63. continue loop
  64. case ENOENT:
  65. return
  66. case:
  67. _panic("futex_wake_all failure")
  68. }
  69. }
  70. }