sync.odin 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. package darwin
  2. // #define OS_WAIT_ON_ADDR_AVAILABILITY \
  3. // __API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4))
  4. when ODIN_OS == .Darwin {
  5. when ODIN_PLATFORM_SUBTARGET_IOS {
  6. WAIT_ON_ADDRESS_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 17_04_00
  7. ULOCK_WAIT_2_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 14_00_00
  8. } else {
  9. WAIT_ON_ADDRESS_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 14_04_00
  10. ULOCK_WAIT_2_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 11_00_00
  11. }
  12. } else {
  13. WAIT_ON_ADDRESS_AVAILABLE :: false
  14. ULOCK_WAIT_2_AVAILABLE :: false
  15. }
  16. os_sync_wait_on_address_flag :: enum u32 {
  17. // This flag should be used when synchronizing among multiple processes by
  18. // placing the @addr passed to os_sync_wait_on_address and its variants
  19. // in a shared memory region.
  20. //
  21. // When using this flag, it is important to pass OS_SYNC_WAKE_BY_ADDRESS_SHARED
  22. // flag along with the exact same @addr to os_sync_wake_by_address_any and
  23. // its variants to correctly find and wake up blocked waiters on the @addr.
  24. //
  25. // This flag should not be used when synchronizing among multiple threads of
  26. // a single process. It allows the kernel to perform performance optimizations
  27. // as the @addr is local to the calling process.
  28. SHARED = 0,
  29. }
  30. os_sync_wait_on_address_flags :: distinct bit_set[os_sync_wait_on_address_flag; u32]
  31. os_sync_wake_by_address_flag :: enum u32 {
  32. // This flag should be used when synchronizing among multiple processes by
  33. // placing the @addr passed to os_sync_wake_by_address_any and its variants
  34. // in a shared memory region.
  35. //
  36. // When using this flag, it is important to pass OS_SYNC_WAIT_ON_ADDRESS_SHARED
  37. // flag along with the exact same @addr to os_sync_wait_on_address and
  38. // its variants to correctly find and wake up blocked waiters on the @addr.
  39. //
  40. // This flag should not be used when synchronizing among multiple threads of
  41. // a single process. It allows the kernel to perform performance optimizations
  42. // as the @addr is local the calling process.
  43. SHARED = 0,
  44. }
  45. os_sync_wake_by_address_flags :: distinct bit_set[os_sync_wake_by_address_flag; u32]
  46. os_clockid :: enum u32 {
  47. MACH_ABSOLUTE_TIME = 32,
  48. }
  49. foreign system {
  50. // This function provides an atomic compare-and-wait functionality that
  51. // can be used to implement other higher level synchronization primitives.
  52. //
  53. // It reads a value from @addr, compares it to expected @value and blocks
  54. // the calling thread if they are equal. This sequence of operations is
  55. // done atomically with respect to other concurrent operations that can
  56. // be performed on this @addr by other threads using this same function
  57. // or os_sync_wake_by_addr variants. At this point, the blocked calling
  58. // thread is considered to be a waiter on this @addr, waiting to be woken
  59. // up by a call to os_sync_wake_by_addr variants. If the value at @addr
  60. // turns out to be different than expected, the calling thread returns
  61. // immediately without blocking.
  62. //
  63. // This function is expected to be used for implementing synchronization
  64. // primitives that do not have a sense of ownership (e.g. condition
  65. // variables, semaphores) as it does not provide priority inversion avoidance.
  66. // For locking primitives, it is recommended that you use existing OS
  67. // primitives such as os_unfair_lock API family / pthread mutex or
  68. // std::mutex.
  69. //
  70. // @param addr
  71. // The userspace address to be used for atomic compare-and-wait.
  72. // This address must be aligned to @size.
  73. //
  74. // @param value
  75. // The value expected at @addr.
  76. //
  77. // @param size
  78. // The size of @value, in bytes. This can be either 4 or 8 today.
  79. // For @value of @size 4 bytes, the upper 4 bytes of @value are ignored.
  80. //
  81. // @param flags
  82. // Flags to alter behavior of os_sync_wait_on_address.
  83. // See os_sync_wait_on_address_flags_t.
  84. //
  85. // @return
  86. // If the calling thread is woken up by a call to os_sync_wake_by_addr
  87. // variants or the value at @addr is different than expected, this function
  88. // returns successfully and the return value indicates the number
  89. // of outstanding waiters blocked on this address.
  90. // In the event of an error, returns -1 with errno set to indicate the error.
  91. //
  92. // EINVAL : Invalid flags or size.
  93. // EINVAL : The @addr passed is NULL or misaligned.
  94. // EINVAL : The operation associated with existing kernel state
  95. // at this @addr is inconsistent with what the caller
  96. // has requested.
  97. // It is important to make sure consistent values are
  98. // passed across wait and wake APIs for @addr, @size
  99. // and the shared memory specification
  100. // (See os_sync_wait_on_address_flags_t).
  101. //
  102. // It is possible for the os_sync_wait_on_address and its variants to perform
  103. // an early return in the event of following errors where user may want to
  104. // re-try the wait operation. E.g. low memory conditions could cause such early
  105. // return.
  106. // It is important to read the current value at the @addr before re-trying
  107. // to ensure that the new value still requires waiting on @addr.
  108. //
  109. // ENOMEM : Unable to allocate memory for kernel internal data
  110. // structures.
  111. // EINTR : The syscall was interrupted / spurious wake up.
  112. // EFAULT : Unable to read value from the @addr. Kernel copyin failed.
  113. // It is possible to receive EFAULT error in following cases:
  114. // 1. The @addr is an invalid address. This is a programmer error.
  115. // 2. The @addr is valid; but, this is a transient error such as
  116. // due to low memory conditions. User may want to re-try the wait
  117. // operation.
  118. // Following code snippet illustrates a possible re-try loop.
  119. // <code>
  120. // retry:
  121. // current = atomic_load_explicit(addr, memory_order_relaxed);
  122. // if (current != expected) {
  123. // int ret = os_sync_wait_on_address(addr, current, size, flags);
  124. // if ((ret < 0) && ((errno == EINTR) || (errno == EFAULT))) {
  125. // goto retry;
  126. // }
  127. // }
  128. // </code>
  129. os_sync_wait_on_address :: proc(
  130. addr: rawptr,
  131. value: u64,
  132. size: uint,
  133. flags: os_sync_wait_on_address_flags,
  134. ) -> i32 ---
  135. // This function is a variant of os_sync_wait_on_address that
  136. // allows the calling thread to specify a deadline
  137. // until which it is willing to block.
  138. //
  139. // @param addr
  140. // The userspace address to be used for atomic compare-and-wait.
  141. // This address must be aligned to @size.
  142. //
  143. // @param value
  144. // The value expected at @addr.
  145. //
  146. // @param size
  147. // The size of @value, in bytes. This can be either 4 or 8 today.
  148. // For @value of @size 4 bytes, the upper 4 bytes of @value are ignored.
  149. //
  150. // @param flags
  151. // Flags to alter behavior of os_sync_wait_on_address_with_deadline.
  152. // See os_sync_wait_on_address_flags_t.
  153. //
  154. // @param clockid
  155. // This value anchors @deadline argument to a specific clock id.
  156. // See os_clockid_t.
  157. //
  158. // @param deadline
  159. // This value is used to specify a deadline until which the calling
  160. // thread is willing to block.
  161. // Passing zero for the @deadline results in an error being returned.
  162. // It is recommended to use os_sync_wait_on_address API to block
  163. // indefinitely until woken up by a call to os_sync_wake_by_address_any
  164. // or os_sync_wake_by_address_all APIs.
  165. //
  166. // @return
  167. // If the calling thread is woken up by a call to os_sync_wake_by_addr
  168. // variants or the value at @addr is different than expected, this function
  169. // returns successfully and the return value indicates the number
  170. // of outstanding waiters blocked on this address.
  171. // In the event of an error, returns -1 with errno set to indicate the error.
  172. //
  173. // In addition to errors returned by os_sync_wait_on_address, this function
  174. // can return the following additional error codes.
  175. //
  176. // EINVAL : Invalid clock id.
  177. // EINVAL : The @deadline passed is 0.
  178. // ETIMEDOUT : Deadline expired.
  179. os_sync_wait_on_address_with_deadline :: proc(
  180. addr: rawptr,
  181. value: u64,
  182. size: uint,
  183. flags: os_sync_wait_on_address_flags,
  184. clockid: os_clockid,
  185. deadline: u64,
  186. ) -> i32 ---
  187. // This function is a variant of os_sync_wait_on_address that
  188. // allows the calling thread to specify a timeout
  189. // until which it is willing to block.
  190. //
  191. // @param addr
  192. // The userspace address to be used for atomic compare-and-wait.
  193. // This address must be aligned to @size.
  194. //
  195. // @param value
  196. // The value expected at @addr.
  197. //
  198. // @param size
  199. // The size of @value, in bytes. This can be either 4 or 8 today.
  200. // For @value of @size 4 bytes, the upper 4 bytes of @value are ignored.
  201. //
  202. // @param flags
  203. // Flags to alter behavior of os_sync_wait_on_address_with_timeout.
  204. // See os_sync_wait_on_address_flags_t.
  205. //
  206. // @param clockid
  207. // This value anchors @timeout_ns argument to a specific clock id.
  208. // See os_clockid_t.
  209. //
  210. // @param timeout_ns
  211. // This value is used to specify a timeout in nanoseconds until which
  212. // the calling thread is willing to block.
  213. // Passing zero for the @timeout_ns results in an error being returned.
  214. // It is recommended to use os_sync_wait_on_address API to block
  215. // indefinitely until woken up by a call to os_sync_wake_by_address_any
  216. // or os_sync_wake_by_address_all APIs.
  217. //
  218. // @return
  219. // If the calling thread is woken up by a call to os_sync_wake_by_address
  220. // variants or the value at @addr is different than expected, this function
  221. // returns successfully and the return value indicates the number
  222. // of outstanding waiters blocked on this address.
  223. // In the event of an error, returns -1 with errno set to indicate the error.
  224. //
  225. // In addition to errors returned by os_sync_wait_on_address, this function
  226. // can return the following additional error codes.
  227. //
  228. // EINVAL : Invalid clock id.
  229. // EINVAL : The @timeout_ns passed is 0.
  230. // ETIMEDOUT : Timeout expired.
  231. os_sync_wait_on_address_with_timeout :: proc(
  232. addr: rawptr,
  233. value: u64,
  234. size: uint,
  235. flags: os_sync_wait_on_address_flags,
  236. clockid: os_clockid,
  237. timeout_ns: u64,
  238. ) -> i32 ---
  239. // This function wakes up one waiter out of all those blocked in os_sync_wait_on_address
  240. // or its variants on the @addr. No guarantee is provided about which
  241. // specific waiter is woken up.
  242. //
  243. // @param addr
  244. // The userspace address to be used for waking up the blocked waiter.
  245. // It should be same as what is passed to os_sync_wait_on_address or its variants.
  246. //
  247. // @param size
  248. // The size of lock value, in bytes. This can be either 4 or 8 today.
  249. // It should be same as what is passed to os_sync_wait_on_address or its variants.
  250. //
  251. // @param flags
  252. // Flags to alter behavior of os_sync_wake_by_address_any.
  253. // See os_sync_wake_by_address_flags_t.
  254. //
  255. // @return
  256. // Returns 0 on success.
  257. // In the event of an error, returns -1 with errno set to indicate the error.
  258. //
  259. // EINVAL : Invalid flags or size.
  260. // EINVAL : The @addr passed is NULL.
  261. // EINVAL : The operation associated with existing kernel state
  262. // at this @addr is inconsistent with what caller
  263. // has requested.
  264. // It is important to make sure consistent values are
  265. // passed across wait and wake APIs for @addr, @size
  266. // and the shared memory specification
  267. // (See os_sync_wake_by_address_flags_t).
  268. // ENOENT : No waiter(s) found waiting on the @addr.
  269. os_sync_wake_by_address_any :: proc(addr: rawptr, size: uint, flags: os_sync_wake_by_address_flags) -> i32 ---
  270. // This function is a variant of os_sync_wake_by_address_any that wakes up all waiters
  271. // blocked in os_sync_wait_on_address or its variants.
  272. //
  273. // @param addr
  274. // The userspace address to be used for waking up the blocked waiters.
  275. // It should be same as what is passed to os_sync_wait_on_address or its variants.
  276. //
  277. // @param size
  278. // The size of lock value, in bytes. This can be either 4 or 8 today.
  279. // It should be same as what is passed to os_sync_wait_on_address or its variants.
  280. //
  281. // @param flags
  282. // Flags to alter behavior of os_sync_wake_by_address_all.
  283. // See os_sync_wake_by_address_flags_t.
  284. //
  285. // @return
  286. // Returns 0 on success.
  287. // In the event of an error, returns -1 with errno set to indicate the error.
  288. //
  289. // This function returns same error codes as returned by os_sync_wait_on_address.
  290. os_sync_wake_by_address_all :: proc(addr: rawptr, size: uint, flags: os_sync_wake_by_address_flags) -> i32 ---
  291. }