futex_darwin.odin 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #+private
  2. #+build darwin
  3. package sync
  4. import "core:c"
  5. import "core:sys/darwin"
  6. import "core:time"
  7. foreign import System "system:System"
  8. foreign System {
  9. // __ulock_wait is not available on 10.15
  10. // See https://github.com/odin-lang/Odin/issues/1959
  11. __ulock_wait :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_us: u32) -> c.int ---
  12. // >= MacOS 11.
  13. __ulock_wait2 :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_ns: u64, value2: u64) -> c.int ---
  14. __ulock_wake :: proc "c" (operation: u32, addr: rawptr, wake_value: u64) -> c.int ---
  15. }
  16. UL_COMPARE_AND_WAIT :: 1
  17. ULF_WAKE_ALL :: 0x00000100
  18. ULF_NO_ERRNO :: 0x01000000
  19. ENOENT :: -2
  20. EINTR :: -4
  21. EFAULT :: -14
  22. ETIMEDOUT :: -60
  23. _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
  24. return _futex_wait_with_timeout(f, expected, 0)
  25. }
  26. _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
  27. when darwin.WAIT_ON_ADDRESS_AVAILABLE {
  28. s: i32
  29. if duration > 0 {
  30. s = darwin.os_sync_wait_on_address_with_timeout(f, u64(expected), size_of(Futex), {}, .MACH_ABSOLUTE_TIME, u64(duration))
  31. } else {
  32. s = darwin.os_sync_wait_on_address(f, u64(expected), size_of(Futex), {})
  33. }
  34. if s >= 0 {
  35. return true
  36. }
  37. switch darwin.errno() {
  38. case -EINTR, -EFAULT:
  39. return true
  40. case -ETIMEDOUT:
  41. return false
  42. case:
  43. panic_contextless("darwin.os_sync_wait_on_address_with_timeout failure")
  44. }
  45. } else {
  46. when darwin.ULOCK_WAIT_2_AVAILABLE {
  47. timeout_ns := u64(duration)
  48. s := __ulock_wait2(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns, 0)
  49. } else {
  50. timeout_us := u32(duration / time.Microsecond)
  51. s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_us)
  52. }
  53. if s >= 0 {
  54. return true
  55. }
  56. switch s {
  57. case EINTR, EFAULT:
  58. return true
  59. case ETIMEDOUT:
  60. return false
  61. case:
  62. panic_contextless("futex_wait failure")
  63. }
  64. return true
  65. }
  66. }
  67. _futex_signal :: proc "contextless" (f: ^Futex) {
  68. when darwin.WAIT_ON_ADDRESS_AVAILABLE {
  69. loop: for {
  70. s := darwin.os_sync_wake_by_address_any(f, size_of(Futex), {})
  71. if s >= 0 {
  72. return
  73. }
  74. switch darwin.errno() {
  75. case -EINTR, -EFAULT:
  76. continue loop
  77. case -ENOENT:
  78. return
  79. case:
  80. panic_contextless("darwin.os_sync_wake_by_address_any failure")
  81. }
  82. }
  83. } else {
  84. loop: for {
  85. s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
  86. if s >= 0 {
  87. return
  88. }
  89. switch s {
  90. case EINTR, EFAULT:
  91. continue loop
  92. case ENOENT:
  93. return
  94. case:
  95. panic_contextless("futex_wake_single failure")
  96. }
  97. }
  98. }
  99. }
  100. _futex_broadcast :: proc "contextless" (f: ^Futex) {
  101. when darwin.WAIT_ON_ADDRESS_AVAILABLE {
  102. loop: for {
  103. s := darwin.os_sync_wake_by_address_all(f, size_of(Futex), {})
  104. if s >= 0 {
  105. return
  106. }
  107. switch darwin.errno() {
  108. case -EINTR, -EFAULT:
  109. continue loop
  110. case -ENOENT:
  111. return
  112. case:
  113. panic_contextless("darwin.os_sync_wake_by_address_all failure")
  114. }
  115. }
  116. } else {
  117. loop: for {
  118. s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
  119. if s >= 0 {
  120. return
  121. }
  122. switch s {
  123. case EINTR, EFAULT:
  124. continue loop
  125. case ENOENT:
  126. return
  127. case:
  128. panic_contextless("futex_wake_all failure")
  129. }
  130. }
  131. }
  132. }