master
  1/*
  2 * Copyright (c) 2016 Apple Inc. All rights reserved.
  3 *
  4 * @APPLE_APACHE_LICENSE_HEADER_START@
  5 *
  6 * Licensed under the Apache License, Version 2.0 (the "License");
  7 * you may not use this file except in compliance with the License.
  8 * You may obtain a copy of the License at
  9 *
 10 *     http://www.apache.org/licenses/LICENSE-2.0
 11 *
 12 * Unless required by applicable law or agreed to in writing, software
 13 * distributed under the License is distributed on an "AS IS" BASIS,
 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15 * See the License for the specific language governing permissions and
 16 * limitations under the License.
 17 *
 18 * @APPLE_APACHE_LICENSE_HEADER_END@
 19 */
 20
 21#ifndef __OS_LOCK__
 22#define __OS_LOCK__
 23
 24#include <Availability.h>
 25#include <sys/cdefs.h>
 26#include <stddef.h>
 27#include <stdint.h>
 28#include <stdbool.h>
 29#include <os/base.h>
 30
 31OS_ASSUME_NONNULL_BEGIN
 32
 33/*! @header
 34 * Low-level lock API.
 35 */
 36
 37#define OS_LOCK_API_VERSION 20160309
 38
 39__BEGIN_DECLS
 40
 41#define OS_UNFAIR_LOCK_AVAILABILITY \
 42		__API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))
 43
 44/*!
 45 * @typedef os_unfair_lock
 46 *
 47 * @abstract
 48 * Low-level lock that allows waiters to block efficiently on contention.
 49 *
 50 * os_unfair_lock is an appropriate lock for cases where simple and lightweight
 51 * mutual exclusion is needed.
 52 * It can be intrusively stored inline in a datastructure without needing a
 53 * separate allocation, reducing memory consumption and cost of indirection.
 54 * For situations where something more sophisticated like condition waits or
 55 * FIFO ordering is needed, use appropriate higher level APIs such as those from
 56 * the pthread or dispatch subsystems.
 57 *
 58 * The values stored in the lock should be considered opaque and implementation
 59 * defined, they contain thread ownership information that the system may use
 60 * to attempt to resolve priority inversions.
 61 *
 62 * This lock must be unlocked from the same thread that locked it, attempts to
 63 * unlock from a different thread will cause an assertion aborting the process.
 64 *
 65 * This lock must not be accessed from multiple processes or threads via shared
 66 * or multiply-mapped memory, because the lock implementation relies on the
 67 * address of the lock value and identity of the owning process.
 68 *
 69 * Must be initialized with OS_UNFAIR_LOCK_INIT.
 70 *
 71 * @discussion
 72 * The name 'unfair' indicates that there is no attempt at enforcing acquisition
 73 * fairness, e.g. an unlocker can potentially immediately reacquire the lock
 74 * before a woken up waiter gets an opportunity to attempt to acquire the lock.
 75 * This is often advantageous for performance reasons, but also makes starvation
 76 * of waiters a possibility.
 77 *
 78 * This lock is suitable as a drop-in replacement for the deprecated OSSpinLock,
 79 * providing much better behavior under contention.
 80 *
 81 * In Swift, note that use of the `&` operator on an unfair lock can copy or move
 82 * the lock memory, leading to misbehavior. Use an OSAllocatedUnfairLock to safely wrap
 83 * access to the lock memory instead. If you use os_unfair_lock APIs directly,
 84 * always make sure to store and use the lock in memory with a stable address.
 85 */
 86OS_UNFAIR_LOCK_AVAILABILITY
 87typedef struct os_unfair_lock_s {
 88	uint32_t _os_unfair_lock_opaque;
 89} os_unfair_lock, *os_unfair_lock_t;
 90
 91#ifndef OS_UNFAIR_LOCK_INIT
 92#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
 93#define OS_UNFAIR_LOCK_INIT ((os_unfair_lock){0})
 94#elif defined(__cplusplus) && __cplusplus >= 201103L
 95#define OS_UNFAIR_LOCK_INIT (os_unfair_lock{})
 96#elif defined(__cplusplus)
 97#define OS_UNFAIR_LOCK_INIT (os_unfair_lock())
 98#else
 99#define OS_UNFAIR_LOCK_INIT {0}
100#endif
101#endif // OS_UNFAIR_LOCK_INIT
102
103/*!
104 * @function os_unfair_lock_lock
105 *
106 * @abstract
107 * Locks an os_unfair_lock.
108 *
109 * @param lock
110 * Pointer to an os_unfair_lock.
111 */
112OS_UNFAIR_LOCK_AVAILABILITY
113OS_EXPORT OS_NOTHROW OS_NONNULL_ALL
114OS_SWIFT_UNAVAILABLE_FROM_ASYNC("Use OSAllocatedUnfairLock.performWhileLocked() for async-safe scoped locking")
115void os_unfair_lock_lock(os_unfair_lock_t lock);
116
117/*!
118 * @function os_unfair_lock_trylock
119 *
120 * @abstract
121 * Locks an os_unfair_lock if it is not already locked.
122 *
123 * @discussion
124 * It is invalid to surround this function with a retry loop, if this function
125 * returns false, the program must be able to proceed without having acquired
126 * the lock, or it must call os_unfair_lock_lock() directly (a retry loop around
127 * os_unfair_lock_trylock() amounts to an inefficient implementation of
128 * os_unfair_lock_lock() that hides the lock waiter from the system and prevents
129 * resolution of priority inversions).
130 *
131 * @param lock
132 * Pointer to an os_unfair_lock.
133 *
134 * @result
135 * Returns true if the lock was succesfully locked and false if the lock was
136 * already locked.
137 */
138OS_UNFAIR_LOCK_AVAILABILITY
139OS_EXPORT OS_NOTHROW OS_WARN_RESULT OS_NONNULL_ALL
140OS_SWIFT_UNAVAILABLE_FROM_ASYNC("Use OSAllocatedUnfairLock.tryPerformWhileLocked() for async-safe scoped locking")
141bool os_unfair_lock_trylock(os_unfair_lock_t lock);
142
143/*!
144 * @function os_unfair_lock_unlock
145 *
146 * @abstract
147 * Unlocks an os_unfair_lock.
148 *
149 * @param lock
150 * Pointer to an os_unfair_lock.
151 */
152OS_UNFAIR_LOCK_AVAILABILITY
153OS_EXPORT OS_NOTHROW OS_NONNULL_ALL
154OS_SWIFT_UNAVAILABLE_FROM_ASYNC("Use OSAllocatedUnfairLock.performWhileLocked() for async-safe scoped locking")
155void os_unfair_lock_unlock(os_unfair_lock_t lock);
156
157/*!
158 * @function os_unfair_lock_assert_owner
159 *
160 * @abstract
161 * Asserts that the calling thread is the current owner of the specified
162 * unfair lock.
163 *
164 * @discussion
165 * If the lock is currently owned by the calling thread, this function returns.
166 *
167 * If the lock is unlocked or owned by a different thread, this function
168 * asserts and terminates the process.
169 *
170 * @param lock
171 * Pointer to an os_unfair_lock.
172 */
173OS_UNFAIR_LOCK_AVAILABILITY
174OS_EXPORT OS_NOTHROW OS_NONNULL_ALL
175void os_unfair_lock_assert_owner(const os_unfair_lock *lock);
176
177/*!
178 * @function os_unfair_lock_assert_not_owner
179 *
180 * @abstract
181 * Asserts that the calling thread is not the current owner of the specified
182 * unfair lock.
183 *
184 * @discussion
185 * If the lock is unlocked or owned by a different thread, this function
186 * returns.
187 *
188 * If the lock is currently owned by the current thread, this function asserts
189 * and terminates the process.
190 *
191 * @param lock
192 * Pointer to an os_unfair_lock.
193 */
194OS_UNFAIR_LOCK_AVAILABILITY
195OS_EXPORT OS_NOTHROW OS_NONNULL_ALL
196void os_unfair_lock_assert_not_owner(const os_unfair_lock *lock);
197
198/*!
199 * @typedef os_unfair_lock_flags_t
200 *
201 * @const OS_UNFAIR_LOCK_FLAG_ADAPTIVE_SPIN
202 * This flag allows the caller of os_unfair_lock_lock_with_flags API to spin
203 * temporarily before blocking, particularly useful when the holder of the
204 * lock is on core. This should only be used for locks where the protected
205 * critical section is always extremely short.
206 */
207OS_REFINED_FOR_SWIFT
208OS_OPTIONS(os_unfair_lock_flags, uint32_t,
209	OS_UNFAIR_LOCK_FLAG_NONE
210		__API_AVAILABLE(macos(15.0), ios(18.0),
211		tvos(18.0), watchos(11.0), visionos(2.0))
212		OS_SWIFT_UNAVAILABLE("Use OSAllocatedUnfairLock APIs that do not require flags.")
213		= 0x00000000,
214	OS_UNFAIR_LOCK_FLAG_ADAPTIVE_SPIN
215		__API_AVAILABLE(macos(15.0), ios(18.0),
216		tvos(18.0), watchos(11.0), visionos(2.0))
217		OS_SWIFT_UNAVAILABLE("Use OSAllocatedUnfairLockFlags.AdaptiveSpin")
218		= 0x00040000,
219);
220
221/*!
222 * @function os_unfair_lock_lock_with_flags
223 *
224 * @abstract
225 * Locks an os_unfair_lock.
226 *
227 * @param lock
228 * Pointer to an os_unfair_lock.
229 *
230 * @param flags
231 * Flags to alter the behavior of the lock. See os_unfair_lock_flags_t.
232 */
233__API_AVAILABLE(macos(15.0), ios(18.0), tvos(18.0), watchos(11.0), visionos(2.0))
234OS_EXPORT OS_NOTHROW OS_NONNULL_ALL
235OS_SWIFT_UNAVAILABLE_FROM_ASYNC("Use OSAllocatedUnfairLock for async-safe scoped locking")
236void os_unfair_lock_lock_with_flags(os_unfair_lock_t lock,
237	os_unfair_lock_flags_t flags);
238
239__END_DECLS
240
241OS_ASSUME_NONNULL_END
242
243#endif // __OS_LOCK__