futex_darwin.odin 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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.framework"
  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. __ulock_wake :: proc "c" (operation: u32, addr: rawptr, wake_value: u64) -> c.int ---
  13. }
  14. UL_COMPARE_AND_WAIT :: 1
  15. ULF_WAKE_ALL :: 0x00000100
  16. ULF_NO_ERRNO :: 0x01000000
  17. ENOENT :: -2
  18. EINTR :: -4
  19. EFAULT :: -14
  20. ETIMEDOUT :: -60
  21. _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
  22. return _futex_wait_with_timeout(f, expected, 0)
  23. }
  24. _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
  25. when darwin.WAIT_ON_ADDRESS_AVAILABLE {
  26. s: i32
  27. if duration > 0 {
  28. s = darwin.os_sync_wait_on_address_with_timeout(f, u64(expected), size_of(Futex), {}, .MACH_ABSOLUTE_TIME, u64(duration))
  29. } else {
  30. s = darwin.os_sync_wait_on_address(f, u64(expected), size_of(Futex), {})
  31. }
  32. if s >= 0 {
  33. return true
  34. }
  35. switch darwin.errno() {
  36. case -EINTR, -EFAULT:
  37. return true
  38. case -ETIMEDOUT:
  39. return false
  40. case:
  41. _panic("darwin.os_sync_wait_on_address_with_timeout failure")
  42. }
  43. } else {
  44. timeout_ns := u32(duration)
  45. s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
  46. if s >= 0 {
  47. return true
  48. }
  49. switch s {
  50. case EINTR, EFAULT:
  51. return true
  52. case ETIMEDOUT:
  53. return false
  54. case:
  55. _panic("futex_wait failure")
  56. }
  57. return true
  58. }
  59. }
  60. _futex_signal :: proc "contextless" (f: ^Futex) {
  61. when darwin.WAIT_ON_ADDRESS_AVAILABLE {
  62. loop: for {
  63. s := darwin.os_sync_wake_by_address_any(f, size_of(Futex), {})
  64. if s >= 0 {
  65. return
  66. }
  67. switch darwin.errno() {
  68. case -EINTR, -EFAULT:
  69. continue loop
  70. case -ENOENT:
  71. return
  72. case:
  73. _panic("darwin.os_sync_wake_by_address_any failure")
  74. }
  75. }
  76. } else {
  77. loop: for {
  78. s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
  79. if s >= 0 {
  80. return
  81. }
  82. switch s {
  83. case EINTR, EFAULT:
  84. continue loop
  85. case ENOENT:
  86. return
  87. case:
  88. _panic("futex_wake_single failure")
  89. }
  90. }
  91. }
  92. }
  93. _futex_broadcast :: proc "contextless" (f: ^Futex) {
  94. when darwin.WAIT_ON_ADDRESS_AVAILABLE {
  95. loop: for {
  96. s := darwin.os_sync_wake_by_address_all(f, size_of(Futex), {})
  97. if s >= 0 {
  98. return
  99. }
  100. switch darwin.errno() {
  101. case -EINTR, -EFAULT:
  102. continue loop
  103. case -ENOENT:
  104. return
  105. case:
  106. _panic("darwin.os_sync_wake_by_address_all failure")
  107. }
  108. }
  109. } else {
  110. loop: for {
  111. s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
  112. if s >= 0 {
  113. return
  114. }
  115. switch s {
  116. case EINTR, EFAULT:
  117. continue loop
  118. case ENOENT:
  119. return
  120. case:
  121. _panic("futex_wake_all failure")
  122. }
  123. }
  124. }
  125. }