diff --git a/lib/libc/include/any-darwin-any/os/os_sync_wait_on_address.h b/lib/libc/include/any-darwin-any/os/os_sync_wait_on_address.h new file mode 100644 index 0000000000000000000000000000000000000000..a79675d216e7e50faad9d50b3fe3670f41d98148 --- /dev/null +++ b/lib/libc/include/any-darwin-any/os/os_sync_wait_on_address.h @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2016 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +#ifndef __OS_SYNC_WAIT_ON_ADDRESS__ +#define __OS_SYNC_WAIT_ON_ADDRESS__ + +#include +#include +#include +#include +#include + +OS_ASSUME_NONNULL_BEGIN + +/*! @header + * Low-level Darwin's futex style APIs. + */ + +__BEGIN_DECLS + +#define OS_WAIT_ON_ADDR_AVAILABILITY \ + __API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4)) + +/*! + * @typedef os_sync_wait_on_address_flags_t + * + * @const OS_SYNC_WAIT_ON_ADDRESS_NONE + * This flag should be used as a default flag when no other flags listed below + * are required. + * + * @const OS_SYNC_WAIT_ON_ADDRESS_SHARED + * 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. + */ +OS_OPTIONS(os_sync_wait_on_address_flags, uint32_t, + OS_SYNC_WAIT_ON_ADDRESS_NONE + OS_WAIT_ON_ADDR_AVAILABILITY = 0x00000000, + OS_SYNC_WAIT_ON_ADDRESS_SHARED + OS_WAIT_ON_ADDR_AVAILABILITY = 0x00000001, +); + +/*! + * @function os_sync_wait_on_address + * + * 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. + * + * 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; + * } + * } + * + */ +OS_WAIT_ON_ADDR_AVAILABILITY +OS_EXPORT OS_NOTHROW OS_NONNULL_ALL +int +os_sync_wait_on_address(void *addr, + uint64_t value, + size_t size, + os_sync_wait_on_address_flags_t flags); + +/*! + * @function os_sync_wait_on_address_with_deadline + * + * 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_WAIT_ON_ADDR_AVAILABILITY +OS_EXPORT OS_NOTHROW OS_NONNULL_ALL +int +os_sync_wait_on_address_with_deadline(void *addr, + uint64_t value, + size_t size, + os_sync_wait_on_address_flags_t flags, + os_clockid_t clockid, + uint64_t deadline); + +/*! + * @function os_sync_wait_on_address_with_timeout + * + * 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_WAIT_ON_ADDR_AVAILABILITY +OS_EXPORT OS_NOTHROW OS_NONNULL_ALL +int +os_sync_wait_on_address_with_timeout(void *addr, + uint64_t value, + size_t size, + os_sync_wait_on_address_flags_t flags, + os_clockid_t clockid, + uint64_t timeout_ns); + +/*! + * @typedef os_sync_wake_by_address_flags_t + * + * @const OS_SYNC_WAKE_BY_ADDRESS_NONE + * This flag should be used as a default flag when no other flags listed below + * are required. + * + * @const OS_SYNC_WAKE_BY_ADDRESS_SHARED + * 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. + */ +OS_OPTIONS(os_sync_wake_by_address_flags, uint32_t, + OS_SYNC_WAKE_BY_ADDRESS_NONE + OS_WAIT_ON_ADDR_AVAILABILITY = 0x00000000, + OS_SYNC_WAKE_BY_ADDRESS_SHARED + OS_WAIT_ON_ADDR_AVAILABILITY = 0x00000001, +); + +/*! + * @function os_sync_wake_by_address_any + * + * 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_WAIT_ON_ADDR_AVAILABILITY +OS_EXPORT OS_NOTHROW OS_NONNULL_ALL +int +os_sync_wake_by_address_any(void *addr, + size_t size, + os_sync_wake_by_address_flags_t flags); + +/*! + * @function os_sync_wake_by_address_all + * + * 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_WAIT_ON_ADDR_AVAILABILITY +OS_EXPORT OS_NOTHROW OS_NONNULL_ALL +int +os_sync_wake_by_address_all(void *addr, + size_t size, + os_sync_wake_by_address_flags_t flags); + +__END_DECLS + +OS_ASSUME_NONNULL_END + +#endif // __OS_SYNC_WAIT_ON_ADDRESS__ diff --git a/tools/macos-headers.c b/tools/macos-headers.c index b739f8f2dfe7ef23fe73757c79192d3a8f3efd27..6346ff51a871ae0e4c5b786cdade809d45973185 100644 --- a/tools/macos-headers.c +++ b/tools/macos-headers.c @@ -190,6 +190,7 @@ #include #include #include +#include #include #include #include