sync.odin 12 KB

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