xref: /xnu-10063.141.1/osfmk/kern/lock_rw.h (revision d8b80295118ef25ac3a784134bcf95cd8e88109f)
1 /*
2  * Copyright (c) 2021 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #ifndef _KERN_RW_LOCK_H_
30 #define _KERN_RW_LOCK_H_
31 
32 #include <kern/lock_types.h>
33 #include <kern/lock_group.h>
34 #include <kern/lock_attr.h>
35 
36 #ifdef  XNU_KERNEL_PRIVATE
37 #include <kern/startup.h>
38 #endif /* XNU_KERNEL_PRIVATE */
39 
40 __BEGIN_DECLS
41 
42 #ifdef  MACH_KERNEL_PRIVATE
43 
44 typedef union {
45 	struct {
46 		uint16_t        shared_count;       /* No. of shared granted request */
47 		uint16_t
48 		    interlock:              1,      /* Interlock */
49 		    priv_excl:              1,      /* priority for Writer */
50 		    want_upgrade:           1,      /* Read-to-write upgrade waiting */
51 		    want_excl:              1,      /* Writer is waiting, or locked for write */
52 		    r_waiting:              1,      /* Someone is sleeping on lock */
53 		    w_waiting:              1,      /* Writer is sleeping on lock */
54 		    can_sleep:              1,      /* Can attempts to lock go to sleep? */
55 		    _pad2:                  8,      /* padding */
56 		    tag_valid:              1;      /* Field is actually a tag, not a bitfield */
57 	};
58 	uint32_t        data;                       /* Single word version of bitfields and shared count */
59 } lck_rw_word_t;
60 
61 typedef struct {
62 	uint32_t        lck_rw_unused : 24; /* tsid one day ... */
63 	uint32_t        lck_rw_type   :  8; /* LCK_TYPE_RW */
64 	uint32_t        lck_rw_padding;
65 	lck_rw_word_t   lck_rw;
66 	uint32_t        lck_rw_owner;       /* ctid_t */
67 } lck_rw_t;     /* arm: 8  arm64: 16 x86: 16 */
68 
69 #define lck_rw_shared_count     lck_rw.shared_count
70 #define lck_rw_interlock        lck_rw.interlock
71 #define lck_rw_priv_excl        lck_rw.priv_excl
72 #define lck_rw_want_upgrade     lck_rw.want_upgrade
73 #define lck_rw_want_excl        lck_rw.want_excl
74 #define lck_r_waiting           lck_rw.r_waiting
75 #define lck_w_waiting           lck_rw.w_waiting
76 #define lck_rw_can_sleep        lck_rw.can_sleep
77 #define lck_rw_data             lck_rw.data
78 // tag and data reference the same memory. When the tag_valid bit is set,
79 // the data word should be treated as a tag instead of a bitfield.
80 #define lck_rw_tag_valid        lck_rw.tag_valid
81 #define lck_rw_tag              lck_rw.data
82 
83 #define LCK_RW_SHARED_READER_OFFSET      0
84 #define LCK_RW_INTERLOCK_BIT            16
85 #define LCK_RW_PRIV_EXCL_BIT            17
86 #define LCK_RW_WANT_UPGRADE_BIT         18
87 #define LCK_RW_WANT_EXCL_BIT            19
88 #define LCK_RW_R_WAITING_BIT            20
89 #define LCK_RW_W_WAITING_BIT            21
90 #define LCK_RW_CAN_SLEEP_BIT            22
91 //                                      23-30
92 #define LCK_RW_TAG_VALID_BIT            31
93 
94 #define LCK_RW_INTERLOCK                (1U << LCK_RW_INTERLOCK_BIT)
95 #define LCK_RW_R_WAITING                (1U << LCK_RW_R_WAITING_BIT)
96 #define LCK_RW_W_WAITING                (1U << LCK_RW_W_WAITING_BIT)
97 #define LCK_RW_WANT_UPGRADE             (1U << LCK_RW_WANT_UPGRADE_BIT)
98 #define LCK_RW_WANT_EXCL                (1U << LCK_RW_WANT_EXCL_BIT)
99 #define LCK_RW_TAG_VALID                (1U << LCK_RW_TAG_VALID_BIT)
100 #define LCK_RW_PRIV_EXCL                (1U << LCK_RW_PRIV_EXCL_BIT)
101 #define LCK_RW_SHARED_MASK              (0xffff << LCK_RW_SHARED_READER_OFFSET)
102 #define LCK_RW_SHARED_READER            (0x1 << LCK_RW_SHARED_READER_OFFSET)
103 
104 #define LCK_RW_TAG_DESTROYED            ((LCK_RW_TAG_VALID | 0xdddddeadu))      /* lock marked as Destroyed */
105 
106 #elif KERNEL_PRIVATE
107 typedef struct {
108 	uintptr_t               opaque[2] __kernel_data_semantics;
109 } lck_rw_t;
110 #else /* @KERNEL_PRIVATE */
111 typedef struct __lck_rw_t__     lck_rw_t;
112 #endif /* !KERNEL_PRIVATE */
113 
114 #if DEVELOPMENT || DEBUG
115 #ifdef XNU_KERNEL_PRIVATE
116 
117 #define DEBUG_RW                        1
118 #define LCK_RW_EXPECTED_MAX_NUMBER      3       /* Expected number per thread of concurrently held rw_lock */
119 
120 #if __LP64__
121 #define LCK_RW_CALLER_PACKED_BITS   48
122 #define LCK_RW_CALLER_PACKED_SHIFT   0
123 #define LCK_RW_CALLER_PACKED_BASE    0
124 #else
125 #define LCK_RW_CALLER_PACKED_BITS   32
126 #define LCK_RW_CALLER_PACKED_SHIFT   0
127 #define LCK_RW_CALLER_PACKED_BASE    0
128 #endif
129 
130 _Static_assert(!VM_PACKING_IS_BASE_RELATIVE(LCK_RW_CALLER_PACKED),
131     "Make sure the rwlde_caller_packed pointer packing is based on arithmetic shifts");
132 
133 
134 struct __attribute__ ((packed)) rw_lock_debug_entry {
135 	lck_rw_t      *rwlde_lock;                                       // rw_lock held
136 	int8_t        rwlde_mode_count;                                  // -1 is held in write mode, positive value is the recursive read count
137 #if __LP64__
138 	uintptr_t     rwlde_caller_packed: LCK_RW_CALLER_PACKED_BITS;    // caller that created the entry
139 #else
140 	uintptr_t     rwlde_caller_packed;                               // caller that created the entry
141 #endif
142 };
143 typedef struct rw_lock_debug {
144 	struct rw_lock_debug_entry rwld_locks[LCK_RW_EXPECTED_MAX_NUMBER]; /* rw_lock debug info of currently held locks */
145 	uint8_t                    rwld_locks_saved : 7,                   /* number of locks saved in rwld_locks */
146 	    rwld_overflow : 1;                                             /* lock_entry was full, so it might be inaccurate */
147 	uint32_t                   rwld_locks_acquired;                    /* number of locks acquired */
148 } rw_lock_debug_t;
149 
150 _Static_assert(LCK_RW_EXPECTED_MAX_NUMBER <= 127, "LCK_RW_EXPECTED_MAX_NUMBER bigger than rwld_locks_saved");
151 
152 #endif /* XNU_KERNEL_PRIVATE */
153 #endif /* DEVELOPMENT || DEBUG */
154 
155 typedef unsigned int     lck_rw_type_t;
156 
157 #define LCK_RW_TYPE_SHARED              0x01
158 #define LCK_RW_TYPE_EXCLUSIVE           0x02
159 
160 #define decl_lck_rw_data(class, name)   class lck_rw_t name
161 
162 #if XNU_KERNEL_PRIVATE
163 /*
164  * Auto-initializing rw-locks declarations
165  * ------------------------------------
166  *
167  * Unless you need to configure your locks in very specific ways,
168  * there is no point creating explicit lock attributes. For most
169  * static locks, this declaration macro can be used:
170  *
171  * - LCK_RW_DECLARE.
172  *
173  * For cases when some particular attributes need to be used,
174  * LCK_RW_DECLARE_ATTR takes a variable declared with
175  * LCK_ATTR_DECLARE as an argument.
176  */
177 
178 struct lck_rw_startup_spec {
179 	lck_rw_t                *lck;
180 	lck_grp_t               *lck_grp;
181 	lck_attr_t              *lck_attr;
182 };
183 
184 extern void             lck_rw_startup_init(
185 	struct lck_rw_startup_spec *spec);
186 
187 #define LCK_RW_DECLARE_ATTR(var, grp, attr) \
188 	lck_rw_t var; \
189 	static __startup_data struct lck_rw_startup_spec \
190 	__startup_lck_rw_spec_ ## var = { &var, grp, attr }; \
191 	STARTUP_ARG(LOCKS, STARTUP_RANK_FOURTH, lck_rw_startup_init, \
192 	    &__startup_lck_rw_spec_ ## var)
193 
194 #define LCK_RW_DECLARE(var, grp) \
195 	LCK_RW_DECLARE_ATTR(var, grp, LCK_ATTR_NULL)
196 
197 #define LCK_RW_ASSERT_SHARED    0x01
198 #define LCK_RW_ASSERT_EXCLUSIVE 0x02
199 #define LCK_RW_ASSERT_HELD      0x03
200 #define LCK_RW_ASSERT_NOTHELD   0x04
201 
202 #if MACH_ASSERT
203 extern boolean_t lck_rw_assert_enabled;
204 #define LCK_RW_ASSERT(lck, type) do { \
205 	        if (__improbable(!(lck_opts_get() & LCK_OPTION_DISABLE_RW_DEBUG))) { \
206 	                lck_rw_assert((lck),(type)); \
207 	        } \
208 	} while (0)
209 #else /* MACH_ASSERT */
210 #define LCK_RW_ASSERT(lck, type)
211 #endif /* MACH_ASSERT */
212 
213 #endif /* XNU_KERNEL_PRIVATE */
214 
215 
216 /*!
217  * @function lck_rw_alloc_init
218  *
219  * @abstract
220  * Allocates and initializes a rw_lock_t.
221  *
222  * @discussion
223  * The function can block. See lck_rw_init() for initialization details.
224  *
225  * @param grp           lock group to associate with the lock.
226  * @param attr          lock attribute to initialize the lock.
227  *
228  * @returns             NULL or the allocated lock
229  */
230 extern lck_rw_t         *lck_rw_alloc_init(
231 	lck_grp_t               *grp,
232 	lck_attr_t              *attr);
233 
234 /*!
235  * @function lck_rw_init
236  *
237  * @abstract
238  * Initializes a rw_lock_t.
239  *
240  * @discussion
241  * Usage statistics for the lock are going to be added to the lock group provided.
242  *
243  * The lock attribute can be LCK_ATTR_NULL or an attribute can be allocated with
244  * lck_attr_alloc_init. So far however none of the attribute settings are supported.
245  *
246  * @param lck           lock to initialize.
247  * @param grp           lock group to associate with the lock.
248  * @param attr          lock attribute to initialize the lock.
249  */
250 extern void             lck_rw_init(
251 	lck_rw_t                *lck,
252 	lck_grp_t               *grp,
253 	lck_attr_t              *attr);
254 
255 /*!
256  * @function lck_rw_free
257  *
258  * @abstract
259  * Frees a rw_lock previously allocated with lck_rw_alloc_init().
260  *
261  * @discussion
262  * The lock must be not held by any thread.
263  *
264  * @param lck           rw_lock to free.
265  */
266 extern void             lck_rw_free(
267 	lck_rw_t                *lck,
268 	lck_grp_t               *grp);
269 
270 /*!
271  * @function lck_rw_destroy
272  *
273  * @abstract
274  * Destroys a rw_lock previously initialized with lck_rw_init().
275  *
276  * @discussion
277  * The lock must be not held by any thread.
278  *
279  * @param lck           rw_lock to destroy.
280  */
281 extern void             lck_rw_destroy(
282 	lck_rw_t                *lck,
283 	lck_grp_t               *grp);
284 
285 /*!
286  * @function lck_rw_lock
287  *
288  * @abstract
289  * Locks a rw_lock with the specified type.
290  *
291  * @discussion
292  * See lck_rw_lock_shared() or lck_rw_lock_exclusive() for more details.
293  *
294  * @param lck           rw_lock to lock.
295  * @param lck_rw_type   LCK_RW_TYPE_SHARED or LCK_RW_TYPE_EXCLUSIVE
296  */
297 extern void             lck_rw_lock(
298 	lck_rw_t                *lck,
299 	lck_rw_type_t           lck_rw_type);
300 
301 /*!
302  * @function lck_rw_try_lock
303  *
304  * @abstract
305  * Tries to locks a rw_lock with the specified type.
306  *
307  * @discussion
308  * This function will return and not wait/block in case the lock is already held.
309  * See lck_rw_try_lock_shared() or lck_rw_try_lock_exclusive() for more details.
310  *
311  * @param lck           rw_lock to lock.
312  * @param lck_rw_type   LCK_RW_TYPE_SHARED or LCK_RW_TYPE_EXCLUSIVE
313  *
314  * @returns TRUE if the lock is successfully acquired, FALSE in case it was already held.
315  */
316 extern boolean_t        lck_rw_try_lock(
317 	lck_rw_t                *lck,
318 	lck_rw_type_t           lck_rw_type);
319 
320 /*!
321  * @function lck_rw_unlock
322  *
323  * @abstract
324  * Unlocks a rw_lock previously locked with lck_rw_type.
325  *
326  * @discussion
327  * The lock must be unlocked by the same thread it was locked from.
328  * The type of the lock/unlock have to match, unless an upgrade/downgrade was performed while
329  * holding the lock.
330  *
331  * @param lck           rw_lock to unlock.
332  * @param lck_rw_type   LCK_RW_TYPE_SHARED or LCK_RW_TYPE_EXCLUSIVE
333  */
334 extern void             lck_rw_unlock(
335 	lck_rw_t                *lck,
336 	lck_rw_type_t           lck_rw_type);
337 
338 /*!
339  * @function lck_rw_lock_shared
340  *
341  * @abstract
342  * Locks a rw_lock in shared mode.
343  *
344  * @discussion
345  * This function can block.
346  * Multiple threads can acquire the lock in shared mode at the same time, but only one thread at a time
347  * can acquire it in exclusive mode.
348  * If the lock is held in shared mode and there are no writers waiting, a reader will be able to acquire
349  * the lock without waiting.
350  * If the lock is held in shared mode and there is at least a writer waiting, a reader will wait
351  * for all the writers to make progress.
352  * NOTE: the thread cannot return to userspace while the lock is held. Recursive locking is not supported.
353  *
354  * @param lck           rw_lock to lock.
355  */
356 extern void             lck_rw_lock_shared(
357 	lck_rw_t                *lck);
358 
359 
360 #if MACH_KERNEL_PRIVATE
361 /*!
362  * @function lck_rw_lock_shared_b
363  *
364  * @abstract
365  * Locks a rw_lock in shared mode. Returns early if the lock can't be acquired
366  * and the specified block returns true.
367  *
368  * @discussion
369  * Identical to lck_rw_lock_shared() but can return early if the lock can't be
370  * acquired and the specified block returns true. The block is called
371  * repeatedly when waiting to acquire the lock.
372  * Should only be called when the lock cannot sleep (i.e. when
373  * lock->lck_rw_can_sleep is false).
374  *
375  * @param lock           rw_lock to lock.
376  * @param lock_pause     block invoked while waiting to acquire lock
377  *
378  * @returns              Returns TRUE if the lock is successfully taken,
379  *                       FALSE if the block returns true and the lock has
380  *                       not been acquired.
381  */
382 extern boolean_t
383     lck_rw_lock_shared_b(
384 	lck_rw_t        * lock,
385 	bool            (^lock_pause)(void));
386 
387 /*!
388  * @function lck_rw_lock_exclusive_b
389  *
390  * @abstract
391  * Locks a rw_lock in exclusive mode. Returns early if the lock can't be acquired
392  * and the specified block returns true.
393  *
394  * @discussion
395  * Identical to lck_rw_lock_exclusive() but can return early if the lock can't be
396  * acquired and the specified block returns true. The block is called
397  * repeatedly when waiting to acquire the lock.
398  * Should only be called when the lock cannot sleep (i.e. when
399  * lock->lck_rw_can_sleep is false).
400  *
401  * @param lock           rw_lock to lock.
402  * @param lock_pause     block invoked while waiting to acquire lock
403  *
404  * @returns              Returns TRUE if the lock is successfully taken,
405  *                       FALSE if the block returns true and the lock has
406  *                       not been acquired.
407  */
408 extern boolean_t
409     lck_rw_lock_exclusive_b(
410 	lck_rw_t        * lock,
411 	bool            (^lock_pause)(void));
412 #endif /* MACH_KERNEL_PRIVATE */
413 
414 /*!
415  * @function lck_rw_lock_shared_to_exclusive
416  *
417  * @abstract
418  * Upgrades a rw_lock held in shared mode to exclusive.
419  *
420  * @discussion
421  * This function can block.
422  * Only one reader at a time can upgrade to exclusive mode. If the upgrades fails the function will
423  * return with the lock not held.
424  * The caller needs to hold the lock in shared mode to upgrade it.
425  *
426  * @param lck           rw_lock already held in shared mode to upgrade.
427  *
428  * @returns TRUE if the lock was upgraded, FALSE if it was not possible.
429  *          If the function was not able to upgrade the lock, the lock will be dropped
430  *          by the function.
431  */
432 extern boolean_t        lck_rw_lock_shared_to_exclusive(
433 	lck_rw_t                *lck);
434 
435 /*!
436  * @function lck_rw_unlock_shared
437  *
438  * @abstract
439  * Unlocks a rw_lock previously locked in shared mode.
440  *
441  * @discussion
442  * The same thread that locked the lock needs to unlock it.
443  *
444  * @param lck           rw_lock held in shared mode to unlock.
445  */
446 extern void             lck_rw_unlock_shared(
447 	lck_rw_t                *lck);
448 
449 /*!
450  * @function lck_rw_lock_exclusive
451  *
452  * @abstract
453  * Locks a rw_lock in exclusive mode.
454  *
455  * @discussion
456  * This function can block.
457  * Multiple threads can acquire the lock in shared mode at the same time, but only one thread at a time
458  * can acquire it in exclusive mode.
459  * NOTE: the thread cannot return to userspace while the lock is held. Recursive locking is not supported.
460  *
461  * @param lck           rw_lock to lock.
462  */
463 extern void             lck_rw_lock_exclusive(
464 	lck_rw_t                *lck);
465 
466 /*!
467  * @function lck_rw_lock_exclusive_to_shared
468  *
469  * @abstract
470  * Downgrades a rw_lock held in exclusive mode to shared.
471  *
472  * @discussion
473  * The caller needs to hold the lock in exclusive mode to be able to downgrade it.
474  *
475  * @param lck           rw_lock already held in exclusive mode to downgrade.
476  */
477 extern void             lck_rw_lock_exclusive_to_shared(
478 	lck_rw_t                *lck);
479 
480 /*!
481  * @function lck_rw_unlock_exclusive
482  *
483  * @abstract
484  * Unlocks a rw_lock previously locked in exclusive mode.
485  *
486  * @discussion
487  * The same thread that locked the lock needs to unlock it.
488  *
489  * @param lck           rw_lock held in exclusive mode to unlock.
490  */
491 extern void             lck_rw_unlock_exclusive(
492 	lck_rw_t                *lck);
493 
494 /*!
495  * @function lck_rw_sleep
496  *
497  * @abstract
498  * Assert_wait on an event while holding the rw_lock.
499  *
500  * @discussion
501  * the flags can decide how to re-acquire the lock upon wake up
502  * (LCK_SLEEP_SHARED, or LCK_SLEEP_EXCLUSIVE, or LCK_SLEEP_UNLOCK)
503  * and if the priority needs to be kept boosted until the lock is
504  * re-acquired (LCK_SLEEP_PROMOTED_PRI).
505  *
506  * @param lck                   rw_lock to use to synch the assert_wait.
507  * @param lck_sleep_action      flags.
508  * @param event                 event to assert_wait on.
509  * @param interruptible         wait type.
510  */
511 extern wait_result_t    lck_rw_sleep(
512 	lck_rw_t                *lck,
513 	lck_sleep_action_t      lck_sleep_action,
514 	event_t                 event,
515 	wait_interrupt_t        interruptible);
516 
517 /*!
518  * @function lck_rw_sleep_deadline
519  *
520  * @abstract
521  * Assert_wait_deadline on an event while holding the rw_lock.
522  *
523  * @discussion
524  * the flags can decide how to re-acquire the lock upon wake up
525  * (LCK_SLEEP_SHARED, or LCK_SLEEP_EXCLUSIVE, or LCK_SLEEP_UNLOCK)
526  * and if the priority needs to be kept boosted until the lock is
527  * re-acquired (LCK_SLEEP_PROMOTED_PRI).
528  *
529  * @param lck                   rw_lock to use to synch the assert_wait.
530  * @param lck_sleep_action      flags.
531  * @param event                 event to assert_wait on.
532  * @param interruptible         wait type.
533  * @param deadline              maximum time after which being woken up
534  */
535 extern wait_result_t    lck_rw_sleep_deadline(
536 	lck_rw_t                *lck,
537 	lck_sleep_action_t      lck_sleep_action,
538 	event_t                 event,
539 	wait_interrupt_t        interruptible,
540 	uint64_t                deadline);
541 
542 #ifdef  XNU_KERNEL_PRIVATE
543 /*!
544  * @function lck_rw_assert
545  *
546  * @abstract
547  * Asserts the rw_lock is held.
548  *
549  * @discussion
550  * read-write locks do not have a concept of ownership when held in shared mode,
551  * so this function merely asserts that someone is holding the lock, not necessarily the caller.
552  * However if rw_lock_debug is on, a best effort mechanism to track the owners is in place, and
553  * this function can be more accurate.
554  * Type can be LCK_RW_ASSERT_SHARED, LCK_RW_ASSERT_EXCLUSIVE, LCK_RW_ASSERT_HELD
555  * LCK_RW_ASSERT_NOTHELD.
556  *
557  * @param lck   rw_lock to check.
558  * @param type  assert type
559  */
560 extern void             lck_rw_assert(
561 	lck_rw_t                *lck,
562 	unsigned int            type);
563 
564 /*!
565  * @function kdp_lck_rw_lock_is_acquired_exclusive
566  *
567  * @abstract
568  * Checks if a rw_lock is held exclusevely.
569  *
570  * @discussion
571  * NOT SAFE: To be used only by kernel debugger to avoid deadlock.
572  *
573  * @param lck   lock to check
574  *
575  * @returns TRUE if the lock is held exclusevely
576  */
577 extern boolean_t        kdp_lck_rw_lock_is_acquired_exclusive(
578 	lck_rw_t                *lck);
579 
580 /*!
581  * @function lck_rw_lock_exclusive_check_contended
582  *
583  * @abstract
584  * Locks a rw_lock in exclusive mode.
585  *
586  * @discussion
587  * This routine IS EXPERIMENTAL.
588  * It's only used for the vm object lock, and use for other subsystems is UNSUPPORTED.
589  * Note that the return value is ONLY A HEURISTIC w.r.t. the lock's contention.
590  *
591  * @param lck           rw_lock to lock.
592  *
593  * @returns Returns TRUE if the thread spun or blocked while attempting to acquire the lock, FALSE
594  *          otherwise.
595  */
596 extern bool             lck_rw_lock_exclusive_check_contended(
597 	lck_rw_t                *lck);
598 
599 /*!
600  * @function lck_rw_lock_yield_shared
601  *
602  * @abstract
603  * Yields a rw_lock held in shared mode.
604  *
605  * @discussion
606  * This function can block.
607  * Yields the lock in case there are writers waiting.
608  * The yield will unlock, block, and re-lock the lock in shared mode.
609  *
610  * @param lck           rw_lock already held in shared mode to yield.
611  * @param force_yield   if set to true it will always yield irrespective of the lock status
612  *
613  * @returns TRUE if the lock was yield, FALSE otherwise
614  */
615 extern bool             lck_rw_lock_yield_shared(
616 	lck_rw_t                *lck,
617 	boolean_t               force_yield);
618 
619 __enum_decl(lck_rw_yield_t, uint32_t, {
620 	LCK_RW_YIELD_WRITERS_ONLY,
621 	LCK_RW_YIELD_ANY_WAITER,
622 	LCK_RW_YIELD_ALWAYS,
623 });
624 
625 /*!
626  * @function lck_rw_lock_yield_exclusive
627  *
628  * @abstract
629  * Yields a rw_lock held in exclusive mode.
630  *
631  * @discussion
632  * This function can block.
633  * Yields the lock in case there are writers waiting.
634  * The yield will unlock, block, and re-lock the lock in exclusive mode.
635  *
636  * @param lck           rw_lock already held in exclusive mode to yield.
637  * @param mode          when to yield.
638  *
639  * @returns TRUE if the lock was yield, FALSE otherwise
640  */
641 extern bool             lck_rw_lock_yield_exclusive(
642 	lck_rw_t                *lck,
643 	lck_rw_yield_t          mode);
644 
645 #endif /* XNU_KERNEL_PRIVATE */
646 
647 #if MACH_KERNEL_PRIVATE
648 
649 /*!
650  * @function lck_rw_lock_count_inc
651  *
652  * @abstract
653  * Increments the number of rwlock held by the (current) thread.
654  */
655 extern void lck_rw_lock_count_inc(
656 	thread_t                thread,
657 	const void             *lock);
658 
659 /*!
660  * @function lck_rw_lock_count_inc
661  *
662  * @abstract
663  * Decrements the number of rwlock held by the (current) thread.
664  */
665 extern void lck_rw_lock_count_dec(
666 	thread_t                thread,
667 	const void             *lock);
668 
669 /*!
670  * @function lck_rw_set_promotion_locked
671  *
672  * @abstract
673  * Callout from context switch if the thread goes
674  * off core with a positive rwlock_count.
675  *
676  * @discussion
677  * Called at splsched with the thread locked.
678  *
679  * @param thread        thread to promote.
680  */
681 extern void             lck_rw_set_promotion_locked(
682 	thread_t                thread);
683 
684 #endif /* MACH_KERNEL_PRIVATE */
685 
686 #ifdef  KERNEL_PRIVATE
687 /*!
688  * @function lck_rw_try_lock_shared
689  *
690  * @abstract
691  * Tries to locks a rw_lock in read mode.
692  *
693  * @discussion
694  * This function will return and not block in case the lock is already held.
695  * See lck_rw_lock_shared for more details.
696  *
697  * @param lck           rw_lock to lock.
698  *
699  * @returns TRUE if the lock is successfully acquired, FALSE in case it was already held.
700  */
701 extern boolean_t        lck_rw_try_lock_shared(
702 	lck_rw_t                *lck);
703 
704 /*!
705  * @function lck_rw_try_lock_exclusive
706  *
707  * @abstract
708  * Tries to locks a rw_lock in write mode.
709  *
710  * @discussion
711  * This function will return and not block in case the lock is already held.
712  * See lck_rw_lock_exclusive for more details.
713  *
714  * @param lck           rw_lock to lock.
715  *
716  * @returns TRUE if the lock is successfully acquired, FALSE in case it was already held.
717  */
718 extern boolean_t        lck_rw_try_lock_exclusive(
719 	lck_rw_t                *lck);
720 
721 /*!
722  * @function lck_rw_done
723  *
724  * @abstract
725  * Force unlocks a rw_lock without consistency checks.
726  *
727  * @discussion
728  * Do not use unless sure you can avoid consistency checks.
729  *
730  * @param lck           rw_lock to unlock.
731  */
732 extern lck_rw_type_t    lck_rw_done(
733 	lck_rw_t                *lck);
734 #endif /* KERNEL_PRIVATE */
735 
736 __END_DECLS
737 
738 #endif /* _KERN_RW_LOCK_H_ */
739