2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
57 #define LOCK_PRIVATE 1
59 #include <mach_ldebug.h>
62 #include <mach/kern_return.h>
63 #include <mach/mach_host_server.h>
64 #include <mach_debug/lockgroup_info.h>
66 #include <kern/lock_stat.h>
67 #include <kern/locks.h>
68 #include <kern/misc_protos.h>
69 #include <kern/zalloc.h>
70 #include <kern/thread.h>
71 #include <kern/processor.h>
72 #include <kern/sched_prim.h>
73 #include <kern/debug.h>
74 #include <libkern/section_keywords.h>
75 #include <machine/atomic.h>
76 #include <machine/machine_cpu.h>
79 #include <sys/kdebug.h>
81 #define LCK_MTX_SLEEP_CODE 0
82 #define LCK_MTX_SLEEP_DEADLINE_CODE 1
83 #define LCK_MTX_LCK_WAIT_CODE 2
84 #define LCK_MTX_UNLCK_WAKEUP_CODE 3
87 #define ALIGN_TEST(p, t) do{if((uintptr_t)p&(sizeof(t)-1)) __builtin_trap();}while(0)
89 #define ALIGN_TEST(p, t) do{}while(0)
92 #define NOINLINE __attribute__((noinline))
94 #define ordered_load_hw(lock) os_atomic_load(&(lock)->lock_data, compiler_acq_rel)
95 #define ordered_store_hw(lock, value) os_atomic_store(&(lock)->lock_data, (value), compiler_acq_rel)
98 queue_head_t lck_grp_queue
;
99 unsigned int lck_grp_cnt
;
101 decl_lck_mtx_data(, lck_grp_lock
);
102 static lck_mtx_ext_t lck_grp_lock_ext
;
104 SECURITY_READ_ONLY_LATE(boolean_t
) spinlock_timeout_panic
= TRUE
;
106 /* Obtain "lcks" options:this currently controls lock statistics */
107 TUNABLE(uint32_t, LcksOpts
, "lcks", 0);
109 ZONE_VIEW_DEFINE(ZV_LCK_GRP_ATTR
, "lck_grp_attr",
110 KHEAP_ID_DEFAULT
, sizeof(lck_grp_attr_t
));
112 ZONE_VIEW_DEFINE(ZV_LCK_GRP
, "lck_grp",
113 KHEAP_ID_DEFAULT
, sizeof(lck_grp_t
));
115 ZONE_VIEW_DEFINE(ZV_LCK_ATTR
, "lck_attr",
116 KHEAP_ID_DEFAULT
, sizeof(lck_attr_t
));
118 lck_grp_attr_t LockDefaultGroupAttr
;
119 lck_grp_t LockCompatGroup
;
120 lck_attr_t LockDefaultLckAttr
;
123 #if defined (__x86_64__)
124 uint64_t dtrace_spin_threshold
= 500; // 500ns
125 #elif defined(__arm__) || defined(__arm64__)
126 uint64_t dtrace_spin_threshold
= LOCK_PANIC_TIMEOUT
/ 1000000; // 500ns
131 unslide_for_kdebug(void* object
)
133 if (__improbable(kdebug_enable
)) {
134 return VM_KERNEL_UNSLIDE_OR_PERM(object
);
144 queue_init(&lck_grp_queue
);
147 * Need to bootstrap the LockCompatGroup instead of calling lck_grp_init() here. This avoids
148 * grabbing the lck_grp_lock before it is initialized.
151 bzero(&LockCompatGroup
, sizeof(lck_grp_t
));
152 (void) strncpy(LockCompatGroup
.lck_grp_name
, "Compatibility APIs", LCK_GRP_MAX_NAME
);
154 LockCompatGroup
.lck_grp_attr
= LCK_ATTR_NONE
;
156 if (LcksOpts
& enaLkStat
) {
157 LockCompatGroup
.lck_grp_attr
|= LCK_GRP_ATTR_STAT
;
159 if (LcksOpts
& enaLkTimeStat
) {
160 LockCompatGroup
.lck_grp_attr
|= LCK_GRP_ATTR_TIME_STAT
;
163 os_ref_init(&LockCompatGroup
.lck_grp_refcnt
, NULL
);
165 enqueue_tail(&lck_grp_queue
, (queue_entry_t
)&LockCompatGroup
);
168 lck_grp_attr_setdefault(&LockDefaultGroupAttr
);
169 lck_attr_setdefault(&LockDefaultLckAttr
);
171 lck_mtx_init_ext(&lck_grp_lock
, &lck_grp_lock_ext
, &LockCompatGroup
, &LockDefaultLckAttr
);
173 STARTUP(LOCKS_EARLY
, STARTUP_RANK_FIRST
, lck_mod_init
);
176 * Routine: lck_grp_attr_alloc_init
180 lck_grp_attr_alloc_init(
183 lck_grp_attr_t
*attr
;
185 attr
= zalloc(ZV_LCK_GRP_ATTR
);
186 lck_grp_attr_setdefault(attr
);
192 * Routine: lck_grp_attr_setdefault
196 lck_grp_attr_setdefault(
197 lck_grp_attr_t
*attr
)
199 if (LcksOpts
& enaLkStat
) {
200 attr
->grp_attr_val
= LCK_GRP_ATTR_STAT
;
202 attr
->grp_attr_val
= 0;
208 * Routine: lck_grp_attr_setstat
212 lck_grp_attr_setstat(
213 lck_grp_attr_t
*attr
)
216 os_atomic_or(&attr
->grp_attr_val
, LCK_GRP_ATTR_STAT
, relaxed
);
221 * Routine: lck_grp_attr_free
226 lck_grp_attr_t
*attr
)
228 zfree(ZV_LCK_GRP_ATTR
, attr
);
233 * Routine: lck_grp_alloc_init
238 const char* grp_name
,
239 lck_grp_attr_t
*attr
)
243 grp
= zalloc(ZV_LCK_GRP
);
244 lck_grp_init(grp
, grp_name
, attr
);
249 * Routine: lck_grp_init
253 lck_grp_init(lck_grp_t
* grp
, const char * grp_name
, lck_grp_attr_t
* attr
)
255 /* make sure locking infrastructure has been initialized */
256 assert(lck_grp_cnt
> 0);
258 bzero((void *)grp
, sizeof(lck_grp_t
));
260 (void)strlcpy(grp
->lck_grp_name
, grp_name
, LCK_GRP_MAX_NAME
);
262 if (attr
!= LCK_GRP_ATTR_NULL
) {
263 grp
->lck_grp_attr
= attr
->grp_attr_val
;
265 grp
->lck_grp_attr
= 0;
266 if (LcksOpts
& enaLkStat
) {
267 grp
->lck_grp_attr
|= LCK_GRP_ATTR_STAT
;
269 if (LcksOpts
& enaLkTimeStat
) {
270 grp
->lck_grp_attr
|= LCK_GRP_ATTR_TIME_STAT
;
274 if (grp
->lck_grp_attr
& LCK_GRP_ATTR_STAT
) {
275 lck_grp_stats_t
*stats
= &grp
->lck_grp_stats
;
278 lck_grp_stat_enable(&stats
->lgss_spin_held
);
279 lck_grp_stat_enable(&stats
->lgss_spin_miss
);
280 #endif /* LOCK_STATS */
282 lck_grp_stat_enable(&stats
->lgss_mtx_held
);
283 lck_grp_stat_enable(&stats
->lgss_mtx_miss
);
284 lck_grp_stat_enable(&stats
->lgss_mtx_direct_wait
);
285 lck_grp_stat_enable(&stats
->lgss_mtx_wait
);
287 if (grp
->lck_grp_attr
& LCK_GRP_ATTR_TIME_STAT
) {
289 lck_grp_stats_t
*stats
= &grp
->lck_grp_stats
;
290 lck_grp_stat_enable(&stats
->lgss_spin_spin
);
291 #endif /* LOCK_STATS */
294 os_ref_init(&grp
->lck_grp_refcnt
, NULL
);
296 lck_mtx_lock(&lck_grp_lock
);
297 enqueue_tail(&lck_grp_queue
, (queue_entry_t
)grp
);
299 lck_mtx_unlock(&lck_grp_lock
);
303 * Routine: lck_grp_free
310 lck_mtx_lock(&lck_grp_lock
);
312 (void)remque((queue_entry_t
)grp
);
313 lck_mtx_unlock(&lck_grp_lock
);
314 lck_grp_deallocate(grp
);
319 * Routine: lck_grp_reference
326 os_ref_retain(&grp
->lck_grp_refcnt
);
331 * Routine: lck_grp_deallocate
338 if (os_ref_release(&grp
->lck_grp_refcnt
) != 0) {
342 zfree(ZV_LCK_GRP
, grp
);
346 * Routine: lck_grp_lckcnt_incr
354 unsigned int *lckcnt
;
358 lckcnt
= &grp
->lck_grp_spincnt
;
361 lckcnt
= &grp
->lck_grp_mtxcnt
;
364 lckcnt
= &grp
->lck_grp_rwcnt
;
366 case LCK_TYPE_TICKET
:
367 lckcnt
= &grp
->lck_grp_ticketcnt
;
370 return panic("lck_grp_lckcnt_incr(): invalid lock type: %d\n", lck_type
);
373 os_atomic_inc(lckcnt
, relaxed
);
377 * Routine: lck_grp_lckcnt_decr
385 unsigned int *lckcnt
;
390 lckcnt
= &grp
->lck_grp_spincnt
;
393 lckcnt
= &grp
->lck_grp_mtxcnt
;
396 lckcnt
= &grp
->lck_grp_rwcnt
;
398 case LCK_TYPE_TICKET
:
399 lckcnt
= &grp
->lck_grp_ticketcnt
;
402 panic("lck_grp_lckcnt_decr(): invalid lock type: %d\n", lck_type
);
406 updated
= os_atomic_dec(lckcnt
, relaxed
);
407 assert(updated
>= 0);
411 * Routine: lck_attr_alloc_init
420 attr
= zalloc(ZV_LCK_ATTR
);
421 lck_attr_setdefault(attr
);
427 * Routine: lck_attr_setdefault
434 #if __arm__ || __arm64__
435 /* <rdar://problem/4404579>: Using LCK_ATTR_DEBUG here causes panic at boot time for arm */
436 attr
->lck_attr_val
= LCK_ATTR_NONE
;
437 #elif __i386__ || __x86_64__
439 if (LcksOpts
& enaLkDeb
) {
440 attr
->lck_attr_val
= LCK_ATTR_DEBUG
;
442 attr
->lck_attr_val
= LCK_ATTR_NONE
;
445 attr
->lck_attr_val
= LCK_ATTR_DEBUG
;
448 #error Unknown architecture.
454 * Routine: lck_attr_setdebug
460 os_atomic_or(&attr
->lck_attr_val
, LCK_ATTR_DEBUG
, relaxed
);
464 * Routine: lck_attr_setdebug
470 os_atomic_andnot(&attr
->lck_attr_val
, LCK_ATTR_DEBUG
, relaxed
);
475 * Routine: lck_attr_rw_shared_priority
478 lck_attr_rw_shared_priority(
481 os_atomic_or(&attr
->lck_attr_val
, LCK_ATTR_RW_SHARED_PRIORITY
, relaxed
);
486 * Routine: lck_attr_free
492 zfree(ZV_LCK_ATTR
, attr
);
496 * Routine: hw_lock_init
498 * Initialize a hardware lock.
500 MARK_AS_HIBERNATE_TEXT
void
501 hw_lock_init(hw_lock_t lock
)
503 ordered_store_hw(lock
, 0);
507 hw_lock_trylock_contended(hw_lock_t lock
, uintptr_t newval
)
509 #if OS_ATOMIC_USE_LLSC
511 os_atomic_rmw_loop(&lock
->lock_data
, oldval
, newval
, acquire
, {
513 wait_for_event(); // clears the monitor so we don't need give_up()
518 #else // !OS_ATOMIC_USE_LLSC
519 #if OS_ATOMIC_HAS_LLSC
520 uintptr_t oldval
= os_atomic_load_exclusive(&lock
->lock_data
, relaxed
);
522 wait_for_event(); // clears the monitor so we don't need give_up()
525 #endif // OS_ATOMIC_HAS_LLSC
526 return os_atomic_cmpxchg(&lock
->lock_data
, 0, newval
, acquire
);
527 #endif // !OS_ATOMIC_USE_LLSC
531 * Routine: hw_lock_lock_contended
533 * Spin until lock is acquired or timeout expires.
534 * timeout is in mach_absolute_time ticks. Called with
535 * preemption disabled.
537 static unsigned int NOINLINE
538 hw_lock_lock_contended(hw_lock_t lock
, uintptr_t data
, uint64_t timeout
, boolean_t do_panic
LCK_GRP_ARG(lck_grp_t
*grp
))
541 uintptr_t holder
= lock
->lock_data
;
545 timeout
= LOCK_PANIC_TIMEOUT
;
547 #if CONFIG_DTRACE || LOCK_STATS
549 boolean_t stat_enabled
= lck_grp_spin_spin_enabled(lock
LCK_GRP_ARG(grp
));
550 #endif /* CONFIG_DTRACE || LOCK_STATS */
552 #if LOCK_STATS || CONFIG_DTRACE
553 if (__improbable(stat_enabled
)) {
554 begin
= mach_absolute_time();
556 #endif /* LOCK_STATS || CONFIG_DTRACE */
558 for (i
= 0; i
< LOCK_SNOOP_SPINS
; i
++) {
560 #if (!__ARM_ENABLE_WFE_) || (LOCK_PRETEST)
561 holder
= ordered_load_hw(lock
);
566 if (hw_lock_trylock_contended(lock
, data
)) {
567 #if CONFIG_DTRACE || LOCK_STATS
568 if (__improbable(stat_enabled
)) {
569 lck_grp_spin_update_spin(lock
LCK_GRP_ARG(grp
), mach_absolute_time() - begin
);
571 lck_grp_spin_update_miss(lock
LCK_GRP_ARG(grp
));
572 #endif /* CONFIG_DTRACE || LOCK_STATS */
577 end
= ml_get_timebase() + timeout
;
578 } else if (ml_get_timebase() >= end
) {
583 // Capture the actual time spent blocked, which may be higher than the timeout
584 // if a misbehaving interrupt stole this thread's CPU time.
585 panic("Spinlock timeout after %llu ticks, %p = %lx",
586 (ml_get_timebase() - end
+ timeout
), lock
, holder
);
592 hw_wait_while_equals(void **address
, void *current
)
598 for (int i
= 0; i
< LOCK_SNOOP_SPINS
; i
++) {
600 #if OS_ATOMIC_HAS_LLSC
601 v
= os_atomic_load_exclusive(address
, relaxed
);
602 if (__probable(v
!= current
)) {
603 os_atomic_clear_exclusive();
608 v
= os_atomic_load(address
, relaxed
);
609 if (__probable(v
!= current
)) {
612 #endif // OS_ATOMIC_HAS_LLSC
615 end
= ml_get_timebase() + LOCK_PANIC_TIMEOUT
;
616 } else if (ml_get_timebase() >= end
) {
617 panic("Wait while equals timeout @ *%p == %p", address
, v
);
623 hw_lock_lock_internal(hw_lock_t lock
, thread_t thread
LCK_GRP_ARG(lck_grp_t
*grp
))
627 state
= LCK_MTX_THREAD_TO_STATE(thread
) | PLATFORM_LCK_ILOCK
;
629 if (ordered_load_hw(lock
)) {
632 #endif // LOCK_PRETEST
633 if (hw_lock_trylock_contended(lock
, state
)) {
638 #endif // LOCK_PRETEST
639 hw_lock_lock_contended(lock
, state
, 0, spinlock_timeout_panic
LCK_GRP_ARG(grp
));
641 lck_grp_spin_update_held(lock
LCK_GRP_ARG(grp
));
647 * Routine: hw_lock_lock
649 * Acquire lock, spinning until it becomes available,
650 * return with preemption disabled.
653 (hw_lock_lock
)(hw_lock_t lock
LCK_GRP_ARG(lck_grp_t
*grp
))
655 thread_t thread
= current_thread();
656 disable_preemption_for_thread(thread
);
657 hw_lock_lock_internal(lock
, thread
LCK_GRP_ARG(grp
));
661 * Routine: hw_lock_lock_nopreempt
663 * Acquire lock, spinning until it becomes available.
666 (hw_lock_lock_nopreempt
)(hw_lock_t lock
LCK_GRP_ARG(lck_grp_t
*grp
))
668 thread_t thread
= current_thread();
669 if (__improbable(!preemption_disabled_for_thread(thread
))) {
670 panic("Attempt to take no-preempt spinlock %p in preemptible context", lock
);
672 hw_lock_lock_internal(lock
, thread
LCK_GRP_ARG(grp
));
675 static inline unsigned int
676 hw_lock_to_internal(hw_lock_t lock
, uint64_t timeout
, thread_t thread
677 LCK_GRP_ARG(lck_grp_t
*grp
))
680 unsigned int success
= 0;
682 state
= LCK_MTX_THREAD_TO_STATE(thread
) | PLATFORM_LCK_ILOCK
;
684 if (ordered_load_hw(lock
)) {
687 #endif // LOCK_PRETEST
688 if (hw_lock_trylock_contended(lock
, state
)) {
694 #endif // LOCK_PRETEST
695 success
= hw_lock_lock_contended(lock
, state
, timeout
, FALSE
LCK_GRP_ARG(grp
));
698 lck_grp_spin_update_held(lock
LCK_GRP_ARG(grp
));
704 * Routine: hw_lock_to
706 * Acquire lock, spinning until it becomes available or timeout.
707 * Timeout is in mach_absolute_time ticks, return with
708 * preemption disabled.
712 (hw_lock_to
)(hw_lock_t lock
, uint64_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
))
714 thread_t thread
= current_thread();
715 disable_preemption_for_thread(thread
);
716 return hw_lock_to_internal(lock
, timeout
, thread
LCK_GRP_ARG(grp
));
720 * Routine: hw_lock_to_nopreempt
722 * Acquire lock, spinning until it becomes available or timeout.
723 * Timeout is in mach_absolute_time ticks, called and return with
724 * preemption disabled.
728 (hw_lock_to_nopreempt
)(hw_lock_t lock
, uint64_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
))
730 thread_t thread
= current_thread();
731 if (__improbable(!preemption_disabled_for_thread(thread
))) {
732 panic("Attempt to test no-preempt spinlock %p in preemptible context", lock
);
734 return hw_lock_to_internal(lock
, timeout
, thread
LCK_GRP_ARG(grp
));
738 * Routine: hw_lock_try
740 * returns with preemption disabled on success.
742 static inline unsigned int
743 hw_lock_try_internal(hw_lock_t lock
, thread_t thread
LCK_GRP_ARG(lck_grp_t
*grp
))
748 if (ordered_load_hw(lock
)) {
751 #endif // LOCK_PRETEST
752 success
= os_atomic_cmpxchg(&lock
->lock_data
, 0,
753 LCK_MTX_THREAD_TO_STATE(thread
) | PLATFORM_LCK_ILOCK
, acquire
);
757 #endif // LOCK_PRETEST
759 lck_grp_spin_update_held(lock
LCK_GRP_ARG(grp
));
766 (hw_lock_try
)(hw_lock_t lock
LCK_GRP_ARG(lck_grp_t
*grp
))
768 thread_t thread
= current_thread();
769 disable_preemption_for_thread(thread
);
770 unsigned int success
= hw_lock_try_internal(lock
, thread
LCK_GRP_ARG(grp
));
779 (hw_lock_try_nopreempt
)(hw_lock_t lock
LCK_GRP_ARG(lck_grp_t
*grp
))
781 thread_t thread
= current_thread();
782 if (__improbable(!preemption_disabled_for_thread(thread
))) {
783 panic("Attempt to test no-preempt spinlock %p in preemptible context", lock
);
785 return hw_lock_try_internal(lock
, thread
LCK_GRP_ARG(grp
));
789 * Routine: hw_lock_unlock
791 * Unconditionally release lock, release preemption level.
794 hw_lock_unlock_internal(hw_lock_t lock
)
796 os_atomic_store(&lock
->lock_data
, 0, release
);
797 #if __arm__ || __arm64__
798 // ARM tests are only for open-source exclusion
800 #endif // __arm__ || __arm64__
802 LOCKSTAT_RECORD(LS_LCK_SPIN_UNLOCK_RELEASE
, lock
, 0);
803 #endif /* CONFIG_DTRACE */
807 (hw_lock_unlock
)(hw_lock_t lock
)
809 hw_lock_unlock_internal(lock
);
814 (hw_lock_unlock_nopreempt
)(hw_lock_t lock
)
816 if (__improbable(!preemption_disabled_for_thread(current_thread()))) {
817 panic("Attempt to release no-preempt spinlock %p in preemptible context", lock
);
819 hw_lock_unlock_internal(lock
);
823 * Routine hw_lock_held, doesn't change preemption state.
824 * N.B. Racy, of course.
827 hw_lock_held(hw_lock_t lock
)
829 return ordered_load_hw(lock
) != 0;
833 hw_lock_bit_to_contended(hw_lock_bit_t
*lock
, uint32_t mask
, uint32_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
));
835 static inline unsigned int
836 hw_lock_bit_to_internal(hw_lock_bit_t
*lock
, unsigned int bit
, uint32_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
))
838 unsigned int success
= 0;
839 uint32_t mask
= (1 << bit
);
841 if (__improbable(!hw_atomic_test_and_set32(lock
, mask
, mask
, memory_order_acquire
, FALSE
))) {
842 success
= hw_lock_bit_to_contended(lock
, mask
, timeout
LCK_GRP_ARG(grp
));
848 lck_grp_spin_update_held(lock
LCK_GRP_ARG(grp
));
856 (hw_lock_bit_to
)(hw_lock_bit_t
* lock
, unsigned int bit
, uint32_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
))
858 _disable_preemption();
859 return hw_lock_bit_to_internal(lock
, bit
, timeout
LCK_GRP_ARG(grp
));
862 static unsigned int NOINLINE
863 hw_lock_bit_to_contended(hw_lock_bit_t
*lock
, uint32_t mask
, uint32_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
))
867 #if CONFIG_DTRACE || LOCK_STATS
869 boolean_t stat_enabled
= lck_grp_spin_spin_enabled(lock
LCK_GRP_ARG(grp
));
870 #endif /* CONFIG_DTRACE || LOCK_STATS */
872 #if LOCK_STATS || CONFIG_DTRACE
873 if (__improbable(stat_enabled
)) {
874 begin
= mach_absolute_time();
876 #endif /* LOCK_STATS || CONFIG_DTRACE */
878 for (i
= 0; i
< LOCK_SNOOP_SPINS
; i
++) {
879 // Always load-exclusive before wfe
880 // This grabs the monitor and wakes up on a release event
881 if (hw_atomic_test_and_set32(lock
, mask
, mask
, memory_order_acquire
, TRUE
)) {
886 end
= ml_get_timebase() + timeout
;
887 } else if (ml_get_timebase() >= end
) {
893 #if CONFIG_DTRACE || LOCK_STATS
894 if (__improbable(stat_enabled
)) {
895 lck_grp_spin_update_spin(lock
LCK_GRP_ARG(grp
), mach_absolute_time() - begin
);
897 lck_grp_spin_update_miss(lock
LCK_GRP_ARG(grp
));
898 #endif /* CONFIG_DTRACE || LCK_GRP_STAT */
904 (hw_lock_bit
)(hw_lock_bit_t
* lock
, unsigned int bit
LCK_GRP_ARG(lck_grp_t
*grp
))
906 if (hw_lock_bit_to(lock
, bit
, LOCK_PANIC_TIMEOUT
, LCK_GRP_PROBEARG(grp
))) {
909 panic("hw_lock_bit(): timed out (%p)", lock
);
913 (hw_lock_bit_nopreempt
)(hw_lock_bit_t
* lock
, unsigned int bit
LCK_GRP_ARG(lck_grp_t
*grp
))
915 if (__improbable(get_preemption_level() == 0)) {
916 panic("Attempt to take no-preempt bitlock %p in preemptible context", lock
);
918 if (hw_lock_bit_to_internal(lock
, bit
, LOCK_PANIC_TIMEOUT
LCK_GRP_ARG(grp
))) {
921 panic("hw_lock_bit_nopreempt(): timed out (%p)", lock
);
926 (hw_lock_bit_try
)(hw_lock_bit_t
* lock
, unsigned int bit
LCK_GRP_ARG(lck_grp_t
*grp
))
928 uint32_t mask
= (1 << bit
);
929 boolean_t success
= FALSE
;
931 _disable_preemption();
932 // TODO: consider weak (non-looping) atomic test-and-set
933 success
= hw_atomic_test_and_set32(lock
, mask
, mask
, memory_order_acquire
, FALSE
);
935 _enable_preemption();
939 lck_grp_spin_update_held(lock
LCK_GRP_ARG(grp
));
946 hw_unlock_bit_internal(hw_lock_bit_t
*lock
, unsigned int bit
)
948 uint32_t mask
= (1 << bit
);
950 os_atomic_andnot(lock
, mask
, release
);
955 LOCKSTAT_RECORD(LS_LCK_SPIN_UNLOCK_RELEASE
, lock
, bit
);
960 * Routine: hw_unlock_bit
962 * Release spin-lock. The second parameter is the bit number to test and set.
963 * Decrement the preemption level.
966 hw_unlock_bit(hw_lock_bit_t
* lock
, unsigned int bit
)
968 hw_unlock_bit_internal(lock
, bit
);
969 _enable_preemption();
973 hw_unlock_bit_nopreempt(hw_lock_bit_t
* lock
, unsigned int bit
)
975 if (__improbable(get_preemption_level() == 0)) {
976 panic("Attempt to release no-preempt bitlock %p in preemptible context", lock
);
978 hw_unlock_bit_internal(lock
, bit
);
982 * Routine: lck_spin_sleep
987 lck_sleep_action_t lck_sleep_action
,
989 wait_interrupt_t interruptible
,
994 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
995 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
998 res
= assert_wait(event
, interruptible
);
999 if (res
== THREAD_WAITING
) {
1000 lck_spin_unlock(lck
);
1001 res
= thread_block(THREAD_CONTINUE_NULL
);
1002 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1003 lck_spin_lock_grp(lck
, grp
);
1005 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1006 lck_spin_unlock(lck
);
1015 lck_sleep_action_t lck_sleep_action
,
1017 wait_interrupt_t interruptible
)
1019 return lck_spin_sleep_grp(lck
, lck_sleep_action
, event
, interruptible
, LCK_GRP_NULL
);
1023 * Routine: lck_spin_sleep_deadline
1026 lck_spin_sleep_deadline(
1028 lck_sleep_action_t lck_sleep_action
,
1030 wait_interrupt_t interruptible
,
1035 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1036 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1039 res
= assert_wait_deadline(event
, interruptible
, deadline
);
1040 if (res
== THREAD_WAITING
) {
1041 lck_spin_unlock(lck
);
1042 res
= thread_block(THREAD_CONTINUE_NULL
);
1043 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1046 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1047 lck_spin_unlock(lck
);
1054 * Routine: lck_mtx_sleep
1059 lck_sleep_action_t lck_sleep_action
,
1061 wait_interrupt_t interruptible
)
1064 thread_t thread
= current_thread();
1066 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_SLEEP_CODE
) | DBG_FUNC_START
,
1067 VM_KERNEL_UNSLIDE_OR_PERM(lck
), (int)lck_sleep_action
, VM_KERNEL_UNSLIDE_OR_PERM(event
), (int)interruptible
, 0);
1069 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1070 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1073 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1075 * We overload the RW lock promotion to give us a priority ceiling
1076 * during the time that this thread is asleep, so that when it
1077 * is re-awakened (and not yet contending on the mutex), it is
1078 * runnable at a reasonably high priority.
1080 thread
->rwlock_count
++;
1083 res
= assert_wait(event
, interruptible
);
1084 if (res
== THREAD_WAITING
) {
1085 lck_mtx_unlock(lck
);
1086 res
= thread_block(THREAD_CONTINUE_NULL
);
1087 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1088 if ((lck_sleep_action
& LCK_SLEEP_SPIN
)) {
1089 lck_mtx_lock_spin(lck
);
1090 } else if ((lck_sleep_action
& LCK_SLEEP_SPIN_ALWAYS
)) {
1091 lck_mtx_lock_spin_always(lck
);
1096 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1097 lck_mtx_unlock(lck
);
1100 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1101 if ((thread
->rwlock_count
-- == 1 /* field now 0 */) && (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1102 /* sched_flags checked without lock, but will be rechecked while clearing */
1103 lck_rw_clear_promotion(thread
, unslide_for_kdebug(event
));
1107 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_SLEEP_CODE
) | DBG_FUNC_END
, (int)res
, 0, 0, 0, 0);
1114 * Routine: lck_mtx_sleep_deadline
1117 lck_mtx_sleep_deadline(
1119 lck_sleep_action_t lck_sleep_action
,
1121 wait_interrupt_t interruptible
,
1125 thread_t thread
= current_thread();
1127 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_SLEEP_DEADLINE_CODE
) | DBG_FUNC_START
,
1128 VM_KERNEL_UNSLIDE_OR_PERM(lck
), (int)lck_sleep_action
, VM_KERNEL_UNSLIDE_OR_PERM(event
), (int)interruptible
, 0);
1130 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1131 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1134 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1136 * See lck_mtx_sleep().
1138 thread
->rwlock_count
++;
1141 res
= assert_wait_deadline(event
, interruptible
, deadline
);
1142 if (res
== THREAD_WAITING
) {
1143 lck_mtx_unlock(lck
);
1144 res
= thread_block(THREAD_CONTINUE_NULL
);
1145 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1146 if ((lck_sleep_action
& LCK_SLEEP_SPIN
)) {
1147 lck_mtx_lock_spin(lck
);
1152 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1153 lck_mtx_unlock(lck
);
1156 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1157 if ((thread
->rwlock_count
-- == 1 /* field now 0 */) && (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1158 /* sched_flags checked without lock, but will be rechecked while clearing */
1159 lck_rw_clear_promotion(thread
, unslide_for_kdebug(event
));
1163 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_SLEEP_DEADLINE_CODE
) | DBG_FUNC_END
, (int)res
, 0, 0, 0, 0);
1169 * Lock Boosting Invariants:
1171 * The lock owner is always promoted to the max priority of all its waiters.
1172 * Max priority is capped at MAXPRI_PROMOTE.
1174 * The last waiter is not given a promotion when it wakes up or acquires the lock.
1175 * When the last waiter is waking up, a new contender can always come in and
1176 * steal the lock without having to wait for the last waiter to make forward progress.
1180 * Routine: lck_mtx_lock_wait
1182 * Invoked in order to wait on contention.
1184 * Called with the interlock locked and
1185 * returns it unlocked.
1187 * Always aggressively sets the owning thread to promoted,
1188 * even if it's the same or higher priority
1189 * This prevents it from lowering its own priority while holding a lock
1191 * TODO: Come up with a more efficient way to handle same-priority promotions
1192 * <rdar://problem/30737670> ARM mutex contention logic could avoid taking the thread lock
1198 struct turnstile
**ts
)
1200 thread_t thread
= current_thread();
1202 __kdebug_only
uintptr_t trace_lck
= unslide_for_kdebug(lck
);
1205 uint64_t sleep_start
= 0;
1207 if (lockstat_probemap
[LS_LCK_MTX_LOCK_BLOCK
] || lockstat_probemap
[LS_LCK_MTX_EXT_LOCK_BLOCK
]) {
1208 sleep_start
= mach_absolute_time();
1212 if (lck
->lck_mtx_tag
!= LCK_MTX_TAG_INDIRECT
) {
1215 mutex
= &lck
->lck_mtx_ptr
->lck_mtx
;
1218 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_LCK_WAIT_CODE
) | DBG_FUNC_START
,
1219 trace_lck
, (uintptr_t)thread_tid(thread
), 0, 0, 0);
1221 assert(thread
->waiting_for_mutex
== NULL
);
1222 thread
->waiting_for_mutex
= mutex
;
1223 mutex
->lck_mtx_waiters
++;
1226 *ts
= turnstile_prepare((uintptr_t)mutex
, NULL
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
1229 struct turnstile
*turnstile
= *ts
;
1230 thread_set_pending_block_hint(thread
, kThreadWaitKernelMutex
);
1231 turnstile_update_inheritor(turnstile
, holder
, (TURNSTILE_DELAYED_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
1233 waitq_assert_wait64(&turnstile
->ts_waitq
, CAST_EVENT64_T(LCK_MTX_EVENT(mutex
)), THREAD_UNINT
| THREAD_WAIT_NOREPORT_USER
, TIMEOUT_WAIT_FOREVER
);
1235 lck_mtx_ilk_unlock(mutex
);
1237 turnstile_update_inheritor_complete(turnstile
, TURNSTILE_INTERLOCK_NOT_HELD
);
1239 thread_block(THREAD_CONTINUE_NULL
);
1241 thread
->waiting_for_mutex
= NULL
;
1243 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_LCK_WAIT_CODE
) | DBG_FUNC_END
, 0, 0, 0, 0, 0);
1246 * Record the DTrace lockstat probe for blocking, block time
1247 * measured from when we were entered.
1250 if (lck
->lck_mtx_tag
!= LCK_MTX_TAG_INDIRECT
) {
1251 LOCKSTAT_RECORD(LS_LCK_MTX_LOCK_BLOCK
, lck
,
1252 mach_absolute_time() - sleep_start
);
1254 LOCKSTAT_RECORD(LS_LCK_MTX_EXT_LOCK_BLOCK
, lck
,
1255 mach_absolute_time() - sleep_start
);
1262 * Routine: lck_mtx_lock_acquire
1264 * Invoked on acquiring the mutex when there is
1267 * Returns the current number of waiters.
1269 * Called with the interlock locked.
1272 lck_mtx_lock_acquire(
1274 struct turnstile
*ts
)
1276 thread_t thread
= current_thread();
1279 if (lck
->lck_mtx_tag
!= LCK_MTX_TAG_INDIRECT
) {
1282 mutex
= &lck
->lck_mtx_ptr
->lck_mtx
;
1285 assert(thread
->waiting_for_mutex
== NULL
);
1287 if (mutex
->lck_mtx_waiters
> 0) {
1289 ts
= turnstile_prepare((uintptr_t)mutex
, NULL
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
1292 turnstile_update_inheritor(ts
, thread
, (TURNSTILE_IMMEDIATE_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
1293 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
1297 turnstile_complete((uintptr_t)mutex
, NULL
, NULL
, TURNSTILE_KERNEL_MUTEX
);
1300 return mutex
->lck_mtx_waiters
;
1304 * Routine: lck_mtx_unlock_wakeup
1306 * Invoked on unlock when there is contention.
1308 * Called with the interlock locked.
1310 * NOTE: callers should call turnstile_clenup after
1311 * dropping the interlock.
1314 lck_mtx_unlock_wakeup(
1318 thread_t thread
= current_thread();
1320 __kdebug_only
uintptr_t trace_lck
= unslide_for_kdebug(lck
);
1321 struct turnstile
*ts
;
1322 kern_return_t did_wake
;
1324 if (lck
->lck_mtx_tag
!= LCK_MTX_TAG_INDIRECT
) {
1327 mutex
= &lck
->lck_mtx_ptr
->lck_mtx
;
1330 if (thread
!= holder
) {
1331 panic("lck_mtx_unlock_wakeup: mutex %p holder %p\n", mutex
, holder
);
1334 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_UNLCK_WAKEUP_CODE
) | DBG_FUNC_START
,
1335 trace_lck
, (uintptr_t)thread_tid(thread
), 0, 0, 0);
1337 assert(mutex
->lck_mtx_waiters
> 0);
1338 assert(thread
->waiting_for_mutex
== NULL
);
1340 ts
= turnstile_prepare((uintptr_t)mutex
, NULL
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
1342 if (mutex
->lck_mtx_waiters
> 1) {
1343 /* WAITQ_PROMOTE_ON_WAKE will call turnstile_update_inheritor on the wokenup thread */
1344 did_wake
= waitq_wakeup64_one(&ts
->ts_waitq
, CAST_EVENT64_T(LCK_MTX_EVENT(mutex
)), THREAD_AWAKENED
, WAITQ_PROMOTE_ON_WAKE
);
1346 did_wake
= waitq_wakeup64_one(&ts
->ts_waitq
, CAST_EVENT64_T(LCK_MTX_EVENT(mutex
)), THREAD_AWAKENED
, WAITQ_ALL_PRIORITIES
);
1347 turnstile_update_inheritor(ts
, NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
1349 assert(did_wake
== KERN_SUCCESS
);
1351 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
1352 turnstile_complete((uintptr_t)mutex
, NULL
, NULL
, TURNSTILE_KERNEL_MUTEX
);
1354 mutex
->lck_mtx_waiters
--;
1356 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_UNLCK_WAKEUP_CODE
) | DBG_FUNC_END
, 0, 0, 0, 0, 0);
1358 return mutex
->lck_mtx_waiters
> 0;
1362 * Routine: mutex_pause
1364 * Called by former callers of simple_lock_pause().
1366 #define MAX_COLLISION_COUNTS 32
1367 #define MAX_COLLISION 8
1369 unsigned int max_collision_count
[MAX_COLLISION_COUNTS
];
1371 uint32_t collision_backoffs
[MAX_COLLISION
] = {
1372 10, 50, 100, 200, 400, 600, 800, 1000
1377 mutex_pause(uint32_t collisions
)
1379 wait_result_t wait_result
;
1382 if (collisions
>= MAX_COLLISION_COUNTS
) {
1383 collisions
= MAX_COLLISION_COUNTS
- 1;
1385 max_collision_count
[collisions
]++;
1387 if (collisions
>= MAX_COLLISION
) {
1388 collisions
= MAX_COLLISION
- 1;
1390 back_off
= collision_backoffs
[collisions
];
1392 wait_result
= assert_wait_timeout((event_t
)mutex_pause
, THREAD_UNINT
, back_off
, NSEC_PER_USEC
);
1393 assert(wait_result
== THREAD_WAITING
);
1395 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1396 assert(wait_result
== THREAD_TIMED_OUT
);
1400 unsigned int mutex_yield_wait
= 0;
1401 unsigned int mutex_yield_no_wait
= 0;
1410 lck_mtx_assert(lck
, LCK_MTX_ASSERT_OWNED
);
1413 if (lck
->lck_mtx_tag
== LCK_MTX_TAG_INDIRECT
) {
1414 waiters
= lck
->lck_mtx_ptr
->lck_mtx
.lck_mtx_waiters
;
1416 waiters
= lck
->lck_mtx_waiters
;
1420 mutex_yield_no_wait
++;
1423 lck_mtx_unlock(lck
);
1431 * Routine: lck_rw_sleep
1436 lck_sleep_action_t lck_sleep_action
,
1438 wait_interrupt_t interruptible
)
1441 lck_rw_type_t lck_rw_type
;
1442 thread_t thread
= current_thread();
1444 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1445 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1448 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1450 * Although we are dropping the RW lock, the intent in most cases
1451 * is that this thread remains as an observer, since it may hold
1452 * some secondary resource, but must yield to avoid deadlock. In
1453 * this situation, make sure that the thread is boosted to the
1454 * RW lock ceiling while blocked, so that it can re-acquire the
1455 * RW lock at that priority.
1457 thread
->rwlock_count
++;
1460 res
= assert_wait(event
, interruptible
);
1461 if (res
== THREAD_WAITING
) {
1462 lck_rw_type
= lck_rw_done(lck
);
1463 res
= thread_block(THREAD_CONTINUE_NULL
);
1464 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1465 if (!(lck_sleep_action
& (LCK_SLEEP_SHARED
| LCK_SLEEP_EXCLUSIVE
))) {
1466 lck_rw_lock(lck
, lck_rw_type
);
1467 } else if (lck_sleep_action
& LCK_SLEEP_EXCLUSIVE
) {
1468 lck_rw_lock_exclusive(lck
);
1470 lck_rw_lock_shared(lck
);
1473 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1474 (void)lck_rw_done(lck
);
1477 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1478 if ((thread
->rwlock_count
-- == 1 /* field now 0 */) && (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1479 /* sched_flags checked without lock, but will be rechecked while clearing */
1481 /* Only if the caller wanted the lck_rw_t returned unlocked should we drop to 0 */
1482 assert(lck_sleep_action
& LCK_SLEEP_UNLOCK
);
1484 lck_rw_clear_promotion(thread
, unslide_for_kdebug(event
));
1493 * Routine: lck_rw_sleep_deadline
1496 lck_rw_sleep_deadline(
1498 lck_sleep_action_t lck_sleep_action
,
1500 wait_interrupt_t interruptible
,
1504 lck_rw_type_t lck_rw_type
;
1505 thread_t thread
= current_thread();
1507 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1508 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1511 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1512 thread
->rwlock_count
++;
1515 res
= assert_wait_deadline(event
, interruptible
, deadline
);
1516 if (res
== THREAD_WAITING
) {
1517 lck_rw_type
= lck_rw_done(lck
);
1518 res
= thread_block(THREAD_CONTINUE_NULL
);
1519 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1520 if (!(lck_sleep_action
& (LCK_SLEEP_SHARED
| LCK_SLEEP_EXCLUSIVE
))) {
1521 lck_rw_lock(lck
, lck_rw_type
);
1522 } else if (lck_sleep_action
& LCK_SLEEP_EXCLUSIVE
) {
1523 lck_rw_lock_exclusive(lck
);
1525 lck_rw_lock_shared(lck
);
1528 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1529 (void)lck_rw_done(lck
);
1532 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1533 if ((thread
->rwlock_count
-- == 1 /* field now 0 */) && (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1534 /* sched_flags checked without lock, but will be rechecked while clearing */
1536 /* Only if the caller wanted the lck_rw_t returned unlocked should we drop to 0 */
1537 assert(lck_sleep_action
& LCK_SLEEP_UNLOCK
);
1539 lck_rw_clear_promotion(thread
, unslide_for_kdebug(event
));
1547 * Reader-writer lock promotion
1549 * We support a limited form of reader-writer
1550 * lock promotion whose effects are:
1552 * * Qualifying threads have decay disabled
1553 * * Scheduler priority is reset to a floor of
1554 * of their statically assigned priority
1557 * The rationale is that lck_rw_ts do not have
1558 * a single owner, so we cannot apply a directed
1559 * priority boost from all waiting threads
1560 * to all holding threads without maintaining
1561 * lists of all shared owners and all waiting
1562 * threads for every lock.
1564 * Instead (and to preserve the uncontended fast-
1565 * path), acquiring (or attempting to acquire)
1566 * a RW lock in shared or exclusive lock increments
1567 * a per-thread counter. Only if that thread stops
1568 * making forward progress (for instance blocking
1569 * on a mutex, or being preempted) do we consult
1570 * the counter and apply the priority floor.
1571 * When the thread becomes runnable again (or in
1572 * the case of preemption it never stopped being
1573 * runnable), it has the priority boost and should
1574 * be in a good position to run on the CPU and
1575 * release all RW locks (at which point the priority
1576 * boost is cleared).
1578 * Care must be taken to ensure that priority
1579 * boosts are not retained indefinitely, since unlike
1580 * mutex priority boosts (where the boost is tied
1581 * to the mutex lifecycle), the boost is tied
1582 * to the thread and independent of any particular
1583 * lck_rw_t. Assertions are in place on return
1584 * to userspace so that the boost is not held
1587 * The routines that increment/decrement the
1588 * per-thread counter should err on the side of
1589 * incrementing any time a preemption is possible
1590 * and the lock would be visible to the rest of the
1591 * system as held (so it should be incremented before
1592 * interlocks are dropped/preemption is enabled, or
1593 * before a CAS is executed to acquire the lock).
1598 * lck_rw_clear_promotion: Undo priority promotions when the last RW
1599 * lock is released by a thread (if a promotion was active)
1602 lck_rw_clear_promotion(thread_t thread
, uintptr_t trace_obj
)
1604 assert(thread
->rwlock_count
== 0);
1606 /* Cancel any promotions if the thread had actually blocked while holding a RW lock */
1607 spl_t s
= splsched();
1608 thread_lock(thread
);
1610 if (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
) {
1611 sched_thread_unpromote_reason(thread
, TH_SFLAG_RW_PROMOTED
, trace_obj
);
1614 thread_unlock(thread
);
1619 * Callout from context switch if the thread goes
1620 * off core with a positive rwlock_count
1622 * Called at splsched with the thread locked
1625 lck_rw_set_promotion_locked(thread_t thread
)
1627 if (LcksOpts
& disLkRWPrio
) {
1631 assert(thread
->rwlock_count
> 0);
1633 if (!(thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1634 sched_thread_promote_reason(thread
, TH_SFLAG_RW_PROMOTED
, 0);
1639 host_lockgroup_info(
1641 lockgroup_info_array_t
*lockgroup_infop
,
1642 mach_msg_type_number_t
*lockgroup_infoCntp
)
1644 lockgroup_info_t
*lockgroup_info_base
;
1645 lockgroup_info_t
*lockgroup_info
;
1646 vm_offset_t lockgroup_info_addr
;
1647 vm_size_t lockgroup_info_size
;
1648 vm_size_t lockgroup_info_vmsize
;
1654 if (host
== HOST_NULL
) {
1655 return KERN_INVALID_HOST
;
1658 lck_mtx_lock(&lck_grp_lock
);
1660 lockgroup_info_size
= lck_grp_cnt
* sizeof(*lockgroup_info
);
1661 lockgroup_info_vmsize
= round_page(lockgroup_info_size
);
1662 kr
= kmem_alloc_pageable(ipc_kernel_map
,
1663 &lockgroup_info_addr
, lockgroup_info_vmsize
, VM_KERN_MEMORY_IPC
);
1664 if (kr
!= KERN_SUCCESS
) {
1665 lck_mtx_unlock(&lck_grp_lock
);
1669 lockgroup_info_base
= (lockgroup_info_t
*) lockgroup_info_addr
;
1670 lck_grp
= (lck_grp_t
*)queue_first(&lck_grp_queue
);
1671 lockgroup_info
= lockgroup_info_base
;
1673 for (i
= 0; i
< lck_grp_cnt
; i
++) {
1674 lockgroup_info
->lock_spin_cnt
= lck_grp
->lck_grp_spincnt
;
1675 lockgroup_info
->lock_rw_cnt
= lck_grp
->lck_grp_rwcnt
;
1676 lockgroup_info
->lock_mtx_cnt
= lck_grp
->lck_grp_mtxcnt
;
1679 lockgroup_info
->lock_spin_held_cnt
= lck_grp
->lck_grp_stats
.lgss_spin_held
.lgs_count
;
1680 lockgroup_info
->lock_spin_miss_cnt
= lck_grp
->lck_grp_stats
.lgss_spin_miss
.lgs_count
;
1681 #endif /* LOCK_STATS */
1683 // Historically on x86, held was used for "direct wait" and util for "held"
1684 lockgroup_info
->lock_mtx_util_cnt
= lck_grp
->lck_grp_stats
.lgss_mtx_held
.lgs_count
;
1685 lockgroup_info
->lock_mtx_held_cnt
= lck_grp
->lck_grp_stats
.lgss_mtx_direct_wait
.lgs_count
;
1686 lockgroup_info
->lock_mtx_miss_cnt
= lck_grp
->lck_grp_stats
.lgss_mtx_miss
.lgs_count
;
1687 lockgroup_info
->lock_mtx_wait_cnt
= lck_grp
->lck_grp_stats
.lgss_mtx_wait
.lgs_count
;
1689 (void) strncpy(lockgroup_info
->lockgroup_name
, lck_grp
->lck_grp_name
, LOCKGROUP_MAX_NAME
);
1691 lck_grp
= (lck_grp_t
*)(queue_next((queue_entry_t
)(lck_grp
)));
1695 *lockgroup_infoCntp
= lck_grp_cnt
;
1696 lck_mtx_unlock(&lck_grp_lock
);
1698 if (lockgroup_info_size
!= lockgroup_info_vmsize
) {
1699 bzero((char *)lockgroup_info
, lockgroup_info_vmsize
- lockgroup_info_size
);
1702 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)lockgroup_info_addr
,
1703 (vm_map_size_t
)lockgroup_info_size
, TRUE
, ©
);
1704 assert(kr
== KERN_SUCCESS
);
1706 *lockgroup_infop
= (lockgroup_info_t
*) copy
;
1708 return KERN_SUCCESS
;
1712 * sleep_with_inheritor and wakeup_with_inheritor KPI
1714 * Functions that allow to sleep on an event and use turnstile to propagate the priority of the sleeping threads to
1715 * the latest thread specified as inheritor.
1717 * The inheritor management is delegated to the caller, the caller needs to store a thread identifier to provide to this functions to specified upon whom
1718 * direct the push. The inheritor cannot run in user space while holding a push from an event. Therefore is the caller responsibility to call a
1719 * wakeup_with_inheritor from inheritor before running in userspace or specify another inheritor before letting the old inheritor run in userspace.
1721 * sleep_with_inheritor requires to hold a locking primitive while invoked, but wakeup_with_inheritor and change_sleep_inheritor don't require it.
1723 * Turnstile requires a non blocking primitive as interlock to synchronize the turnstile data structure manipulation, threfore sleep_with_inheritor, change_sleep_inheritor and
1724 * wakeup_with_inheritor will require the same interlock to manipulate turnstiles.
1725 * If sleep_with_inheritor is associated with a locking primitive that can block (like lck_mtx_t or lck_rw_t), an handoff to a non blocking primitive is required before
1726 * invoking any turnstile operation.
1728 * All functions will save the turnstile associated with the event on the turnstile kernel hash table and will use the the turnstile kernel hash table bucket
1729 * spinlock as the turnstile interlock. Because we do not want to hold interrupt disabled while holding the bucket interlock a new turnstile kernel hash table
1730 * is instantiated for this KPI to manage the hash without interrupt disabled.
1732 * - all events on the system that hash on the same bucket will contend on the same spinlock.
1733 * - every event will have a dedicated wait_queue.
1735 * Different locking primitives can be associated with sleep_with_inheritor as long as the primitive_lock() and primitive_unlock() functions are provided to
1736 * sleep_with_inheritor_turnstile to perform the handoff with the bucket spinlock.
1740 wakeup_with_inheritor_and_turnstile_type(event_t event
, turnstile_type_t type
, wait_result_t result
, bool wake_one
, lck_wake_action_t action
, thread_t
*thread_wokenup
)
1743 struct turnstile
*ts
= NULL
;
1744 kern_return_t ret
= KERN_NOT_WAITING
;
1749 * the hash bucket spinlock is used as turnstile interlock
1751 turnstile_hash_bucket_lock((uintptr_t)event
, &index
, type
);
1753 ts
= turnstile_prepare((uintptr_t)event
, NULL
, TURNSTILE_NULL
, type
);
1756 if (action
== LCK_WAKE_DEFAULT
) {
1757 priority
= WAITQ_PROMOTE_ON_WAKE
;
1759 assert(action
== LCK_WAKE_DO_NOT_TRANSFER_PUSH
);
1760 priority
= WAITQ_ALL_PRIORITIES
;
1764 * WAITQ_PROMOTE_ON_WAKE will call turnstile_update_inheritor
1765 * if it finds a thread
1767 wokeup
= waitq_wakeup64_identify(&ts
->ts_waitq
, CAST_EVENT64_T(event
), result
, priority
);
1768 if (wokeup
!= NULL
) {
1769 if (thread_wokenup
!= NULL
) {
1770 *thread_wokenup
= wokeup
;
1772 thread_deallocate_safe(wokeup
);
1775 if (action
== LCK_WAKE_DO_NOT_TRANSFER_PUSH
) {
1779 if (thread_wokenup
!= NULL
) {
1780 *thread_wokenup
= NULL
;
1782 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
1783 ret
= KERN_NOT_WAITING
;
1786 ret
= waitq_wakeup64_all(&ts
->ts_waitq
, CAST_EVENT64_T(event
), result
, WAITQ_ALL_PRIORITIES
);
1787 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
1791 * turnstile_update_inheritor_complete could be called while holding the interlock.
1792 * In this case the new inheritor or is null, or is a thread that is just been woken up
1793 * and have not blocked because it is racing with the same interlock used here
1795 * So there is no chain to update for the new inheritor.
1797 * However unless the current thread is the old inheritor,
1798 * old inheritor can be blocked and requires a chain update.
1800 * The chain should be short because kernel turnstiles cannot have user turnstiles
1801 * chained after them.
1803 * We can anyway optimize this by asking turnstile to tell us
1804 * if old inheritor needs an update and drop the lock
1805 * just in that case.
1807 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1809 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
1811 turnstile_hash_bucket_lock((uintptr_t)NULL
, &index
, type
);
1814 turnstile_complete((uintptr_t)event
, NULL
, NULL
, type
);
1816 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1818 turnstile_cleanup();
1823 static wait_result_t
1824 sleep_with_inheritor_and_turnstile_type(event_t event
,
1826 wait_interrupt_t interruptible
,
1828 turnstile_type_t type
,
1829 void (^primitive_lock
)(void),
1830 void (^primitive_unlock
)(void))
1834 struct turnstile
*ts
= NULL
;
1837 * the hash bucket spinlock is used as turnstile interlock,
1838 * lock it before releasing the primitive lock
1840 turnstile_hash_bucket_lock((uintptr_t)event
, &index
, type
);
1844 ts
= turnstile_prepare((uintptr_t)event
, NULL
, TURNSTILE_NULL
, type
);
1846 thread_set_pending_block_hint(current_thread(), kThreadWaitSleepWithInheritor
);
1848 * We need TURNSTILE_DELAYED_UPDATE because we will call
1849 * waitq_assert_wait64 after.
1851 turnstile_update_inheritor(ts
, inheritor
, (TURNSTILE_DELAYED_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
1853 ret
= waitq_assert_wait64(&ts
->ts_waitq
, CAST_EVENT64_T(event
), interruptible
, deadline
);
1855 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1858 * Update new and old inheritor chains outside the interlock;
1860 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
1862 if (ret
== THREAD_WAITING
) {
1863 ret
= thread_block(THREAD_CONTINUE_NULL
);
1866 turnstile_hash_bucket_lock((uintptr_t)NULL
, &index
, type
);
1868 turnstile_complete((uintptr_t)event
, NULL
, NULL
, type
);
1870 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1872 turnstile_cleanup();
1880 change_sleep_inheritor_and_turnstile_type(event_t event
,
1882 turnstile_type_t type
)
1885 struct turnstile
*ts
= NULL
;
1886 kern_return_t ret
= KERN_SUCCESS
;
1888 * the hash bucket spinlock is used as turnstile interlock
1890 turnstile_hash_bucket_lock((uintptr_t)event
, &index
, type
);
1892 ts
= turnstile_prepare((uintptr_t)event
, NULL
, TURNSTILE_NULL
, type
);
1894 if (!turnstile_has_waiters(ts
)) {
1895 ret
= KERN_NOT_WAITING
;
1899 * We will not call an assert_wait later so use TURNSTILE_IMMEDIATE_UPDATE
1901 turnstile_update_inheritor(ts
, inheritor
, (TURNSTILE_IMMEDIATE_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
1903 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1906 * update the chains outside the interlock
1908 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
1910 turnstile_hash_bucket_lock((uintptr_t)NULL
, &index
, type
);
1912 turnstile_complete((uintptr_t)event
, NULL
, NULL
, type
);
1914 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1916 turnstile_cleanup();
1921 typedef void (^void_block_void
)(void);
1924 * sleep_with_inheritor functions with lck_mtx_t as locking primitive.
1928 lck_mtx_sleep_with_inheritor_and_turnstile_type(lck_mtx_t
*lock
, lck_sleep_action_t lck_sleep_action
, event_t event
, thread_t inheritor
, wait_interrupt_t interruptible
, uint64_t deadline
, turnstile_type_t type
)
1930 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
1932 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1933 return sleep_with_inheritor_and_turnstile_type(event
,
1939 ^{lck_mtx_unlock(lock
);});
1940 } else if (lck_sleep_action
& LCK_SLEEP_SPIN
) {
1941 return sleep_with_inheritor_and_turnstile_type(event
,
1946 ^{lck_mtx_lock_spin(lock
);},
1947 ^{lck_mtx_unlock(lock
);});
1948 } else if (lck_sleep_action
& LCK_SLEEP_SPIN_ALWAYS
) {
1949 return sleep_with_inheritor_and_turnstile_type(event
,
1954 ^{lck_mtx_lock_spin_always(lock
);},
1955 ^{lck_mtx_unlock(lock
);});
1957 return sleep_with_inheritor_and_turnstile_type(event
,
1962 ^{lck_mtx_lock(lock
);},
1963 ^{lck_mtx_unlock(lock
);});
1968 * Name: lck_spin_sleep_with_inheritor
1970 * Description: deschedule the current thread and wait on the waitq associated with event to be woken up.
1971 * While waiting, the sched priority of the waiting thread will contribute to the push of the event that will
1972 * be directed to the inheritor specified.
1973 * An interruptible mode and deadline can be specified to return earlier from the wait.
1976 * Arg1: lck_spin_t lock used to protect the sleep. The lock will be dropped while sleeping and reaquired before returning according to the sleep action specified.
1977 * Arg2: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_UNLOCK.
1978 * Arg3: event to wait on.
1979 * Arg4: thread to propagate the event push to.
1980 * Arg5: interruptible flag for wait.
1981 * Arg6: deadline for wait.
1983 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
1984 * Lock will be dropped while waiting.
1985 * The inheritor specified cannot run in user space until another inheritor is specified for the event or a
1986 * wakeup for the event is called.
1988 * Returns: result of the wait.
1991 lck_spin_sleep_with_inheritor(
1993 lck_sleep_action_t lck_sleep_action
,
1996 wait_interrupt_t interruptible
,
1999 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
2000 return sleep_with_inheritor_and_turnstile_type(event
, inheritor
,
2001 interruptible
, deadline
, TURNSTILE_SLEEP_INHERITOR
,
2002 ^{}, ^{ lck_spin_unlock(lock
); });
2004 return sleep_with_inheritor_and_turnstile_type(event
, inheritor
,
2005 interruptible
, deadline
, TURNSTILE_SLEEP_INHERITOR
,
2006 ^{ lck_spin_lock(lock
); }, ^{ lck_spin_unlock(lock
); });
2011 * Name: lck_mtx_sleep_with_inheritor
2013 * Description: deschedule the current thread and wait on the waitq associated with event to be woken up.
2014 * While waiting, the sched priority of the waiting thread will contribute to the push of the event that will
2015 * be directed to the inheritor specified.
2016 * An interruptible mode and deadline can be specified to return earlier from the wait.
2019 * Arg1: lck_mtx_t lock used to protect the sleep. The lock will be dropped while sleeping and reaquired before returning according to the sleep action specified.
2020 * Arg2: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_UNLOCK, LCK_SLEEP_SPIN, LCK_SLEEP_SPIN_ALWAYS.
2021 * Arg3: event to wait on.
2022 * Arg4: thread to propagate the event push to.
2023 * Arg5: interruptible flag for wait.
2024 * Arg6: deadline for wait.
2026 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
2027 * Lock will be dropped while waiting.
2028 * The inheritor specified cannot run in user space until another inheritor is specified for the event or a
2029 * wakeup for the event is called.
2031 * Returns: result of the wait.
2034 lck_mtx_sleep_with_inheritor(lck_mtx_t
*lock
, lck_sleep_action_t lck_sleep_action
, event_t event
, thread_t inheritor
, wait_interrupt_t interruptible
, uint64_t deadline
)
2036 return lck_mtx_sleep_with_inheritor_and_turnstile_type(lock
, lck_sleep_action
, event
, inheritor
, interruptible
, deadline
, TURNSTILE_SLEEP_INHERITOR
);
2040 * sleep_with_inheritor functions with lck_rw_t as locking primitive.
2044 lck_rw_sleep_with_inheritor_and_turnstile_type(lck_rw_t
*lock
, lck_sleep_action_t lck_sleep_action
, event_t event
, thread_t inheritor
, wait_interrupt_t interruptible
, uint64_t deadline
, turnstile_type_t type
)
2046 __block lck_rw_type_t lck_rw_type
= LCK_RW_TYPE_EXCLUSIVE
;
2048 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2050 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
2051 return sleep_with_inheritor_and_turnstile_type(event
,
2057 ^{lck_rw_type
= lck_rw_done(lock
);});
2058 } else if (!(lck_sleep_action
& (LCK_SLEEP_SHARED
| LCK_SLEEP_EXCLUSIVE
))) {
2059 return sleep_with_inheritor_and_turnstile_type(event
,
2064 ^{lck_rw_lock(lock
, lck_rw_type
);},
2065 ^{lck_rw_type
= lck_rw_done(lock
);});
2066 } else if (lck_sleep_action
& LCK_SLEEP_EXCLUSIVE
) {
2067 return sleep_with_inheritor_and_turnstile_type(event
,
2072 ^{lck_rw_lock_exclusive(lock
);},
2073 ^{lck_rw_type
= lck_rw_done(lock
);});
2075 return sleep_with_inheritor_and_turnstile_type(event
,
2080 ^{lck_rw_lock_shared(lock
);},
2081 ^{lck_rw_type
= lck_rw_done(lock
);});
2086 * Name: lck_rw_sleep_with_inheritor
2088 * Description: deschedule the current thread and wait on the waitq associated with event to be woken up.
2089 * While waiting, the sched priority of the waiting thread will contribute to the push of the event that will
2090 * be directed to the inheritor specified.
2091 * An interruptible mode and deadline can be specified to return earlier from the wait.
2094 * Arg1: lck_rw_t lock used to protect the sleep. The lock will be dropped while sleeping and reaquired before returning according to the sleep action specified.
2095 * Arg2: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_SHARED, LCK_SLEEP_EXCLUSIVE.
2096 * Arg3: event to wait on.
2097 * Arg4: thread to propagate the event push to.
2098 * Arg5: interruptible flag for wait.
2099 * Arg6: deadline for wait.
2101 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
2102 * Lock will be dropped while waiting.
2103 * The inheritor specified cannot run in user space until another inheritor is specified for the event or a
2104 * wakeup for the event is called.
2106 * Returns: result of the wait.
2109 lck_rw_sleep_with_inheritor(lck_rw_t
*lock
, lck_sleep_action_t lck_sleep_action
, event_t event
, thread_t inheritor
, wait_interrupt_t interruptible
, uint64_t deadline
)
2111 return lck_rw_sleep_with_inheritor_and_turnstile_type(lock
, lck_sleep_action
, event
, inheritor
, interruptible
, deadline
, TURNSTILE_SLEEP_INHERITOR
);
2115 * wakeup_with_inheritor functions are independent from the locking primitive.
2119 * Name: wakeup_one_with_inheritor
2121 * Description: wake up one waiter for event if any. The thread woken up will be the one with the higher sched priority waiting on event.
2122 * The push for the event will be transferred from the last inheritor to the woken up thread if LCK_WAKE_DEFAULT is specified.
2123 * If LCK_WAKE_DO_NOT_TRANSFER_PUSH is specified the push will not be transferred.
2126 * Arg1: event to wake from.
2127 * Arg2: wait result to pass to the woken up thread.
2128 * Arg3: wake flag. LCK_WAKE_DEFAULT or LCK_WAKE_DO_NOT_TRANSFER_PUSH.
2129 * Arg4: pointer for storing the thread wokenup.
2131 * Returns: KERN_NOT_WAITING if no threads were waiting, KERN_SUCCESS otherwise.
2133 * Conditions: The new inheritor wokenup cannot run in user space until another inheritor is specified for the event or a
2134 * wakeup for the event is called.
2135 * A reference for the wokenup thread is acquired.
2136 * NOTE: this cannot be called from interrupt context.
2139 wakeup_one_with_inheritor(event_t event
, wait_result_t result
, lck_wake_action_t action
, thread_t
*thread_wokenup
)
2141 return wakeup_with_inheritor_and_turnstile_type(event
,
2142 TURNSTILE_SLEEP_INHERITOR
,
2150 * Name: wakeup_all_with_inheritor
2152 * Description: wake up all waiters waiting for event. The old inheritor will lose the push.
2155 * Arg1: event to wake from.
2156 * Arg2: wait result to pass to the woken up threads.
2158 * Returns: KERN_NOT_WAITING if no threads were waiting, KERN_SUCCESS otherwise.
2160 * Conditions: NOTE: this cannot be called from interrupt context.
2163 wakeup_all_with_inheritor(event_t event
, wait_result_t result
)
2165 return wakeup_with_inheritor_and_turnstile_type(event
,
2166 TURNSTILE_SLEEP_INHERITOR
,
2174 * change_sleep_inheritor is independent from the locking primitive.
2178 * Name: change_sleep_inheritor
2180 * Description: Redirect the push of the waiting threads of event to the new inheritor specified.
2183 * Arg1: event to redirect the push.
2184 * Arg2: new inheritor for event.
2186 * Returns: KERN_NOT_WAITING if no threads were waiting, KERN_SUCCESS otherwise.
2188 * Conditions: In case of success, the new inheritor cannot run in user space until another inheritor is specified for the event or a
2189 * wakeup for the event is called.
2190 * NOTE: this cannot be called from interrupt context.
2193 change_sleep_inheritor(event_t event
, thread_t inheritor
)
2195 return change_sleep_inheritor_and_turnstile_type(event
,
2197 TURNSTILE_SLEEP_INHERITOR
);
2201 kdp_sleep_with_inheritor_find_owner(struct waitq
* waitq
, __unused event64_t event
, thread_waitinfo_t
* waitinfo
)
2203 assert(waitinfo
->wait_type
== kThreadWaitSleepWithInheritor
);
2204 assert(waitq_is_turnstile_queue(waitq
));
2205 waitinfo
->owner
= 0;
2206 waitinfo
->context
= 0;
2208 if (waitq_held(waitq
)) {
2212 struct turnstile
*turnstile
= waitq_to_turnstile(waitq
);
2213 assert(turnstile
->ts_inheritor_flags
& TURNSTILE_INHERITOR_THREAD
);
2214 waitinfo
->owner
= thread_tid(turnstile
->ts_inheritor
);
2217 typedef void (*void_func_void
)(void);
2219 static kern_return_t
2220 gate_try_close(gate_t
*gate
)
2225 __assert_only
bool waiters
;
2226 thread_t thread
= current_thread();
2228 if (os_atomic_cmpxchg(&gate
->gate_data
, 0, GATE_THREAD_TO_STATE(thread
), acquire
)) {
2229 return KERN_SUCCESS
;
2233 state
= ordered_load_gate(gate
);
2234 holder
= GATE_STATE_TO_THREAD(state
);
2236 if (holder
== NULL
) {
2237 waiters
= gate_has_waiters(state
);
2238 assert(waiters
== FALSE
);
2240 state
= GATE_THREAD_TO_STATE(current_thread());
2241 state
|= GATE_ILOCK
;
2242 ordered_store_gate(gate
, state
);
2245 if (holder
== current_thread()) {
2246 panic("Trying to close a gate already owned by current thread %p", current_thread());
2256 gate_close(gate_t
* gate
)
2260 __assert_only
bool waiters
;
2261 thread_t thread
= current_thread();
2263 if (os_atomic_cmpxchg(&gate
->gate_data
, 0, GATE_THREAD_TO_STATE(thread
), acquire
)) {
2268 state
= ordered_load_gate(gate
);
2269 holder
= GATE_STATE_TO_THREAD(state
);
2271 if (holder
!= NULL
) {
2272 panic("Closing a gate already owned by %p from current thread %p", holder
, current_thread());
2275 waiters
= gate_has_waiters(state
);
2276 assert(waiters
== FALSE
);
2278 state
= GATE_THREAD_TO_STATE(thread
);
2279 state
|= GATE_ILOCK
;
2280 ordered_store_gate(gate
, state
);
2286 gate_open_turnstile(gate_t
*gate
)
2288 struct turnstile
*ts
= NULL
;
2290 ts
= turnstile_prepare((uintptr_t)gate
, &gate
->turnstile
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
2291 waitq_wakeup64_all(&ts
->ts_waitq
, CAST_EVENT64_T(GATE_EVENT(gate
)), THREAD_AWAKENED
, WAITQ_ALL_PRIORITIES
);
2292 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
2293 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
2294 turnstile_complete((uintptr_t)gate
, &gate
->turnstile
, NULL
, TURNSTILE_KERNEL_MUTEX
);
2296 * We can do the cleanup while holding the interlock.
2298 * 1. current_thread is the previous inheritor and it is running
2299 * 2. new inheritor is NULL.
2300 * => No chain of turnstiles needs to be updated.
2302 turnstile_cleanup();
2306 gate_open(gate_t
*gate
)
2311 thread_t thread
= current_thread();
2313 if (os_atomic_cmpxchg(&gate
->gate_data
, GATE_THREAD_TO_STATE(thread
), 0, release
)) {
2318 state
= ordered_load_gate(gate
);
2319 holder
= GATE_STATE_TO_THREAD(state
);
2320 waiters
= gate_has_waiters(state
);
2322 if (holder
!= thread
) {
2323 panic("Opening gate owned by %p from current thread %p", holder
, thread
);
2327 gate_open_turnstile(gate
);
2331 ordered_store_gate(gate
, state
);
2336 static kern_return_t
2337 gate_handoff_turnstile(gate_t
*gate
,
2339 thread_t
*thread_woken_up
,
2342 struct turnstile
*ts
= NULL
;
2343 kern_return_t ret
= KERN_FAILURE
;
2346 ts
= turnstile_prepare((uintptr_t)gate
, &gate
->turnstile
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
2348 * Wake up the higest priority thread waiting on the gate
2350 hp_thread
= waitq_wakeup64_identify(&ts
->ts_waitq
, CAST_EVENT64_T(GATE_EVENT(gate
)), THREAD_AWAKENED
, WAITQ_PROMOTE_ON_WAKE
);
2352 if (hp_thread
!= NULL
) {
2354 * In this case waitq_wakeup64_identify has called turnstile_update_inheritor for us
2356 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
2357 *thread_woken_up
= hp_thread
;
2358 *waiters
= turnstile_has_waiters(ts
);
2360 * Note: hp_thread is the new holder and the new inheritor.
2361 * In case there are no more waiters, it doesn't need to be the inheritor
2362 * and it shouldn't be it by the time it finishes the wait, so that its next open or
2363 * handoff can go through the fast path.
2364 * We could set the inheritor to NULL here, or the new holder itself can set it
2365 * on its way back from the sleep. In the latter case there are more chanses that
2366 * new waiters will come by, avoiding to do the opearation at all.
2371 * waiters can have been woken up by an interrupt and still not
2372 * have updated gate->waiters, so we couldn't find them on the waitq.
2373 * Update the inheritor to NULL here, so that the current thread can return to userspace
2374 * indipendently from when the interrupted waiters will finish the wait.
2376 if (flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
) {
2377 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
2378 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
2380 // there are no waiters.
2381 ret
= KERN_NOT_WAITING
;
2384 turnstile_complete((uintptr_t)gate
, &gate
->turnstile
, NULL
, TURNSTILE_KERNEL_MUTEX
);
2387 * We can do the cleanup while holding the interlock.
2389 * 1. current_thread is the previous inheritor and it is running
2390 * 2. new inheritor is NULL or it is a just wokenup thread that will race acquiring the lock
2391 * of the gate before trying to sleep.
2392 * => No chain of turnstiles needs to be updated.
2394 turnstile_cleanup();
2399 static kern_return_t
2400 gate_handoff(gate_t
*gate
,
2404 thread_t new_holder
= NULL
;
2408 thread_t thread
= current_thread();
2410 assert(flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
|| flags
== GATE_HANDOFF_DEFAULT
);
2412 if (flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
) {
2413 if (os_atomic_cmpxchg(&gate
->gate_data
, GATE_THREAD_TO_STATE(thread
), 0, release
)) {
2414 //gate opened but there were no waiters, so return KERN_NOT_WAITING.
2415 return KERN_NOT_WAITING
;
2420 state
= ordered_load_gate(gate
);
2421 holder
= GATE_STATE_TO_THREAD(state
);
2422 waiters
= gate_has_waiters(state
);
2424 if (holder
!= current_thread()) {
2425 panic("Handing off gate owned by %p from current thread %p", holder
, current_thread());
2429 ret
= gate_handoff_turnstile(gate
, flags
, &new_holder
, &waiters
);
2430 if (ret
== KERN_SUCCESS
) {
2431 state
= GATE_THREAD_TO_STATE(new_holder
);
2433 state
|= GATE_WAITERS
;
2436 if (flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
) {
2441 if (flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
) {
2444 ret
= KERN_NOT_WAITING
;
2446 state
|= GATE_ILOCK
;
2447 ordered_store_gate(gate
, state
);
2452 thread_deallocate(new_holder
);
2457 static void_func_void
2458 gate_steal_turnstile(gate_t
*gate
,
2459 thread_t new_inheritor
)
2461 struct turnstile
*ts
= NULL
;
2463 ts
= turnstile_prepare((uintptr_t)gate
, &gate
->turnstile
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
2465 turnstile_update_inheritor(ts
, new_inheritor
, (TURNSTILE_IMMEDIATE_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
2466 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
2467 turnstile_complete((uintptr_t)gate
, &gate
->turnstile
, NULL
, TURNSTILE_KERNEL_MUTEX
);
2470 * turnstile_cleanup might need to update the chain of the old holder.
2471 * This operation should happen without the turnstile interlock held.
2473 return turnstile_cleanup
;
2477 gate_steal(gate_t
*gate
)
2481 thread_t thread
= current_thread();
2484 void_func_void func_after_interlock_unlock
;
2487 state
= ordered_load_gate(gate
);
2488 holder
= GATE_STATE_TO_THREAD(state
);
2489 waiters
= gate_has_waiters(state
);
2491 assert(holder
!= NULL
);
2492 state
= GATE_THREAD_TO_STATE(thread
) | GATE_ILOCK
;
2494 state
|= GATE_WAITERS
;
2495 ordered_store_gate(gate
, state
);
2496 func_after_interlock_unlock
= gate_steal_turnstile(gate
, thread
);
2499 func_after_interlock_unlock();
2501 ordered_store_gate(gate
, state
);
2506 static void_func_void
2507 gate_wait_turnstile(gate_t
*gate
,
2508 wait_interrupt_t interruptible
,
2511 wait_result_t
* wait
,
2514 struct turnstile
*ts
;
2517 ts
= turnstile_prepare((uintptr_t)gate
, &gate
->turnstile
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
2519 turnstile_update_inheritor(ts
, holder
, (TURNSTILE_DELAYED_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
2520 waitq_assert_wait64(&ts
->ts_waitq
, CAST_EVENT64_T(GATE_EVENT(gate
)), interruptible
, deadline
);
2524 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
2526 *wait
= thread_block(THREAD_CONTINUE_NULL
);
2530 *waiters
= turnstile_has_waiters(ts
);
2534 * We want to enable the fast path as soon as we see that there are no more waiters.
2535 * On the fast path the holder will not do any turnstile operations.
2536 * Set the inheritor as NULL here.
2538 * NOTE: if it was an open operation that woke this thread up, the inheritor has
2539 * already been set to NULL.
2541 state
= ordered_load_gate(gate
);
2542 holder
= GATE_STATE_TO_THREAD(state
);
2544 ((*wait
!= THREAD_AWAKENED
) || // thread interrupted or timedout
2545 holder
== current_thread())) { // thread was woken up and it is the new holder
2546 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
2547 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
2551 turnstile_complete((uintptr_t)gate
, &gate
->turnstile
, NULL
, TURNSTILE_KERNEL_MUTEX
);
2554 * turnstile_cleanup might need to update the chain of the old holder.
2555 * This operation should happen without the turnstile primitive interlock held.
2557 return turnstile_cleanup
;
2560 static gate_wait_result_t
2561 gate_wait(gate_t
* gate
,
2562 wait_interrupt_t interruptible
,
2564 void (^primitive_unlock
)(void),
2565 void (^primitive_lock
)(void))
2567 gate_wait_result_t ret
;
2568 void_func_void func_after_interlock_unlock
;
2569 wait_result_t wait_result
;
2576 state
= ordered_load_gate(gate
);
2577 holder
= GATE_STATE_TO_THREAD(state
);
2579 if (holder
== NULL
) {
2580 panic("Trying to wait on open gate thread %p gate %p", current_thread(), gate
);
2583 state
|= GATE_WAITERS
;
2584 ordered_store_gate(gate
, state
);
2587 * Release the primitive lock before any
2588 * turnstile operation. Turnstile
2589 * does not support a blocking primitive as
2592 * In this way, concurrent threads will be
2593 * able to acquire the primitive lock
2594 * but still will wait for me through the
2599 func_after_interlock_unlock
= gate_wait_turnstile( gate
,
2606 state
= ordered_load_gate(gate
);
2607 holder
= GATE_STATE_TO_THREAD(state
);
2609 switch (wait_result
) {
2610 case THREAD_INTERRUPTED
:
2611 case THREAD_TIMED_OUT
:
2612 assert(holder
!= current_thread());
2615 state
|= GATE_WAITERS
;
2617 state
&= ~GATE_WAITERS
;
2619 ordered_store_gate(gate
, state
);
2621 if (wait_result
== THREAD_INTERRUPTED
) {
2622 ret
= GATE_INTERRUPTED
;
2624 ret
= GATE_TIMED_OUT
;
2629 * Note it is possible that even if the gate was handed off to
2630 * me, someone called gate_steal() before I woke up.
2632 * As well as it is possible that the gate was opened, but someone
2633 * closed it while I was waking up.
2635 * In both cases we return GATE_OPENED, as the gate was opened to me
2636 * at one point, it is the caller responsibility to check again if
2639 if (holder
== current_thread()) {
2650 * turnstile func that needs to be executed without
2651 * holding the primitive interlock
2653 func_after_interlock_unlock();
2660 gate_assert(gate_t
*gate
, int flags
)
2666 state
= ordered_load_gate(gate
);
2667 holder
= GATE_STATE_TO_THREAD(state
);
2670 case GATE_ASSERT_CLOSED
:
2671 assert(holder
!= NULL
);
2673 case GATE_ASSERT_OPEN
:
2674 assert(holder
== NULL
);
2676 case GATE_ASSERT_HELD
:
2677 assert(holder
== current_thread());
2680 panic("invalid %s flag %d", __func__
, flags
);
2687 gate_init(gate_t
*gate
)
2689 gate
->gate_data
= 0;
2690 gate
->turnstile
= NULL
;
2694 gate_destroy(__assert_only gate_t
*gate
)
2696 assert(gate
->gate_data
== 0);
2697 assert(gate
->turnstile
== NULL
);
2701 * Name: lck_rw_gate_init
2703 * Description: initializes a variable declared with decl_lck_rw_gate_data.
2706 * Arg1: lck_rw_t lock used to protect the gate.
2707 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2710 lck_rw_gate_init(lck_rw_t
*lock
, gate_t
*gate
)
2717 * Name: lck_rw_gate_destroy
2719 * Description: destroys a variable previously initialized.
2722 * Arg1: lck_rw_t lock used to protect the gate.
2723 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2726 lck_rw_gate_destroy(lck_rw_t
*lock
, gate_t
*gate
)
2733 * Name: lck_rw_gate_try_close
2735 * Description: Tries to close the gate.
2736 * In case of success the current thread will be set as
2737 * the holder of the gate.
2740 * Arg1: lck_rw_t lock used to protect the gate.
2741 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2743 * Conditions: Lock must be held. Returns with the lock held.
2746 * KERN_SUCCESS in case the gate was successfully closed. The current thread is the new holder
2748 * A matching lck_rw_gate_open() or lck_rw_gate_handoff() needs to be called later on
2749 * to wake up possible waiters on the gate before returning to userspace.
2750 * If the intent is to conditionally probe the gate before waiting, the lock must not be dropped
2751 * between the calls to lck_rw_gate_try_close() and lck_rw_gate_wait().
2753 * KERN_FAILURE in case the gate was already closed. Will panic if the current thread was already the holder of the gate.
2754 * lck_rw_gate_wait() should be called instead if the intent is to unconditionally wait on this gate.
2755 * The calls to lck_rw_gate_try_close() and lck_rw_gate_wait() should
2756 * be done without dropping the lock that is protecting the gate in between.
2759 lck_rw_gate_try_close(__assert_only lck_rw_t
*lock
, gate_t
*gate
)
2761 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2763 return gate_try_close(gate
);
2767 * Name: lck_rw_gate_close
2769 * Description: Closes the gate. The current thread will be set as
2770 * the holder of the gate. Will panic if the gate is already closed.
2771 * A matching lck_rw_gate_open() or lck_rw_gate_handoff() needs to be called later on
2772 * to wake up possible waiters on the gate before returning to userspace.
2775 * Arg1: lck_rw_t lock used to protect the gate.
2776 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2778 * Conditions: Lock must be held. Returns with the lock held.
2779 * The gate must be open.
2783 lck_rw_gate_close(__assert_only lck_rw_t
*lock
, gate_t
*gate
)
2785 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2787 return gate_close(gate
);
2791 * Name: lck_rw_gate_open
2793 * Description: Opens the gate and wakes up possible waiters.
2796 * Arg1: lck_rw_t lock used to protect the gate.
2797 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2799 * Conditions: Lock must be held. Returns with the lock held.
2800 * The current thread must be the holder of the gate.
2804 lck_rw_gate_open(__assert_only lck_rw_t
*lock
, gate_t
*gate
)
2806 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2812 * Name: lck_rw_gate_handoff
2814 * Description: Tries to transfer the ownership of the gate. The waiter with highest sched
2815 * priority will be selected as the new holder of the gate, and woken up,
2816 * with the gate remaining in the closed state throughout.
2817 * If no waiters are present, the gate will be kept closed and KERN_NOT_WAITING
2819 * GATE_HANDOFF_OPEN_IF_NO_WAITERS flag can be used to specify if the gate should be opened in
2820 * case no waiters were found.
2824 * Arg1: lck_rw_t lock used to protect the gate.
2825 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2826 * Arg3: flags - GATE_HANDOFF_DEFAULT or GATE_HANDOFF_OPEN_IF_NO_WAITERS
2828 * Conditions: Lock must be held. Returns with the lock held.
2829 * The current thread must be the holder of the gate.
2832 * KERN_SUCCESS in case one of the waiters became the new holder.
2833 * KERN_NOT_WAITING in case there were no waiters.
2837 lck_rw_gate_handoff(__assert_only lck_rw_t
*lock
, gate_t
*gate
, int flags
)
2839 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2841 return gate_handoff(gate
, flags
);
2845 * Name: lck_rw_gate_steal
2847 * Description: Set the current ownership of the gate. It sets the current thread as the
2848 * new holder of the gate.
2849 * A matching lck_rw_gate_open() or lck_rw_gate_handoff() needs to be called later on
2850 * to wake up possible waiters on the gate before returning to userspace.
2851 * NOTE: the previous holder should not call lck_rw_gate_open() or lck_rw_gate_handoff()
2856 * Arg1: lck_rw_t lock used to protect the gate.
2857 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2859 * Conditions: Lock must be held. Returns with the lock held.
2860 * The gate must be closed and the current thread must not already be the holder.
2864 lck_rw_gate_steal(__assert_only lck_rw_t
*lock
, gate_t
*gate
)
2866 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2872 * Name: lck_rw_gate_wait
2874 * Description: Waits for the current thread to become the holder of the gate or for the
2875 * gate to become open. An interruptible mode and deadline can be specified
2876 * to return earlier from the wait.
2879 * Arg1: lck_rw_t lock used to protect the gate.
2880 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2881 * Arg3: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_SHARED, LCK_SLEEP_EXCLUSIVE.
2882 * Arg3: interruptible flag for wait.
2885 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
2886 * Lock will be dropped while waiting.
2887 * The gate must be closed.
2889 * Returns: Reason why the thread was woken up.
2890 * GATE_HANDOFF - the current thread was handed off the ownership of the gate.
2891 * A matching lck_rw_gate_open() or lck_rw_gate_handoff() needs to be called later on
2892 * to wake up possible waiters on the gate before returning to userspace.
2893 * GATE_OPENED - the gate was opened by the holder.
2894 * GATE_TIMED_OUT - the thread was woken up by a timeout.
2895 * GATE_INTERRUPTED - the thread was interrupted while sleeping.
2899 lck_rw_gate_wait(lck_rw_t
*lock
, gate_t
*gate
, lck_sleep_action_t lck_sleep_action
, wait_interrupt_t interruptible
, uint64_t deadline
)
2901 __block lck_rw_type_t lck_rw_type
= LCK_RW_TYPE_EXCLUSIVE
;
2903 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2905 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
2906 return gate_wait(gate
,
2909 ^{lck_rw_type
= lck_rw_done(lock
);},
2911 } else if (!(lck_sleep_action
& (LCK_SLEEP_SHARED
| LCK_SLEEP_EXCLUSIVE
))) {
2912 return gate_wait(gate
,
2915 ^{lck_rw_type
= lck_rw_done(lock
);},
2916 ^{lck_rw_lock(lock
, lck_rw_type
);});
2917 } else if (lck_sleep_action
& LCK_SLEEP_EXCLUSIVE
) {
2918 return gate_wait(gate
,
2921 ^{lck_rw_type
= lck_rw_done(lock
);},
2922 ^{lck_rw_lock_exclusive(lock
);});
2924 return gate_wait(gate
,
2927 ^{lck_rw_type
= lck_rw_done(lock
);},
2928 ^{lck_rw_lock_shared(lock
);});
2933 * Name: lck_rw_gate_assert
2935 * Description: asserts that the gate is in the specified state.
2938 * Arg1: lck_rw_t lock used to protect the gate.
2939 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2940 * Arg3: flags to specified assert type.
2941 * GATE_ASSERT_CLOSED - the gate is currently closed
2942 * GATE_ASSERT_OPEN - the gate is currently opened
2943 * GATE_ASSERT_HELD - the gate is currently closed and the current thread is the holder
2946 lck_rw_gate_assert(__assert_only lck_rw_t
*lock
, gate_t
*gate
, int flags
)
2948 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2950 gate_assert(gate
, flags
);
2955 * Name: lck_mtx_gate_init
2957 * Description: initializes a variable declared with decl_lck_mtx_gate_data.
2960 * Arg1: lck_mtx_t lock used to protect the gate.
2961 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
2964 lck_mtx_gate_init(lck_mtx_t
*lock
, gate_t
*gate
)
2971 * Name: lck_mtx_gate_destroy
2973 * Description: destroys a variable previously initialized
2976 * Arg1: lck_mtx_t lock used to protect the gate.
2977 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
2980 lck_mtx_gate_destroy(lck_mtx_t
*lock
, gate_t
*gate
)
2987 * Name: lck_mtx_gate_try_close
2989 * Description: Tries to close the gate.
2990 * In case of success the current thread will be set as
2991 * the holder of the gate.
2994 * Arg1: lck_mtx_t lock used to protect the gate.
2995 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
2997 * Conditions: Lock must be held. Returns with the lock held.
3000 * KERN_SUCCESS in case the gate was successfully closed. The current thread is the new holder
3002 * A matching lck_mtx_gate_open() or lck_mtx_gate_handoff() needs to be called later on
3003 * to wake up possible waiters on the gate before returning to userspace.
3004 * If the intent is to conditionally probe the gate before waiting, the lock must not be dropped
3005 * between the calls to lck_mtx_gate_try_close() and lck_mtx_gate_wait().
3007 * KERN_FAILURE in case the gate was already closed. Will panic if the current thread was already the holder of the gate.
3008 * lck_mtx_gate_wait() should be called instead if the intent is to unconditionally wait on this gate.
3009 * The calls to lck_mtx_gate_try_close() and lck_mtx_gate_wait() should
3010 * be done without dropping the lock that is protecting the gate in between.
3013 lck_mtx_gate_try_close(__assert_only lck_mtx_t
*lock
, gate_t
*gate
)
3015 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3017 return gate_try_close(gate
);
3021 * Name: lck_mtx_gate_close
3023 * Description: Closes the gate. The current thread will be set as
3024 * the holder of the gate. Will panic if the gate is already closed.
3025 * A matching lck_mtx_gate_open() or lck_mtx_gate_handoff() needs to be called later on
3026 * to wake up possible waiters on the gate before returning to userspace.
3029 * Arg1: lck_mtx_t lock used to protect the gate.
3030 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3032 * Conditions: Lock must be held. Returns with the lock held.
3033 * The gate must be open.
3037 lck_mtx_gate_close(__assert_only lck_mtx_t
*lock
, gate_t
*gate
)
3039 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3041 return gate_close(gate
);
3045 * Name: lck_mtx_gate_open
3047 * Description: Opens of the gate and wakes up possible waiters.
3050 * Arg1: lck_mtx_t lock used to protect the gate.
3051 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3053 * Conditions: Lock must be held. Returns with the lock held.
3054 * The current thread must be the holder of the gate.
3058 lck_mtx_gate_open(__assert_only lck_mtx_t
*lock
, gate_t
*gate
)
3060 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3066 * Name: lck_mtx_gate_handoff
3068 * Description: Set the current ownership of the gate. The waiter with highest sched
3069 * priority will be selected as the new holder of the gate, and woken up,
3070 * with the gate remaining in the closed state throughout.
3071 * If no waiters are present, the gate will be kept closed and KERN_NOT_WAITING
3073 * OPEN_ON_FAILURE flag can be used to specify if the gate should be opened in
3074 * case no waiters were found.
3078 * Arg1: lck_mtx_t lock used to protect the gate.
3079 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3080 * Arg3: flags - GATE_NO_FALGS or OPEN_ON_FAILURE
3082 * Conditions: Lock must be held. Returns with the lock held.
3083 * The current thread must be the holder of the gate.
3086 * KERN_SUCCESS in case one of the waiters became the new holder.
3087 * KERN_NOT_WAITING in case there were no waiters.
3091 lck_mtx_gate_handoff(__assert_only lck_mtx_t
*lock
, gate_t
*gate
, int flags
)
3093 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3095 return gate_handoff(gate
, flags
);
3099 * Name: lck_mtx_gate_steal
3101 * Description: Steals the ownership of the gate. It sets the current thread as the
3102 * new holder of the gate.
3103 * A matching lck_mtx_gate_open() or lck_mtx_gate_handoff() needs to be called later on
3104 * to wake up possible waiters on the gate before returning to userspace.
3105 * NOTE: the previous holder should not call lck_mtx_gate_open() or lck_mtx_gate_handoff()
3110 * Arg1: lck_mtx_t lock used to protect the gate.
3111 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3113 * Conditions: Lock must be held. Returns with the lock held.
3114 * The gate must be closed and the current thread must not already be the holder.
3118 lck_mtx_gate_steal(__assert_only lck_mtx_t
*lock
, gate_t
*gate
)
3120 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3126 * Name: lck_mtx_gate_wait
3128 * Description: Waits for the current thread to become the holder of the gate or for the
3129 * gate to become open. An interruptible mode and deadline can be specified
3130 * to return earlier from the wait.
3133 * Arg1: lck_mtx_t lock used to protect the gate.
3134 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3135 * Arg3: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_UNLOCK, LCK_SLEEP_SPIN, LCK_SLEEP_SPIN_ALWAYS.
3136 * Arg3: interruptible flag for wait.
3139 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
3140 * Lock will be dropped while waiting.
3141 * The gate must be closed.
3143 * Returns: Reason why the thread was woken up.
3144 * GATE_HANDOFF - the current thread was handed off the ownership of the gate.
3145 * A matching lck_mtx_gate_open() or lck_mtx_gate_handoff() needs to be called later on
3146 * to wake up possible waiters on the gate before returning to userspace.
3147 * GATE_OPENED - the gate was opened by the holder.
3148 * GATE_TIMED_OUT - the thread was woken up by a timeout.
3149 * GATE_INTERRUPTED - the thread was interrupted while sleeping.
3153 lck_mtx_gate_wait(lck_mtx_t
*lock
, gate_t
*gate
, lck_sleep_action_t lck_sleep_action
, wait_interrupt_t interruptible
, uint64_t deadline
)
3155 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3157 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
3158 return gate_wait(gate
,
3161 ^{lck_mtx_unlock(lock
);},
3163 } else if (lck_sleep_action
& LCK_SLEEP_SPIN
) {
3164 return gate_wait(gate
,
3167 ^{lck_mtx_unlock(lock
);},
3168 ^{lck_mtx_lock_spin(lock
);});
3169 } else if (lck_sleep_action
& LCK_SLEEP_SPIN_ALWAYS
) {
3170 return gate_wait(gate
,
3173 ^{lck_mtx_unlock(lock
);},
3174 ^{lck_mtx_lock_spin_always(lock
);});
3176 return gate_wait(gate
,
3179 ^{lck_mtx_unlock(lock
);},
3180 ^{lck_mtx_lock(lock
);});
3185 * Name: lck_mtx_gate_assert
3187 * Description: asserts that the gate is in the specified state.
3190 * Arg1: lck_mtx_t lock used to protect the gate.
3191 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3192 * Arg3: flags to specified assert type.
3193 * GATE_ASSERT_CLOSED - the gate is currently closed
3194 * GATE_ASSERT_OPEN - the gate is currently opened
3195 * GATE_ASSERT_HELD - the gate is currently closed and the current thread is the holder
3198 lck_mtx_gate_assert(__assert_only lck_mtx_t
*lock
, gate_t
*gate
, int flags
)
3200 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3202 gate_assert(gate
, flags
);
3205 #pragma mark - LCK_*_DECLARE support
3209 lck_grp_attr_startup_init(struct lck_grp_attr_startup_spec
*sp
)
3211 lck_grp_attr_t
*attr
= sp
->grp_attr
;
3212 lck_grp_attr_setdefault(attr
);
3213 attr
->grp_attr_val
|= sp
->grp_attr_set_flags
;
3214 attr
->grp_attr_val
&= ~sp
->grp_attr_clear_flags
;
3219 lck_grp_startup_init(struct lck_grp_startup_spec
*sp
)
3221 lck_grp_init(sp
->grp
, sp
->grp_name
, sp
->grp_attr
);
3226 lck_attr_startup_init(struct lck_attr_startup_spec
*sp
)
3228 lck_attr_t
*attr
= sp
->lck_attr
;
3229 lck_attr_setdefault(attr
);
3230 attr
->lck_attr_val
|= sp
->lck_attr_set_flags
;
3231 attr
->lck_attr_val
&= ~sp
->lck_attr_clear_flags
;
3236 lck_spin_startup_init(struct lck_spin_startup_spec
*sp
)
3238 lck_spin_init(sp
->lck
, sp
->lck_grp
, sp
->lck_attr
);
3243 lck_mtx_startup_init(struct lck_mtx_startup_spec
*sp
)
3246 lck_mtx_init_ext(sp
->lck
, sp
->lck_ext
, sp
->lck_grp
, sp
->lck_attr
);
3248 lck_mtx_init(sp
->lck
, sp
->lck_grp
, sp
->lck_attr
);
3254 lck_rw_startup_init(struct lck_rw_startup_spec
*sp
)
3256 lck_rw_init(sp
->lck
, sp
->lck_grp
, sp
->lck_attr
);
3261 usimple_lock_startup_init(struct usimple_lock_startup_spec
*sp
)
3263 simple_lock_init(sp
->lck
, sp
->lck_init_arg
);