123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- package darwin
- // #define OS_WAIT_ON_ADDR_AVAILABILITY \
- // __API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4))
- when ODIN_OS == .Darwin {
- when ODIN_PLATFORM_SUBTARGET_IOS {
- WAIT_ON_ADDRESS_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 17_04_00
- ULOCK_WAIT_2_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 14_00_00
- } else {
- WAIT_ON_ADDRESS_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 14_04_00
- ULOCK_WAIT_2_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 11_00_00
- }
- } else {
- WAIT_ON_ADDRESS_AVAILABLE :: false
- ULOCK_WAIT_2_AVAILABLE :: false
- }
- os_sync_wait_on_address_flag :: enum u32 {
- // This flag should be used when synchronizing among multiple processes by
- // placing the @addr passed to os_sync_wait_on_address and its variants
- // in a shared memory region.
- //
- // When using this flag, it is important to pass OS_SYNC_WAKE_BY_ADDRESS_SHARED
- // flag along with the exact same @addr to os_sync_wake_by_address_any and
- // its variants to correctly find and wake up blocked waiters on the @addr.
- //
- // This flag should not be used when synchronizing among multiple threads of
- // a single process. It allows the kernel to perform performance optimizations
- // as the @addr is local to the calling process.
- SHARED = 0,
- }
- os_sync_wait_on_address_flags :: distinct bit_set[os_sync_wait_on_address_flag; u32]
- os_sync_wake_by_address_flag :: enum u32 {
- // This flag should be used when synchronizing among multiple processes by
- // placing the @addr passed to os_sync_wake_by_address_any and its variants
- // in a shared memory region.
- //
- // When using this flag, it is important to pass OS_SYNC_WAIT_ON_ADDRESS_SHARED
- // flag along with the exact same @addr to os_sync_wait_on_address and
- // its variants to correctly find and wake up blocked waiters on the @addr.
- //
- // This flag should not be used when synchronizing among multiple threads of
- // a single process. It allows the kernel to perform performance optimizations
- // as the @addr is local the calling process.
- SHARED = 0,
- }
- os_sync_wake_by_address_flags :: distinct bit_set[os_sync_wake_by_address_flag; u32]
- os_clockid :: enum u32 {
- MACH_ABSOLUTE_TIME = 32,
- }
- foreign system {
- // This function provides an atomic compare-and-wait functionality that
- // can be used to implement other higher level synchronization primitives.
- //
- // It reads a value from @addr, compares it to expected @value and blocks
- // the calling thread if they are equal. This sequence of operations is
- // done atomically with respect to other concurrent operations that can
- // be performed on this @addr by other threads using this same function
- // or os_sync_wake_by_addr variants. At this point, the blocked calling
- // thread is considered to be a waiter on this @addr, waiting to be woken
- // up by a call to os_sync_wake_by_addr variants. If the value at @addr
- // turns out to be different than expected, the calling thread returns
- // immediately without blocking.
- //
- // This function is expected to be used for implementing synchronization
- // primitives that do not have a sense of ownership (e.g. condition
- // variables, semaphores) as it does not provide priority inversion avoidance.
- // For locking primitives, it is recommended that you use existing OS
- // primitives such as os_unfair_lock API family / pthread mutex or
- // std::mutex.
- //
- // @param addr
- // The userspace address to be used for atomic compare-and-wait.
- // This address must be aligned to @size.
- //
- // @param value
- // The value expected at @addr.
- //
- // @param size
- // The size of @value, in bytes. This can be either 4 or 8 today.
- // For @value of @size 4 bytes, the upper 4 bytes of @value are ignored.
- //
- // @param flags
- // Flags to alter behavior of os_sync_wait_on_address.
- // See os_sync_wait_on_address_flags_t.
- //
- // @return
- // If the calling thread is woken up by a call to os_sync_wake_by_addr
- // variants or the value at @addr is different than expected, this function
- // returns successfully and the return value indicates the number
- // of outstanding waiters blocked on this address.
- // In the event of an error, returns -1 with errno set to indicate the error.
- //
- // EINVAL : Invalid flags or size.
- // EINVAL : The @addr passed is NULL or misaligned.
- // EINVAL : The operation associated with existing kernel state
- // at this @addr is inconsistent with what the caller
- // has requested.
- // It is important to make sure consistent values are
- // passed across wait and wake APIs for @addr, @size
- // and the shared memory specification
- // (See os_sync_wait_on_address_flags_t).
- //
- // It is possible for the os_sync_wait_on_address and its variants to perform
- // an early return in the event of following errors where user may want to
- // re-try the wait operation. E.g. low memory conditions could cause such early
- // return.
- // It is important to read the current value at the @addr before re-trying
- // to ensure that the new value still requires waiting on @addr.
- //
- // ENOMEM : Unable to allocate memory for kernel internal data
- // structures.
- // EINTR : The syscall was interrupted / spurious wake up.
- // EFAULT : Unable to read value from the @addr. Kernel copyin failed.
- // It is possible to receive EFAULT error in following cases:
- // 1. The @addr is an invalid address. This is a programmer error.
- // 2. The @addr is valid; but, this is a transient error such as
- // due to low memory conditions. User may want to re-try the wait
- // operation.
- // Following code snippet illustrates a possible re-try loop.
- // <code>
- // retry:
- // current = atomic_load_explicit(addr, memory_order_relaxed);
- // if (current != expected) {
- // int ret = os_sync_wait_on_address(addr, current, size, flags);
- // if ((ret < 0) && ((errno == EINTR) || (errno == EFAULT))) {
- // goto retry;
- // }
- // }
- // </code>
- os_sync_wait_on_address :: proc(
- addr: rawptr,
- value: u64,
- size: uint,
- flags: os_sync_wait_on_address_flags,
- ) -> i32 ---
- // This function is a variant of os_sync_wait_on_address that
- // allows the calling thread to specify a deadline
- // until which it is willing to block.
- //
- // @param addr
- // The userspace address to be used for atomic compare-and-wait.
- // This address must be aligned to @size.
- //
- // @param value
- // The value expected at @addr.
- //
- // @param size
- // The size of @value, in bytes. This can be either 4 or 8 today.
- // For @value of @size 4 bytes, the upper 4 bytes of @value are ignored.
- //
- // @param flags
- // Flags to alter behavior of os_sync_wait_on_address_with_deadline.
- // See os_sync_wait_on_address_flags_t.
- //
- // @param clockid
- // This value anchors @deadline argument to a specific clock id.
- // See os_clockid_t.
- //
- // @param deadline
- // This value is used to specify a deadline until which the calling
- // thread is willing to block.
- // Passing zero for the @deadline results in an error being returned.
- // It is recommended to use os_sync_wait_on_address API to block
- // indefinitely until woken up by a call to os_sync_wake_by_address_any
- // or os_sync_wake_by_address_all APIs.
- //
- // @return
- // If the calling thread is woken up by a call to os_sync_wake_by_addr
- // variants or the value at @addr is different than expected, this function
- // returns successfully and the return value indicates the number
- // of outstanding waiters blocked on this address.
- // In the event of an error, returns -1 with errno set to indicate the error.
- //
- // In addition to errors returned by os_sync_wait_on_address, this function
- // can return the following additional error codes.
- //
- // EINVAL : Invalid clock id.
- // EINVAL : The @deadline passed is 0.
- // ETIMEDOUT : Deadline expired.
- os_sync_wait_on_address_with_deadline :: proc(
- addr: rawptr,
- value: u64,
- size: uint,
- flags: os_sync_wait_on_address_flags,
- clockid: os_clockid,
- deadline: u64,
- ) -> i32 ---
- // This function is a variant of os_sync_wait_on_address that
- // allows the calling thread to specify a timeout
- // until which it is willing to block.
- //
- // @param addr
- // The userspace address to be used for atomic compare-and-wait.
- // This address must be aligned to @size.
- //
- // @param value
- // The value expected at @addr.
- //
- // @param size
- // The size of @value, in bytes. This can be either 4 or 8 today.
- // For @value of @size 4 bytes, the upper 4 bytes of @value are ignored.
- //
- // @param flags
- // Flags to alter behavior of os_sync_wait_on_address_with_timeout.
- // See os_sync_wait_on_address_flags_t.
- //
- // @param clockid
- // This value anchors @timeout_ns argument to a specific clock id.
- // See os_clockid_t.
- //
- // @param timeout_ns
- // This value is used to specify a timeout in nanoseconds until which
- // the calling thread is willing to block.
- // Passing zero for the @timeout_ns results in an error being returned.
- // It is recommended to use os_sync_wait_on_address API to block
- // indefinitely until woken up by a call to os_sync_wake_by_address_any
- // or os_sync_wake_by_address_all APIs.
- //
- // @return
- // If the calling thread is woken up by a call to os_sync_wake_by_address
- // variants or the value at @addr is different than expected, this function
- // returns successfully and the return value indicates the number
- // of outstanding waiters blocked on this address.
- // In the event of an error, returns -1 with errno set to indicate the error.
- //
- // In addition to errors returned by os_sync_wait_on_address, this function
- // can return the following additional error codes.
- //
- // EINVAL : Invalid clock id.
- // EINVAL : The @timeout_ns passed is 0.
- // ETIMEDOUT : Timeout expired.
- os_sync_wait_on_address_with_timeout :: proc(
- addr: rawptr,
- value: u64,
- size: uint,
- flags: os_sync_wait_on_address_flags,
- clockid: os_clockid,
- timeout_ns: u64,
- ) -> i32 ---
- // This function wakes up one waiter out of all those blocked in os_sync_wait_on_address
- // or its variants on the @addr. No guarantee is provided about which
- // specific waiter is woken up.
- //
- // @param addr
- // The userspace address to be used for waking up the blocked waiter.
- // It should be same as what is passed to os_sync_wait_on_address or its variants.
- //
- // @param size
- // The size of lock value, in bytes. This can be either 4 or 8 today.
- // It should be same as what is passed to os_sync_wait_on_address or its variants.
- //
- // @param flags
- // Flags to alter behavior of os_sync_wake_by_address_any.
- // See os_sync_wake_by_address_flags_t.
- //
- // @return
- // Returns 0 on success.
- // In the event of an error, returns -1 with errno set to indicate the error.
- //
- // EINVAL : Invalid flags or size.
- // EINVAL : The @addr passed is NULL.
- // EINVAL : The operation associated with existing kernel state
- // at this @addr is inconsistent with what caller
- // has requested.
- // It is important to make sure consistent values are
- // passed across wait and wake APIs for @addr, @size
- // and the shared memory specification
- // (See os_sync_wake_by_address_flags_t).
- // ENOENT : No waiter(s) found waiting on the @addr.
- os_sync_wake_by_address_any :: proc(addr: rawptr, size: uint, flags: os_sync_wake_by_address_flags) -> i32 ---
- // This function is a variant of os_sync_wake_by_address_any that wakes up all waiters
- // blocked in os_sync_wait_on_address or its variants.
- //
- // @param addr
- // The userspace address to be used for waking up the blocked waiters.
- // It should be same as what is passed to os_sync_wait_on_address or its variants.
- //
- // @param size
- // The size of lock value, in bytes. This can be either 4 or 8 today.
- // It should be same as what is passed to os_sync_wait_on_address or its variants.
- //
- // @param flags
- // Flags to alter behavior of os_sync_wake_by_address_all.
- // See os_sync_wake_by_address_flags_t.
- //
- // @return
- // Returns 0 on success.
- // In the event of an error, returns -1 with errno set to indicate the error.
- //
- // This function returns same error codes as returned by os_sync_wait_on_address.
- os_sync_wake_by_address_all :: proc(addr: rawptr, size: uint, flags: os_sync_wake_by_address_flags) -> i32 ---
- }
|