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.
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
));
676 * Routine: hw_lock_to
678 * Acquire lock, spinning until it becomes available or timeout.
679 * Timeout is in mach_absolute_time ticks, return with
680 * preemption disabled.
684 (hw_lock_to
)(hw_lock_t lock
, uint64_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
))
688 unsigned int success
= 0;
690 thread
= current_thread();
691 disable_preemption_for_thread(thread
);
692 state
= LCK_MTX_THREAD_TO_STATE(thread
) | PLATFORM_LCK_ILOCK
;
694 if (ordered_load_hw(lock
)) {
697 #endif // LOCK_PRETEST
698 if (hw_lock_trylock_contended(lock
, state
)) {
704 #endif // LOCK_PRETEST
705 success
= hw_lock_lock_contended(lock
, state
, timeout
, FALSE
LCK_GRP_ARG(grp
));
708 lck_grp_spin_update_held(lock
LCK_GRP_ARG(grp
));
714 * Routine: hw_lock_try
716 * returns with preemption disabled on success.
718 static inline unsigned int
719 hw_lock_try_internal(hw_lock_t lock
, thread_t thread
LCK_GRP_ARG(lck_grp_t
*grp
))
724 if (ordered_load_hw(lock
)) {
727 #endif // LOCK_PRETEST
728 success
= os_atomic_cmpxchg(&lock
->lock_data
, 0,
729 LCK_MTX_THREAD_TO_STATE(thread
) | PLATFORM_LCK_ILOCK
, acquire
);
733 #endif // LOCK_PRETEST
735 lck_grp_spin_update_held(lock
LCK_GRP_ARG(grp
));
742 (hw_lock_try
)(hw_lock_t lock
LCK_GRP_ARG(lck_grp_t
*grp
))
744 thread_t thread
= current_thread();
745 disable_preemption_for_thread(thread
);
746 unsigned int success
= hw_lock_try_internal(lock
, thread
LCK_GRP_ARG(grp
));
755 (hw_lock_try_nopreempt
)(hw_lock_t lock
LCK_GRP_ARG(lck_grp_t
*grp
))
757 thread_t thread
= current_thread();
758 if (__improbable(!preemption_disabled_for_thread(thread
))) {
759 panic("Attempt to test no-preempt spinlock %p in preemptible context", lock
);
761 return hw_lock_try_internal(lock
, thread
LCK_GRP_ARG(grp
));
765 * Routine: hw_lock_unlock
767 * Unconditionally release lock, release preemption level.
770 hw_lock_unlock_internal(hw_lock_t lock
)
772 os_atomic_store(&lock
->lock_data
, 0, release
);
773 #if __arm__ || __arm64__
774 // ARM tests are only for open-source exclusion
776 #endif // __arm__ || __arm64__
778 LOCKSTAT_RECORD(LS_LCK_SPIN_UNLOCK_RELEASE
, lock
, 0);
779 #endif /* CONFIG_DTRACE */
783 (hw_lock_unlock
)(hw_lock_t lock
)
785 hw_lock_unlock_internal(lock
);
790 (hw_lock_unlock_nopreempt
)(hw_lock_t lock
)
792 if (__improbable(!preemption_disabled_for_thread(current_thread()))) {
793 panic("Attempt to release no-preempt spinlock %p in preemptible context", lock
);
795 hw_lock_unlock_internal(lock
);
799 * Routine hw_lock_held, doesn't change preemption state.
800 * N.B. Racy, of course.
803 hw_lock_held(hw_lock_t lock
)
805 return ordered_load_hw(lock
) != 0;
809 hw_lock_bit_to_contended(hw_lock_bit_t
*lock
, uint32_t mask
, uint32_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
));
811 static inline unsigned int
812 hw_lock_bit_to_internal(hw_lock_bit_t
*lock
, unsigned int bit
, uint32_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
))
814 unsigned int success
= 0;
815 uint32_t mask
= (1 << bit
);
817 if (__improbable(!hw_atomic_test_and_set32(lock
, mask
, mask
, memory_order_acquire
, FALSE
))) {
818 success
= hw_lock_bit_to_contended(lock
, mask
, timeout
LCK_GRP_ARG(grp
));
824 lck_grp_spin_update_held(lock
LCK_GRP_ARG(grp
));
832 (hw_lock_bit_to
)(hw_lock_bit_t
* lock
, unsigned int bit
, uint32_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
))
834 _disable_preemption();
835 return hw_lock_bit_to_internal(lock
, bit
, timeout
LCK_GRP_ARG(grp
));
838 static unsigned int NOINLINE
839 hw_lock_bit_to_contended(hw_lock_bit_t
*lock
, uint32_t mask
, uint32_t timeout
LCK_GRP_ARG(lck_grp_t
*grp
))
843 #if CONFIG_DTRACE || LOCK_STATS
845 boolean_t stat_enabled
= lck_grp_spin_spin_enabled(lock
LCK_GRP_ARG(grp
));
846 #endif /* CONFIG_DTRACE || LOCK_STATS */
848 #if LOCK_STATS || CONFIG_DTRACE
849 if (__improbable(stat_enabled
)) {
850 begin
= mach_absolute_time();
852 #endif /* LOCK_STATS || CONFIG_DTRACE */
854 for (i
= 0; i
< LOCK_SNOOP_SPINS
; i
++) {
855 // Always load-exclusive before wfe
856 // This grabs the monitor and wakes up on a release event
857 if (hw_atomic_test_and_set32(lock
, mask
, mask
, memory_order_acquire
, TRUE
)) {
862 end
= ml_get_timebase() + timeout
;
863 } else if (ml_get_timebase() >= end
) {
869 #if CONFIG_DTRACE || LOCK_STATS
870 if (__improbable(stat_enabled
)) {
871 lck_grp_spin_update_spin(lock
LCK_GRP_ARG(grp
), mach_absolute_time() - begin
);
873 lck_grp_spin_update_miss(lock
LCK_GRP_ARG(grp
));
874 #endif /* CONFIG_DTRACE || LCK_GRP_STAT */
880 (hw_lock_bit
)(hw_lock_bit_t
* lock
, unsigned int bit
LCK_GRP_ARG(lck_grp_t
*grp
))
882 if (hw_lock_bit_to(lock
, bit
, LOCK_PANIC_TIMEOUT
, LCK_GRP_PROBEARG(grp
))) {
885 panic("hw_lock_bit(): timed out (%p)", lock
);
889 (hw_lock_bit_nopreempt
)(hw_lock_bit_t
* lock
, unsigned int bit
LCK_GRP_ARG(lck_grp_t
*grp
))
891 if (__improbable(get_preemption_level() == 0)) {
892 panic("Attempt to take no-preempt bitlock %p in preemptible context", lock
);
894 if (hw_lock_bit_to_internal(lock
, bit
, LOCK_PANIC_TIMEOUT
LCK_GRP_ARG(grp
))) {
897 panic("hw_lock_bit_nopreempt(): timed out (%p)", lock
);
902 (hw_lock_bit_try
)(hw_lock_bit_t
* lock
, unsigned int bit
LCK_GRP_ARG(lck_grp_t
*grp
))
904 uint32_t mask
= (1 << bit
);
905 boolean_t success
= FALSE
;
907 _disable_preemption();
908 // TODO: consider weak (non-looping) atomic test-and-set
909 success
= hw_atomic_test_and_set32(lock
, mask
, mask
, memory_order_acquire
, FALSE
);
911 _enable_preemption();
915 lck_grp_spin_update_held(lock
LCK_GRP_ARG(grp
));
922 hw_unlock_bit_internal(hw_lock_bit_t
*lock
, unsigned int bit
)
924 uint32_t mask
= (1 << bit
);
926 os_atomic_andnot(lock
, mask
, release
);
931 LOCKSTAT_RECORD(LS_LCK_SPIN_UNLOCK_RELEASE
, lock
, bit
);
936 * Routine: hw_unlock_bit
938 * Release spin-lock. The second parameter is the bit number to test and set.
939 * Decrement the preemption level.
942 hw_unlock_bit(hw_lock_bit_t
* lock
, unsigned int bit
)
944 hw_unlock_bit_internal(lock
, bit
);
945 _enable_preemption();
949 hw_unlock_bit_nopreempt(hw_lock_bit_t
* lock
, unsigned int bit
)
951 if (__improbable(get_preemption_level() == 0)) {
952 panic("Attempt to release no-preempt bitlock %p in preemptible context", lock
);
954 hw_unlock_bit_internal(lock
, bit
);
958 * Routine: lck_spin_sleep
963 lck_sleep_action_t lck_sleep_action
,
965 wait_interrupt_t interruptible
,
970 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
971 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
974 res
= assert_wait(event
, interruptible
);
975 if (res
== THREAD_WAITING
) {
976 lck_spin_unlock(lck
);
977 res
= thread_block(THREAD_CONTINUE_NULL
);
978 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
979 lck_spin_lock_grp(lck
, grp
);
981 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
982 lck_spin_unlock(lck
);
991 lck_sleep_action_t lck_sleep_action
,
993 wait_interrupt_t interruptible
)
995 return lck_spin_sleep_grp(lck
, lck_sleep_action
, event
, interruptible
, LCK_GRP_NULL
);
999 * Routine: lck_spin_sleep_deadline
1002 lck_spin_sleep_deadline(
1004 lck_sleep_action_t lck_sleep_action
,
1006 wait_interrupt_t interruptible
,
1011 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1012 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1015 res
= assert_wait_deadline(event
, interruptible
, deadline
);
1016 if (res
== THREAD_WAITING
) {
1017 lck_spin_unlock(lck
);
1018 res
= thread_block(THREAD_CONTINUE_NULL
);
1019 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1022 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1023 lck_spin_unlock(lck
);
1030 * Routine: lck_mtx_sleep
1035 lck_sleep_action_t lck_sleep_action
,
1037 wait_interrupt_t interruptible
)
1040 thread_t thread
= current_thread();
1042 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_SLEEP_CODE
) | DBG_FUNC_START
,
1043 VM_KERNEL_UNSLIDE_OR_PERM(lck
), (int)lck_sleep_action
, VM_KERNEL_UNSLIDE_OR_PERM(event
), (int)interruptible
, 0);
1045 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1046 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1049 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1051 * We overload the RW lock promotion to give us a priority ceiling
1052 * during the time that this thread is asleep, so that when it
1053 * is re-awakened (and not yet contending on the mutex), it is
1054 * runnable at a reasonably high priority.
1056 thread
->rwlock_count
++;
1059 res
= assert_wait(event
, interruptible
);
1060 if (res
== THREAD_WAITING
) {
1061 lck_mtx_unlock(lck
);
1062 res
= thread_block(THREAD_CONTINUE_NULL
);
1063 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1064 if ((lck_sleep_action
& LCK_SLEEP_SPIN
)) {
1065 lck_mtx_lock_spin(lck
);
1066 } else if ((lck_sleep_action
& LCK_SLEEP_SPIN_ALWAYS
)) {
1067 lck_mtx_lock_spin_always(lck
);
1072 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1073 lck_mtx_unlock(lck
);
1076 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1077 if ((thread
->rwlock_count
-- == 1 /* field now 0 */) && (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1078 /* sched_flags checked without lock, but will be rechecked while clearing */
1079 lck_rw_clear_promotion(thread
, unslide_for_kdebug(event
));
1083 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_SLEEP_CODE
) | DBG_FUNC_END
, (int)res
, 0, 0, 0, 0);
1090 * Routine: lck_mtx_sleep_deadline
1093 lck_mtx_sleep_deadline(
1095 lck_sleep_action_t lck_sleep_action
,
1097 wait_interrupt_t interruptible
,
1101 thread_t thread
= current_thread();
1103 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_SLEEP_DEADLINE_CODE
) | DBG_FUNC_START
,
1104 VM_KERNEL_UNSLIDE_OR_PERM(lck
), (int)lck_sleep_action
, VM_KERNEL_UNSLIDE_OR_PERM(event
), (int)interruptible
, 0);
1106 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1107 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1110 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1112 * See lck_mtx_sleep().
1114 thread
->rwlock_count
++;
1117 res
= assert_wait_deadline(event
, interruptible
, deadline
);
1118 if (res
== THREAD_WAITING
) {
1119 lck_mtx_unlock(lck
);
1120 res
= thread_block(THREAD_CONTINUE_NULL
);
1121 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1122 if ((lck_sleep_action
& LCK_SLEEP_SPIN
)) {
1123 lck_mtx_lock_spin(lck
);
1128 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1129 lck_mtx_unlock(lck
);
1132 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1133 if ((thread
->rwlock_count
-- == 1 /* field now 0 */) && (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1134 /* sched_flags checked without lock, but will be rechecked while clearing */
1135 lck_rw_clear_promotion(thread
, unslide_for_kdebug(event
));
1139 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_SLEEP_DEADLINE_CODE
) | DBG_FUNC_END
, (int)res
, 0, 0, 0, 0);
1145 * Lock Boosting Invariants:
1147 * The lock owner is always promoted to the max priority of all its waiters.
1148 * Max priority is capped at MAXPRI_PROMOTE.
1150 * The last waiter is not given a promotion when it wakes up or acquires the lock.
1151 * When the last waiter is waking up, a new contender can always come in and
1152 * steal the lock without having to wait for the last waiter to make forward progress.
1156 * Routine: lck_mtx_lock_wait
1158 * Invoked in order to wait on contention.
1160 * Called with the interlock locked and
1161 * returns it unlocked.
1163 * Always aggressively sets the owning thread to promoted,
1164 * even if it's the same or higher priority
1165 * This prevents it from lowering its own priority while holding a lock
1167 * TODO: Come up with a more efficient way to handle same-priority promotions
1168 * <rdar://problem/30737670> ARM mutex contention logic could avoid taking the thread lock
1174 struct turnstile
**ts
)
1176 thread_t thread
= current_thread();
1178 __kdebug_only
uintptr_t trace_lck
= unslide_for_kdebug(lck
);
1181 uint64_t sleep_start
= 0;
1183 if (lockstat_probemap
[LS_LCK_MTX_LOCK_BLOCK
] || lockstat_probemap
[LS_LCK_MTX_EXT_LOCK_BLOCK
]) {
1184 sleep_start
= mach_absolute_time();
1188 if (lck
->lck_mtx_tag
!= LCK_MTX_TAG_INDIRECT
) {
1191 mutex
= &lck
->lck_mtx_ptr
->lck_mtx
;
1194 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_LCK_WAIT_CODE
) | DBG_FUNC_START
,
1195 trace_lck
, (uintptr_t)thread_tid(thread
), 0, 0, 0);
1197 assert(thread
->waiting_for_mutex
== NULL
);
1198 thread
->waiting_for_mutex
= mutex
;
1199 mutex
->lck_mtx_waiters
++;
1202 *ts
= turnstile_prepare((uintptr_t)mutex
, NULL
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
1205 struct turnstile
*turnstile
= *ts
;
1206 thread_set_pending_block_hint(thread
, kThreadWaitKernelMutex
);
1207 turnstile_update_inheritor(turnstile
, holder
, (TURNSTILE_DELAYED_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
1209 waitq_assert_wait64(&turnstile
->ts_waitq
, CAST_EVENT64_T(LCK_MTX_EVENT(mutex
)), THREAD_UNINT
| THREAD_WAIT_NOREPORT_USER
, TIMEOUT_WAIT_FOREVER
);
1211 lck_mtx_ilk_unlock(mutex
);
1213 turnstile_update_inheritor_complete(turnstile
, TURNSTILE_INTERLOCK_NOT_HELD
);
1215 thread_block(THREAD_CONTINUE_NULL
);
1217 thread
->waiting_for_mutex
= NULL
;
1219 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_LCK_WAIT_CODE
) | DBG_FUNC_END
, 0, 0, 0, 0, 0);
1222 * Record the DTrace lockstat probe for blocking, block time
1223 * measured from when we were entered.
1226 if (lck
->lck_mtx_tag
!= LCK_MTX_TAG_INDIRECT
) {
1227 LOCKSTAT_RECORD(LS_LCK_MTX_LOCK_BLOCK
, lck
,
1228 mach_absolute_time() - sleep_start
);
1230 LOCKSTAT_RECORD(LS_LCK_MTX_EXT_LOCK_BLOCK
, lck
,
1231 mach_absolute_time() - sleep_start
);
1238 * Routine: lck_mtx_lock_acquire
1240 * Invoked on acquiring the mutex when there is
1243 * Returns the current number of waiters.
1245 * Called with the interlock locked.
1248 lck_mtx_lock_acquire(
1250 struct turnstile
*ts
)
1252 thread_t thread
= current_thread();
1255 if (lck
->lck_mtx_tag
!= LCK_MTX_TAG_INDIRECT
) {
1258 mutex
= &lck
->lck_mtx_ptr
->lck_mtx
;
1261 assert(thread
->waiting_for_mutex
== NULL
);
1263 if (mutex
->lck_mtx_waiters
> 0) {
1265 ts
= turnstile_prepare((uintptr_t)mutex
, NULL
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
1268 turnstile_update_inheritor(ts
, thread
, (TURNSTILE_IMMEDIATE_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
1269 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
1273 turnstile_complete((uintptr_t)mutex
, NULL
, NULL
, TURNSTILE_KERNEL_MUTEX
);
1276 return mutex
->lck_mtx_waiters
;
1280 * Routine: lck_mtx_unlock_wakeup
1282 * Invoked on unlock when there is contention.
1284 * Called with the interlock locked.
1286 * NOTE: callers should call turnstile_clenup after
1287 * dropping the interlock.
1290 lck_mtx_unlock_wakeup(
1294 thread_t thread
= current_thread();
1296 __kdebug_only
uintptr_t trace_lck
= unslide_for_kdebug(lck
);
1297 struct turnstile
*ts
;
1298 kern_return_t did_wake
;
1300 if (lck
->lck_mtx_tag
!= LCK_MTX_TAG_INDIRECT
) {
1303 mutex
= &lck
->lck_mtx_ptr
->lck_mtx
;
1306 if (thread
!= holder
) {
1307 panic("lck_mtx_unlock_wakeup: mutex %p holder %p\n", mutex
, holder
);
1310 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_UNLCK_WAKEUP_CODE
) | DBG_FUNC_START
,
1311 trace_lck
, (uintptr_t)thread_tid(thread
), 0, 0, 0);
1313 assert(mutex
->lck_mtx_waiters
> 0);
1314 assert(thread
->waiting_for_mutex
== NULL
);
1316 ts
= turnstile_prepare((uintptr_t)mutex
, NULL
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
1318 if (mutex
->lck_mtx_waiters
> 1) {
1319 /* WAITQ_PROMOTE_ON_WAKE will call turnstile_update_inheritor on the wokenup thread */
1320 did_wake
= waitq_wakeup64_one(&ts
->ts_waitq
, CAST_EVENT64_T(LCK_MTX_EVENT(mutex
)), THREAD_AWAKENED
, WAITQ_PROMOTE_ON_WAKE
);
1322 did_wake
= waitq_wakeup64_one(&ts
->ts_waitq
, CAST_EVENT64_T(LCK_MTX_EVENT(mutex
)), THREAD_AWAKENED
, WAITQ_ALL_PRIORITIES
);
1323 turnstile_update_inheritor(ts
, NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
1325 assert(did_wake
== KERN_SUCCESS
);
1327 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
1328 turnstile_complete((uintptr_t)mutex
, NULL
, NULL
, TURNSTILE_KERNEL_MUTEX
);
1330 mutex
->lck_mtx_waiters
--;
1332 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_MTX_UNLCK_WAKEUP_CODE
) | DBG_FUNC_END
, 0, 0, 0, 0, 0);
1334 return mutex
->lck_mtx_waiters
> 0;
1338 * Routine: mutex_pause
1340 * Called by former callers of simple_lock_pause().
1342 #define MAX_COLLISION_COUNTS 32
1343 #define MAX_COLLISION 8
1345 unsigned int max_collision_count
[MAX_COLLISION_COUNTS
];
1347 uint32_t collision_backoffs
[MAX_COLLISION
] = {
1348 10, 50, 100, 200, 400, 600, 800, 1000
1353 mutex_pause(uint32_t collisions
)
1355 wait_result_t wait_result
;
1358 if (collisions
>= MAX_COLLISION_COUNTS
) {
1359 collisions
= MAX_COLLISION_COUNTS
- 1;
1361 max_collision_count
[collisions
]++;
1363 if (collisions
>= MAX_COLLISION
) {
1364 collisions
= MAX_COLLISION
- 1;
1366 back_off
= collision_backoffs
[collisions
];
1368 wait_result
= assert_wait_timeout((event_t
)mutex_pause
, THREAD_UNINT
, back_off
, NSEC_PER_USEC
);
1369 assert(wait_result
== THREAD_WAITING
);
1371 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1372 assert(wait_result
== THREAD_TIMED_OUT
);
1376 unsigned int mutex_yield_wait
= 0;
1377 unsigned int mutex_yield_no_wait
= 0;
1386 lck_mtx_assert(lck
, LCK_MTX_ASSERT_OWNED
);
1389 if (lck
->lck_mtx_tag
== LCK_MTX_TAG_INDIRECT
) {
1390 waiters
= lck
->lck_mtx_ptr
->lck_mtx
.lck_mtx_waiters
;
1392 waiters
= lck
->lck_mtx_waiters
;
1396 mutex_yield_no_wait
++;
1399 lck_mtx_unlock(lck
);
1407 * Routine: lck_rw_sleep
1412 lck_sleep_action_t lck_sleep_action
,
1414 wait_interrupt_t interruptible
)
1417 lck_rw_type_t lck_rw_type
;
1418 thread_t thread
= current_thread();
1420 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1421 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1424 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1426 * Although we are dropping the RW lock, the intent in most cases
1427 * is that this thread remains as an observer, since it may hold
1428 * some secondary resource, but must yield to avoid deadlock. In
1429 * this situation, make sure that the thread is boosted to the
1430 * RW lock ceiling while blocked, so that it can re-acquire the
1431 * RW lock at that priority.
1433 thread
->rwlock_count
++;
1436 res
= assert_wait(event
, interruptible
);
1437 if (res
== THREAD_WAITING
) {
1438 lck_rw_type
= lck_rw_done(lck
);
1439 res
= thread_block(THREAD_CONTINUE_NULL
);
1440 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1441 if (!(lck_sleep_action
& (LCK_SLEEP_SHARED
| LCK_SLEEP_EXCLUSIVE
))) {
1442 lck_rw_lock(lck
, lck_rw_type
);
1443 } else if (lck_sleep_action
& LCK_SLEEP_EXCLUSIVE
) {
1444 lck_rw_lock_exclusive(lck
);
1446 lck_rw_lock_shared(lck
);
1449 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1450 (void)lck_rw_done(lck
);
1453 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1454 if ((thread
->rwlock_count
-- == 1 /* field now 0 */) && (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1455 /* sched_flags checked without lock, but will be rechecked while clearing */
1457 /* Only if the caller wanted the lck_rw_t returned unlocked should we drop to 0 */
1458 assert(lck_sleep_action
& LCK_SLEEP_UNLOCK
);
1460 lck_rw_clear_promotion(thread
, unslide_for_kdebug(event
));
1469 * Routine: lck_rw_sleep_deadline
1472 lck_rw_sleep_deadline(
1474 lck_sleep_action_t lck_sleep_action
,
1476 wait_interrupt_t interruptible
,
1480 lck_rw_type_t lck_rw_type
;
1481 thread_t thread
= current_thread();
1483 if ((lck_sleep_action
& ~LCK_SLEEP_MASK
) != 0) {
1484 panic("Invalid lock sleep action %x\n", lck_sleep_action
);
1487 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1488 thread
->rwlock_count
++;
1491 res
= assert_wait_deadline(event
, interruptible
, deadline
);
1492 if (res
== THREAD_WAITING
) {
1493 lck_rw_type
= lck_rw_done(lck
);
1494 res
= thread_block(THREAD_CONTINUE_NULL
);
1495 if (!(lck_sleep_action
& LCK_SLEEP_UNLOCK
)) {
1496 if (!(lck_sleep_action
& (LCK_SLEEP_SHARED
| LCK_SLEEP_EXCLUSIVE
))) {
1497 lck_rw_lock(lck
, lck_rw_type
);
1498 } else if (lck_sleep_action
& LCK_SLEEP_EXCLUSIVE
) {
1499 lck_rw_lock_exclusive(lck
);
1501 lck_rw_lock_shared(lck
);
1504 } else if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1505 (void)lck_rw_done(lck
);
1508 if (lck_sleep_action
& LCK_SLEEP_PROMOTED_PRI
) {
1509 if ((thread
->rwlock_count
-- == 1 /* field now 0 */) && (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1510 /* sched_flags checked without lock, but will be rechecked while clearing */
1512 /* Only if the caller wanted the lck_rw_t returned unlocked should we drop to 0 */
1513 assert(lck_sleep_action
& LCK_SLEEP_UNLOCK
);
1515 lck_rw_clear_promotion(thread
, unslide_for_kdebug(event
));
1523 * Reader-writer lock promotion
1525 * We support a limited form of reader-writer
1526 * lock promotion whose effects are:
1528 * * Qualifying threads have decay disabled
1529 * * Scheduler priority is reset to a floor of
1530 * of their statically assigned priority
1533 * The rationale is that lck_rw_ts do not have
1534 * a single owner, so we cannot apply a directed
1535 * priority boost from all waiting threads
1536 * to all holding threads without maintaining
1537 * lists of all shared owners and all waiting
1538 * threads for every lock.
1540 * Instead (and to preserve the uncontended fast-
1541 * path), acquiring (or attempting to acquire)
1542 * a RW lock in shared or exclusive lock increments
1543 * a per-thread counter. Only if that thread stops
1544 * making forward progress (for instance blocking
1545 * on a mutex, or being preempted) do we consult
1546 * the counter and apply the priority floor.
1547 * When the thread becomes runnable again (or in
1548 * the case of preemption it never stopped being
1549 * runnable), it has the priority boost and should
1550 * be in a good position to run on the CPU and
1551 * release all RW locks (at which point the priority
1552 * boost is cleared).
1554 * Care must be taken to ensure that priority
1555 * boosts are not retained indefinitely, since unlike
1556 * mutex priority boosts (where the boost is tied
1557 * to the mutex lifecycle), the boost is tied
1558 * to the thread and independent of any particular
1559 * lck_rw_t. Assertions are in place on return
1560 * to userspace so that the boost is not held
1563 * The routines that increment/decrement the
1564 * per-thread counter should err on the side of
1565 * incrementing any time a preemption is possible
1566 * and the lock would be visible to the rest of the
1567 * system as held (so it should be incremented before
1568 * interlocks are dropped/preemption is enabled, or
1569 * before a CAS is executed to acquire the lock).
1574 * lck_rw_clear_promotion: Undo priority promotions when the last RW
1575 * lock is released by a thread (if a promotion was active)
1578 lck_rw_clear_promotion(thread_t thread
, uintptr_t trace_obj
)
1580 assert(thread
->rwlock_count
== 0);
1582 /* Cancel any promotions if the thread had actually blocked while holding a RW lock */
1583 spl_t s
= splsched();
1584 thread_lock(thread
);
1586 if (thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
) {
1587 sched_thread_unpromote_reason(thread
, TH_SFLAG_RW_PROMOTED
, trace_obj
);
1590 thread_unlock(thread
);
1595 * Callout from context switch if the thread goes
1596 * off core with a positive rwlock_count
1598 * Called at splsched with the thread locked
1601 lck_rw_set_promotion_locked(thread_t thread
)
1603 if (LcksOpts
& disLkRWPrio
) {
1607 assert(thread
->rwlock_count
> 0);
1609 if (!(thread
->sched_flags
& TH_SFLAG_RW_PROMOTED
)) {
1610 sched_thread_promote_reason(thread
, TH_SFLAG_RW_PROMOTED
, 0);
1615 host_lockgroup_info(
1617 lockgroup_info_array_t
*lockgroup_infop
,
1618 mach_msg_type_number_t
*lockgroup_infoCntp
)
1620 lockgroup_info_t
*lockgroup_info_base
;
1621 lockgroup_info_t
*lockgroup_info
;
1622 vm_offset_t lockgroup_info_addr
;
1623 vm_size_t lockgroup_info_size
;
1624 vm_size_t lockgroup_info_vmsize
;
1630 if (host
== HOST_NULL
) {
1631 return KERN_INVALID_HOST
;
1634 lck_mtx_lock(&lck_grp_lock
);
1636 lockgroup_info_size
= lck_grp_cnt
* sizeof(*lockgroup_info
);
1637 lockgroup_info_vmsize
= round_page(lockgroup_info_size
);
1638 kr
= kmem_alloc_pageable(ipc_kernel_map
,
1639 &lockgroup_info_addr
, lockgroup_info_vmsize
, VM_KERN_MEMORY_IPC
);
1640 if (kr
!= KERN_SUCCESS
) {
1641 lck_mtx_unlock(&lck_grp_lock
);
1645 lockgroup_info_base
= (lockgroup_info_t
*) lockgroup_info_addr
;
1646 lck_grp
= (lck_grp_t
*)queue_first(&lck_grp_queue
);
1647 lockgroup_info
= lockgroup_info_base
;
1649 for (i
= 0; i
< lck_grp_cnt
; i
++) {
1650 lockgroup_info
->lock_spin_cnt
= lck_grp
->lck_grp_spincnt
;
1651 lockgroup_info
->lock_rw_cnt
= lck_grp
->lck_grp_rwcnt
;
1652 lockgroup_info
->lock_mtx_cnt
= lck_grp
->lck_grp_mtxcnt
;
1655 lockgroup_info
->lock_spin_held_cnt
= lck_grp
->lck_grp_stats
.lgss_spin_held
.lgs_count
;
1656 lockgroup_info
->lock_spin_miss_cnt
= lck_grp
->lck_grp_stats
.lgss_spin_miss
.lgs_count
;
1657 #endif /* LOCK_STATS */
1659 // Historically on x86, held was used for "direct wait" and util for "held"
1660 lockgroup_info
->lock_mtx_util_cnt
= lck_grp
->lck_grp_stats
.lgss_mtx_held
.lgs_count
;
1661 lockgroup_info
->lock_mtx_held_cnt
= lck_grp
->lck_grp_stats
.lgss_mtx_direct_wait
.lgs_count
;
1662 lockgroup_info
->lock_mtx_miss_cnt
= lck_grp
->lck_grp_stats
.lgss_mtx_miss
.lgs_count
;
1663 lockgroup_info
->lock_mtx_wait_cnt
= lck_grp
->lck_grp_stats
.lgss_mtx_wait
.lgs_count
;
1665 (void) strncpy(lockgroup_info
->lockgroup_name
, lck_grp
->lck_grp_name
, LOCKGROUP_MAX_NAME
);
1667 lck_grp
= (lck_grp_t
*)(queue_next((queue_entry_t
)(lck_grp
)));
1671 *lockgroup_infoCntp
= lck_grp_cnt
;
1672 lck_mtx_unlock(&lck_grp_lock
);
1674 if (lockgroup_info_size
!= lockgroup_info_vmsize
) {
1675 bzero((char *)lockgroup_info
, lockgroup_info_vmsize
- lockgroup_info_size
);
1678 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)lockgroup_info_addr
,
1679 (vm_map_size_t
)lockgroup_info_size
, TRUE
, ©
);
1680 assert(kr
== KERN_SUCCESS
);
1682 *lockgroup_infop
= (lockgroup_info_t
*) copy
;
1684 return KERN_SUCCESS
;
1688 * sleep_with_inheritor and wakeup_with_inheritor KPI
1690 * Functions that allow to sleep on an event and use turnstile to propagate the priority of the sleeping threads to
1691 * the latest thread specified as inheritor.
1693 * 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
1694 * 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
1695 * wakeup_with_inheritor from inheritor before running in userspace or specify another inheritor before letting the old inheritor run in userspace.
1697 * sleep_with_inheritor requires to hold a locking primitive while invoked, but wakeup_with_inheritor and change_sleep_inheritor don't require it.
1699 * Turnstile requires a non blocking primitive as interlock to synchronize the turnstile data structure manipulation, threfore sleep_with_inheritor, change_sleep_inheritor and
1700 * wakeup_with_inheritor will require the same interlock to manipulate turnstiles.
1701 * 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
1702 * invoking any turnstile operation.
1704 * 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
1705 * 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
1706 * is instantiated for this KPI to manage the hash without interrupt disabled.
1708 * - all events on the system that hash on the same bucket will contend on the same spinlock.
1709 * - every event will have a dedicated wait_queue.
1711 * Different locking primitives can be associated with sleep_with_inheritor as long as the primitive_lock() and primitive_unlock() functions are provided to
1712 * sleep_with_inheritor_turnstile to perform the handoff with the bucket spinlock.
1716 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
)
1719 struct turnstile
*ts
= NULL
;
1720 kern_return_t ret
= KERN_NOT_WAITING
;
1725 * the hash bucket spinlock is used as turnstile interlock
1727 turnstile_hash_bucket_lock((uintptr_t)event
, &index
, type
);
1729 ts
= turnstile_prepare((uintptr_t)event
, NULL
, TURNSTILE_NULL
, type
);
1732 if (action
== LCK_WAKE_DEFAULT
) {
1733 priority
= WAITQ_PROMOTE_ON_WAKE
;
1735 assert(action
== LCK_WAKE_DO_NOT_TRANSFER_PUSH
);
1736 priority
= WAITQ_ALL_PRIORITIES
;
1740 * WAITQ_PROMOTE_ON_WAKE will call turnstile_update_inheritor
1741 * if it finds a thread
1743 wokeup
= waitq_wakeup64_identify(&ts
->ts_waitq
, CAST_EVENT64_T(event
), result
, priority
);
1744 if (wokeup
!= NULL
) {
1745 if (thread_wokenup
!= NULL
) {
1746 *thread_wokenup
= wokeup
;
1748 thread_deallocate_safe(wokeup
);
1751 if (action
== LCK_WAKE_DO_NOT_TRANSFER_PUSH
) {
1755 if (thread_wokenup
!= NULL
) {
1756 *thread_wokenup
= NULL
;
1758 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
1759 ret
= KERN_NOT_WAITING
;
1762 ret
= waitq_wakeup64_all(&ts
->ts_waitq
, CAST_EVENT64_T(event
), result
, WAITQ_ALL_PRIORITIES
);
1763 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
1767 * turnstile_update_inheritor_complete could be called while holding the interlock.
1768 * In this case the new inheritor or is null, or is a thread that is just been woken up
1769 * and have not blocked because it is racing with the same interlock used here
1771 * So there is no chain to update for the new inheritor.
1773 * However unless the current thread is the old inheritor,
1774 * old inheritor can be blocked and requires a chain update.
1776 * The chain should be short because kernel turnstiles cannot have user turnstiles
1777 * chained after them.
1779 * We can anyway optimize this by asking turnstile to tell us
1780 * if old inheritor needs an update and drop the lock
1781 * just in that case.
1783 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1785 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
1787 turnstile_hash_bucket_lock((uintptr_t)NULL
, &index
, type
);
1790 turnstile_complete((uintptr_t)event
, NULL
, NULL
, type
);
1792 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1794 turnstile_cleanup();
1799 static wait_result_t
1800 sleep_with_inheritor_and_turnstile_type(event_t event
,
1802 wait_interrupt_t interruptible
,
1804 turnstile_type_t type
,
1805 void (^primitive_lock
)(void),
1806 void (^primitive_unlock
)(void))
1810 struct turnstile
*ts
= NULL
;
1813 * the hash bucket spinlock is used as turnstile interlock,
1814 * lock it before releasing the primitive lock
1816 turnstile_hash_bucket_lock((uintptr_t)event
, &index
, type
);
1820 ts
= turnstile_prepare((uintptr_t)event
, NULL
, TURNSTILE_NULL
, type
);
1822 thread_set_pending_block_hint(current_thread(), kThreadWaitSleepWithInheritor
);
1824 * We need TURNSTILE_DELAYED_UPDATE because we will call
1825 * waitq_assert_wait64 after.
1827 turnstile_update_inheritor(ts
, inheritor
, (TURNSTILE_DELAYED_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
1829 ret
= waitq_assert_wait64(&ts
->ts_waitq
, CAST_EVENT64_T(event
), interruptible
, deadline
);
1831 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1834 * Update new and old inheritor chains outside the interlock;
1836 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
1838 if (ret
== THREAD_WAITING
) {
1839 ret
= thread_block(THREAD_CONTINUE_NULL
);
1842 turnstile_hash_bucket_lock((uintptr_t)NULL
, &index
, type
);
1844 turnstile_complete((uintptr_t)event
, NULL
, NULL
, type
);
1846 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1848 turnstile_cleanup();
1856 change_sleep_inheritor_and_turnstile_type(event_t event
,
1858 turnstile_type_t type
)
1861 struct turnstile
*ts
= NULL
;
1862 kern_return_t ret
= KERN_SUCCESS
;
1864 * the hash bucket spinlock is used as turnstile interlock
1866 turnstile_hash_bucket_lock((uintptr_t)event
, &index
, type
);
1868 ts
= turnstile_prepare((uintptr_t)event
, NULL
, TURNSTILE_NULL
, type
);
1870 if (!turnstile_has_waiters(ts
)) {
1871 ret
= KERN_NOT_WAITING
;
1875 * We will not call an assert_wait later so use TURNSTILE_IMMEDIATE_UPDATE
1877 turnstile_update_inheritor(ts
, inheritor
, (TURNSTILE_IMMEDIATE_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
1879 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1882 * update the chains outside the interlock
1884 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
1886 turnstile_hash_bucket_lock((uintptr_t)NULL
, &index
, type
);
1888 turnstile_complete((uintptr_t)event
, NULL
, NULL
, type
);
1890 turnstile_hash_bucket_unlock((uintptr_t)NULL
, &index
, type
, 0);
1892 turnstile_cleanup();
1897 typedef void (^void_block_void
)(void);
1900 * sleep_with_inheritor functions with lck_mtx_t as locking primitive.
1904 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
)
1906 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
1908 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1909 return sleep_with_inheritor_and_turnstile_type(event
,
1915 ^{lck_mtx_unlock(lock
);});
1916 } else if (lck_sleep_action
& LCK_SLEEP_SPIN
) {
1917 return sleep_with_inheritor_and_turnstile_type(event
,
1922 ^{lck_mtx_lock_spin(lock
);},
1923 ^{lck_mtx_unlock(lock
);});
1924 } else if (lck_sleep_action
& LCK_SLEEP_SPIN_ALWAYS
) {
1925 return sleep_with_inheritor_and_turnstile_type(event
,
1930 ^{lck_mtx_lock_spin_always(lock
);},
1931 ^{lck_mtx_unlock(lock
);});
1933 return sleep_with_inheritor_and_turnstile_type(event
,
1938 ^{lck_mtx_lock(lock
);},
1939 ^{lck_mtx_unlock(lock
);});
1944 * Name: lck_spin_sleep_with_inheritor
1946 * Description: deschedule the current thread and wait on the waitq associated with event to be woken up.
1947 * While waiting, the sched priority of the waiting thread will contribute to the push of the event that will
1948 * be directed to the inheritor specified.
1949 * An interruptible mode and deadline can be specified to return earlier from the wait.
1952 * 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.
1953 * Arg2: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_UNLOCK.
1954 * Arg3: event to wait on.
1955 * Arg4: thread to propagate the event push to.
1956 * Arg5: interruptible flag for wait.
1957 * Arg6: deadline for wait.
1959 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
1960 * Lock will be dropped while waiting.
1961 * The inheritor specified cannot run in user space until another inheritor is specified for the event or a
1962 * wakeup for the event is called.
1964 * Returns: result of the wait.
1967 lck_spin_sleep_with_inheritor(
1969 lck_sleep_action_t lck_sleep_action
,
1972 wait_interrupt_t interruptible
,
1975 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
1976 return sleep_with_inheritor_and_turnstile_type(event
, inheritor
,
1977 interruptible
, deadline
, TURNSTILE_SLEEP_INHERITOR
,
1978 ^{}, ^{ lck_spin_unlock(lock
); });
1980 return sleep_with_inheritor_and_turnstile_type(event
, inheritor
,
1981 interruptible
, deadline
, TURNSTILE_SLEEP_INHERITOR
,
1982 ^{ lck_spin_lock(lock
); }, ^{ lck_spin_unlock(lock
); });
1987 * Name: lck_mtx_sleep_with_inheritor
1989 * Description: deschedule the current thread and wait on the waitq associated with event to be woken up.
1990 * While waiting, the sched priority of the waiting thread will contribute to the push of the event that will
1991 * be directed to the inheritor specified.
1992 * An interruptible mode and deadline can be specified to return earlier from the wait.
1995 * 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.
1996 * Arg2: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_UNLOCK, LCK_SLEEP_SPIN, LCK_SLEEP_SPIN_ALWAYS.
1997 * Arg3: event to wait on.
1998 * Arg4: thread to propagate the event push to.
1999 * Arg5: interruptible flag for wait.
2000 * Arg6: deadline for wait.
2002 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
2003 * Lock will be dropped while waiting.
2004 * The inheritor specified cannot run in user space until another inheritor is specified for the event or a
2005 * wakeup for the event is called.
2007 * Returns: result of the wait.
2010 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
)
2012 return lck_mtx_sleep_with_inheritor_and_turnstile_type(lock
, lck_sleep_action
, event
, inheritor
, interruptible
, deadline
, TURNSTILE_SLEEP_INHERITOR
);
2016 * sleep_with_inheritor functions with lck_rw_t as locking primitive.
2020 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
)
2022 __block lck_rw_type_t lck_rw_type
= LCK_RW_TYPE_EXCLUSIVE
;
2024 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2026 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
2027 return sleep_with_inheritor_and_turnstile_type(event
,
2033 ^{lck_rw_type
= lck_rw_done(lock
);});
2034 } else if (!(lck_sleep_action
& (LCK_SLEEP_SHARED
| LCK_SLEEP_EXCLUSIVE
))) {
2035 return sleep_with_inheritor_and_turnstile_type(event
,
2040 ^{lck_rw_lock(lock
, lck_rw_type
);},
2041 ^{lck_rw_type
= lck_rw_done(lock
);});
2042 } else if (lck_sleep_action
& LCK_SLEEP_EXCLUSIVE
) {
2043 return sleep_with_inheritor_and_turnstile_type(event
,
2048 ^{lck_rw_lock_exclusive(lock
);},
2049 ^{lck_rw_type
= lck_rw_done(lock
);});
2051 return sleep_with_inheritor_and_turnstile_type(event
,
2056 ^{lck_rw_lock_shared(lock
);},
2057 ^{lck_rw_type
= lck_rw_done(lock
);});
2062 * Name: lck_rw_sleep_with_inheritor
2064 * Description: deschedule the current thread and wait on the waitq associated with event to be woken up.
2065 * While waiting, the sched priority of the waiting thread will contribute to the push of the event that will
2066 * be directed to the inheritor specified.
2067 * An interruptible mode and deadline can be specified to return earlier from the wait.
2070 * 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.
2071 * Arg2: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_SHARED, LCK_SLEEP_EXCLUSIVE.
2072 * Arg3: event to wait on.
2073 * Arg4: thread to propagate the event push to.
2074 * Arg5: interruptible flag for wait.
2075 * Arg6: deadline for wait.
2077 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
2078 * Lock will be dropped while waiting.
2079 * The inheritor specified cannot run in user space until another inheritor is specified for the event or a
2080 * wakeup for the event is called.
2082 * Returns: result of the wait.
2085 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
)
2087 return lck_rw_sleep_with_inheritor_and_turnstile_type(lock
, lck_sleep_action
, event
, inheritor
, interruptible
, deadline
, TURNSTILE_SLEEP_INHERITOR
);
2091 * wakeup_with_inheritor functions are independent from the locking primitive.
2095 * Name: wakeup_one_with_inheritor
2097 * 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.
2098 * The push for the event will be transferred from the last inheritor to the woken up thread if LCK_WAKE_DEFAULT is specified.
2099 * If LCK_WAKE_DO_NOT_TRANSFER_PUSH is specified the push will not be transferred.
2102 * Arg1: event to wake from.
2103 * Arg2: wait result to pass to the woken up thread.
2104 * Arg3: wake flag. LCK_WAKE_DEFAULT or LCK_WAKE_DO_NOT_TRANSFER_PUSH.
2105 * Arg4: pointer for storing the thread wokenup.
2107 * Returns: KERN_NOT_WAITING if no threads were waiting, KERN_SUCCESS otherwise.
2109 * Conditions: The new inheritor wokenup cannot run in user space until another inheritor is specified for the event or a
2110 * wakeup for the event is called.
2111 * A reference for the wokenup thread is acquired.
2112 * NOTE: this cannot be called from interrupt context.
2115 wakeup_one_with_inheritor(event_t event
, wait_result_t result
, lck_wake_action_t action
, thread_t
*thread_wokenup
)
2117 return wakeup_with_inheritor_and_turnstile_type(event
,
2118 TURNSTILE_SLEEP_INHERITOR
,
2126 * Name: wakeup_all_with_inheritor
2128 * Description: wake up all waiters waiting for event. The old inheritor will lose the push.
2131 * Arg1: event to wake from.
2132 * Arg2: wait result to pass to the woken up threads.
2134 * Returns: KERN_NOT_WAITING if no threads were waiting, KERN_SUCCESS otherwise.
2136 * Conditions: NOTE: this cannot be called from interrupt context.
2139 wakeup_all_with_inheritor(event_t event
, wait_result_t result
)
2141 return wakeup_with_inheritor_and_turnstile_type(event
,
2142 TURNSTILE_SLEEP_INHERITOR
,
2150 * change_sleep_inheritor is independent from the locking primitive.
2154 * Name: change_sleep_inheritor
2156 * Description: Redirect the push of the waiting threads of event to the new inheritor specified.
2159 * Arg1: event to redirect the push.
2160 * Arg2: new inheritor for event.
2162 * Returns: KERN_NOT_WAITING if no threads were waiting, KERN_SUCCESS otherwise.
2164 * Conditions: In case of success, the new inheritor cannot run in user space until another inheritor is specified for the event or a
2165 * wakeup for the event is called.
2166 * NOTE: this cannot be called from interrupt context.
2169 change_sleep_inheritor(event_t event
, thread_t inheritor
)
2171 return change_sleep_inheritor_and_turnstile_type(event
,
2173 TURNSTILE_SLEEP_INHERITOR
);
2177 kdp_sleep_with_inheritor_find_owner(struct waitq
* waitq
, __unused event64_t event
, thread_waitinfo_t
* waitinfo
)
2179 assert(waitinfo
->wait_type
== kThreadWaitSleepWithInheritor
);
2180 assert(waitq_is_turnstile_queue(waitq
));
2181 waitinfo
->owner
= 0;
2182 waitinfo
->context
= 0;
2184 if (waitq_held(waitq
)) {
2188 struct turnstile
*turnstile
= waitq_to_turnstile(waitq
);
2189 assert(turnstile
->ts_inheritor_flags
& TURNSTILE_INHERITOR_THREAD
);
2190 waitinfo
->owner
= thread_tid(turnstile
->ts_inheritor
);
2193 typedef void (*void_func_void
)(void);
2195 static kern_return_t
2196 gate_try_close(gate_t
*gate
)
2201 __assert_only
bool waiters
;
2202 thread_t thread
= current_thread();
2204 if (os_atomic_cmpxchg(&gate
->gate_data
, 0, GATE_THREAD_TO_STATE(thread
), acquire
)) {
2205 return KERN_SUCCESS
;
2209 state
= ordered_load_gate(gate
);
2210 holder
= GATE_STATE_TO_THREAD(state
);
2212 if (holder
== NULL
) {
2213 waiters
= gate_has_waiters(state
);
2214 assert(waiters
== FALSE
);
2216 state
= GATE_THREAD_TO_STATE(current_thread());
2217 state
|= GATE_ILOCK
;
2218 ordered_store_gate(gate
, state
);
2221 if (holder
== current_thread()) {
2222 panic("Trying to close a gate already owned by current thread %p", current_thread());
2232 gate_close(gate_t
* gate
)
2236 __assert_only
bool waiters
;
2237 thread_t thread
= current_thread();
2239 if (os_atomic_cmpxchg(&gate
->gate_data
, 0, GATE_THREAD_TO_STATE(thread
), acquire
)) {
2244 state
= ordered_load_gate(gate
);
2245 holder
= GATE_STATE_TO_THREAD(state
);
2247 if (holder
!= NULL
) {
2248 panic("Closing a gate already owned by %p from current thread %p", holder
, current_thread());
2251 waiters
= gate_has_waiters(state
);
2252 assert(waiters
== FALSE
);
2254 state
= GATE_THREAD_TO_STATE(thread
);
2255 state
|= GATE_ILOCK
;
2256 ordered_store_gate(gate
, state
);
2262 gate_open_turnstile(gate_t
*gate
)
2264 struct turnstile
*ts
= NULL
;
2266 ts
= turnstile_prepare((uintptr_t)gate
, &gate
->turnstile
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
2267 waitq_wakeup64_all(&ts
->ts_waitq
, CAST_EVENT64_T(GATE_EVENT(gate
)), THREAD_AWAKENED
, WAITQ_ALL_PRIORITIES
);
2268 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
2269 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
2270 turnstile_complete((uintptr_t)gate
, &gate
->turnstile
, NULL
, TURNSTILE_KERNEL_MUTEX
);
2272 * We can do the cleanup while holding the interlock.
2274 * 1. current_thread is the previous inheritor and it is running
2275 * 2. new inheritor is NULL.
2276 * => No chain of turnstiles needs to be updated.
2278 turnstile_cleanup();
2282 gate_open(gate_t
*gate
)
2287 thread_t thread
= current_thread();
2289 if (os_atomic_cmpxchg(&gate
->gate_data
, GATE_THREAD_TO_STATE(thread
), 0, release
)) {
2294 state
= ordered_load_gate(gate
);
2295 holder
= GATE_STATE_TO_THREAD(state
);
2296 waiters
= gate_has_waiters(state
);
2298 if (holder
!= thread
) {
2299 panic("Opening gate owned by %p from current thread %p", holder
, thread
);
2303 gate_open_turnstile(gate
);
2307 ordered_store_gate(gate
, state
);
2312 static kern_return_t
2313 gate_handoff_turnstile(gate_t
*gate
,
2315 thread_t
*thread_woken_up
,
2318 struct turnstile
*ts
= NULL
;
2319 kern_return_t ret
= KERN_FAILURE
;
2322 ts
= turnstile_prepare((uintptr_t)gate
, &gate
->turnstile
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
2324 * Wake up the higest priority thread waiting on the gate
2326 hp_thread
= waitq_wakeup64_identify(&ts
->ts_waitq
, CAST_EVENT64_T(GATE_EVENT(gate
)), THREAD_AWAKENED
, WAITQ_PROMOTE_ON_WAKE
);
2328 if (hp_thread
!= NULL
) {
2330 * In this case waitq_wakeup64_identify has called turnstile_update_inheritor for us
2332 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
2333 *thread_woken_up
= hp_thread
;
2334 *waiters
= turnstile_has_waiters(ts
);
2336 * Note: hp_thread is the new holder and the new inheritor.
2337 * In case there are no more waiters, it doesn't need to be the inheritor
2338 * and it shouldn't be it by the time it finishes the wait, so that its next open or
2339 * handoff can go through the fast path.
2340 * We could set the inheritor to NULL here, or the new holder itself can set it
2341 * on its way back from the sleep. In the latter case there are more chanses that
2342 * new waiters will come by, avoiding to do the opearation at all.
2347 * waiters can have been woken up by an interrupt and still not
2348 * have updated gate->waiters, so we couldn't find them on the waitq.
2349 * Update the inheritor to NULL here, so that the current thread can return to userspace
2350 * indipendently from when the interrupted waiters will finish the wait.
2352 if (flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
) {
2353 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
2354 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
2356 // there are no waiters.
2357 ret
= KERN_NOT_WAITING
;
2360 turnstile_complete((uintptr_t)gate
, &gate
->turnstile
, NULL
, TURNSTILE_KERNEL_MUTEX
);
2363 * We can do the cleanup while holding the interlock.
2365 * 1. current_thread is the previous inheritor and it is running
2366 * 2. new inheritor is NULL or it is a just wokenup thread that will race acquiring the lock
2367 * of the gate before trying to sleep.
2368 * => No chain of turnstiles needs to be updated.
2370 turnstile_cleanup();
2375 static kern_return_t
2376 gate_handoff(gate_t
*gate
,
2380 thread_t new_holder
= NULL
;
2384 thread_t thread
= current_thread();
2386 assert(flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
|| flags
== GATE_HANDOFF_DEFAULT
);
2388 if (flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
) {
2389 if (os_atomic_cmpxchg(&gate
->gate_data
, GATE_THREAD_TO_STATE(thread
), 0, release
)) {
2390 //gate opened but there were no waiters, so return KERN_NOT_WAITING.
2391 return KERN_NOT_WAITING
;
2396 state
= ordered_load_gate(gate
);
2397 holder
= GATE_STATE_TO_THREAD(state
);
2398 waiters
= gate_has_waiters(state
);
2400 if (holder
!= current_thread()) {
2401 panic("Handing off gate owned by %p from current thread %p", holder
, current_thread());
2405 ret
= gate_handoff_turnstile(gate
, flags
, &new_holder
, &waiters
);
2406 if (ret
== KERN_SUCCESS
) {
2407 state
= GATE_THREAD_TO_STATE(new_holder
);
2409 state
|= GATE_WAITERS
;
2412 if (flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
) {
2417 if (flags
== GATE_HANDOFF_OPEN_IF_NO_WAITERS
) {
2420 ret
= KERN_NOT_WAITING
;
2422 state
|= GATE_ILOCK
;
2423 ordered_store_gate(gate
, state
);
2428 thread_deallocate(new_holder
);
2433 static void_func_void
2434 gate_steal_turnstile(gate_t
*gate
,
2435 thread_t new_inheritor
)
2437 struct turnstile
*ts
= NULL
;
2439 ts
= turnstile_prepare((uintptr_t)gate
, &gate
->turnstile
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
2441 turnstile_update_inheritor(ts
, new_inheritor
, (TURNSTILE_IMMEDIATE_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
2442 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_HELD
);
2443 turnstile_complete((uintptr_t)gate
, &gate
->turnstile
, NULL
, TURNSTILE_KERNEL_MUTEX
);
2446 * turnstile_cleanup might need to update the chain of the old holder.
2447 * This operation should happen without the turnstile interlock held.
2449 return turnstile_cleanup
;
2453 gate_steal(gate_t
*gate
)
2457 thread_t thread
= current_thread();
2460 void_func_void func_after_interlock_unlock
;
2463 state
= ordered_load_gate(gate
);
2464 holder
= GATE_STATE_TO_THREAD(state
);
2465 waiters
= gate_has_waiters(state
);
2467 assert(holder
!= NULL
);
2468 state
= GATE_THREAD_TO_STATE(thread
) | GATE_ILOCK
;
2470 state
|= GATE_WAITERS
;
2471 ordered_store_gate(gate
, state
);
2472 func_after_interlock_unlock
= gate_steal_turnstile(gate
, thread
);
2475 func_after_interlock_unlock();
2477 ordered_store_gate(gate
, state
);
2482 static void_func_void
2483 gate_wait_turnstile(gate_t
*gate
,
2484 wait_interrupt_t interruptible
,
2487 wait_result_t
* wait
,
2490 struct turnstile
*ts
;
2493 ts
= turnstile_prepare((uintptr_t)gate
, &gate
->turnstile
, TURNSTILE_NULL
, TURNSTILE_KERNEL_MUTEX
);
2495 turnstile_update_inheritor(ts
, holder
, (TURNSTILE_DELAYED_UPDATE
| TURNSTILE_INHERITOR_THREAD
));
2496 waitq_assert_wait64(&ts
->ts_waitq
, CAST_EVENT64_T(GATE_EVENT(gate
)), interruptible
, deadline
);
2500 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
2502 *wait
= thread_block(THREAD_CONTINUE_NULL
);
2506 *waiters
= turnstile_has_waiters(ts
);
2510 * We want to enable the fast path as soon as we see that there are no more waiters.
2511 * On the fast path the holder will not do any turnstile operations.
2512 * Set the inheritor as NULL here.
2514 * NOTE: if it was an open operation that woke this thread up, the inheritor has
2515 * already been set to NULL.
2517 state
= ordered_load_gate(gate
);
2518 holder
= GATE_STATE_TO_THREAD(state
);
2520 ((*wait
!= THREAD_AWAKENED
) || // thread interrupted or timedout
2521 holder
== current_thread())) { // thread was woken up and it is the new holder
2522 turnstile_update_inheritor(ts
, TURNSTILE_INHERITOR_NULL
, TURNSTILE_IMMEDIATE_UPDATE
);
2523 turnstile_update_inheritor_complete(ts
, TURNSTILE_INTERLOCK_NOT_HELD
);
2527 turnstile_complete((uintptr_t)gate
, &gate
->turnstile
, NULL
, TURNSTILE_KERNEL_MUTEX
);
2530 * turnstile_cleanup might need to update the chain of the old holder.
2531 * This operation should happen without the turnstile primitive interlock held.
2533 return turnstile_cleanup
;
2536 static gate_wait_result_t
2537 gate_wait(gate_t
* gate
,
2538 wait_interrupt_t interruptible
,
2540 void (^primitive_unlock
)(void),
2541 void (^primitive_lock
)(void))
2543 gate_wait_result_t ret
;
2544 void_func_void func_after_interlock_unlock
;
2545 wait_result_t wait_result
;
2552 state
= ordered_load_gate(gate
);
2553 holder
= GATE_STATE_TO_THREAD(state
);
2555 if (holder
== NULL
) {
2556 panic("Trying to wait on open gate thread %p gate %p", current_thread(), gate
);
2559 state
|= GATE_WAITERS
;
2560 ordered_store_gate(gate
, state
);
2563 * Release the primitive lock before any
2564 * turnstile operation. Turnstile
2565 * does not support a blocking primitive as
2568 * In this way, concurrent threads will be
2569 * able to acquire the primitive lock
2570 * but still will wait for me through the
2575 func_after_interlock_unlock
= gate_wait_turnstile( gate
,
2582 state
= ordered_load_gate(gate
);
2583 holder
= GATE_STATE_TO_THREAD(state
);
2585 switch (wait_result
) {
2586 case THREAD_INTERRUPTED
:
2587 case THREAD_TIMED_OUT
:
2588 assert(holder
!= current_thread());
2591 state
|= GATE_WAITERS
;
2593 state
&= ~GATE_WAITERS
;
2595 ordered_store_gate(gate
, state
);
2597 if (wait_result
== THREAD_INTERRUPTED
) {
2598 ret
= GATE_INTERRUPTED
;
2600 ret
= GATE_TIMED_OUT
;
2605 * Note it is possible that even if the gate was handed off to
2606 * me, someone called gate_steal() before I woke up.
2608 * As well as it is possible that the gate was opened, but someone
2609 * closed it while I was waking up.
2611 * In both cases we return GATE_OPENED, as the gate was opened to me
2612 * at one point, it is the caller responsibility to check again if
2615 if (holder
== current_thread()) {
2626 * turnstile func that needs to be executed without
2627 * holding the primitive interlock
2629 func_after_interlock_unlock();
2636 gate_assert(gate_t
*gate
, int flags
)
2642 state
= ordered_load_gate(gate
);
2643 holder
= GATE_STATE_TO_THREAD(state
);
2646 case GATE_ASSERT_CLOSED
:
2647 assert(holder
!= NULL
);
2649 case GATE_ASSERT_OPEN
:
2650 assert(holder
== NULL
);
2652 case GATE_ASSERT_HELD
:
2653 assert(holder
== current_thread());
2656 panic("invalid %s flag %d", __func__
, flags
);
2663 gate_init(gate_t
*gate
)
2665 gate
->gate_data
= 0;
2666 gate
->turnstile
= NULL
;
2670 gate_destroy(__assert_only gate_t
*gate
)
2672 assert(gate
->gate_data
== 0);
2673 assert(gate
->turnstile
== NULL
);
2677 * Name: lck_rw_gate_init
2679 * Description: initializes a variable declared with decl_lck_rw_gate_data.
2682 * Arg1: lck_rw_t lock used to protect the gate.
2683 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2686 lck_rw_gate_init(lck_rw_t
*lock
, gate_t
*gate
)
2693 * Name: lck_rw_gate_destroy
2695 * Description: destroys a variable previously initialized.
2698 * Arg1: lck_rw_t lock used to protect the gate.
2699 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2702 lck_rw_gate_destroy(lck_rw_t
*lock
, gate_t
*gate
)
2709 * Name: lck_rw_gate_try_close
2711 * Description: Tries to close the gate.
2712 * In case of success the current thread will be set as
2713 * the holder of the gate.
2716 * Arg1: lck_rw_t lock used to protect the gate.
2717 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2719 * Conditions: Lock must be held. Returns with the lock held.
2722 * KERN_SUCCESS in case the gate was successfully closed. The current thread is the new holder
2724 * A matching lck_rw_gate_open() or lck_rw_gate_handoff() needs to be called later on
2725 * to wake up possible waiters on the gate before returning to userspace.
2726 * If the intent is to conditionally probe the gate before waiting, the lock must not be dropped
2727 * between the calls to lck_rw_gate_try_close() and lck_rw_gate_wait().
2729 * KERN_FAILURE in case the gate was already closed. Will panic if the current thread was already the holder of the gate.
2730 * lck_rw_gate_wait() should be called instead if the intent is to unconditionally wait on this gate.
2731 * The calls to lck_rw_gate_try_close() and lck_rw_gate_wait() should
2732 * be done without dropping the lock that is protecting the gate in between.
2735 lck_rw_gate_try_close(__assert_only lck_rw_t
*lock
, gate_t
*gate
)
2737 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2739 return gate_try_close(gate
);
2743 * Name: lck_rw_gate_close
2745 * Description: Closes the gate. The current thread will be set as
2746 * the holder of the gate. Will panic if the gate is already closed.
2747 * A matching lck_rw_gate_open() or lck_rw_gate_handoff() needs to be called later on
2748 * to wake up possible waiters on the gate before returning to userspace.
2751 * Arg1: lck_rw_t lock used to protect the gate.
2752 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2754 * Conditions: Lock must be held. Returns with the lock held.
2755 * The gate must be open.
2759 lck_rw_gate_close(__assert_only lck_rw_t
*lock
, gate_t
*gate
)
2761 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2763 return gate_close(gate
);
2767 * Name: lck_rw_gate_open
2769 * Description: Opens the gate and wakes up possible waiters.
2772 * Arg1: lck_rw_t lock used to protect the gate.
2773 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2775 * Conditions: Lock must be held. Returns with the lock held.
2776 * The current thread must be the holder of the gate.
2780 lck_rw_gate_open(__assert_only lck_rw_t
*lock
, gate_t
*gate
)
2782 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2788 * Name: lck_rw_gate_handoff
2790 * Description: Tries to transfer the ownership of the gate. The waiter with highest sched
2791 * priority will be selected as the new holder of the gate, and woken up,
2792 * with the gate remaining in the closed state throughout.
2793 * If no waiters are present, the gate will be kept closed and KERN_NOT_WAITING
2795 * GATE_HANDOFF_OPEN_IF_NO_WAITERS flag can be used to specify if the gate should be opened in
2796 * case no waiters were found.
2800 * Arg1: lck_rw_t lock used to protect the gate.
2801 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2802 * Arg3: flags - GATE_HANDOFF_DEFAULT or GATE_HANDOFF_OPEN_IF_NO_WAITERS
2804 * Conditions: Lock must be held. Returns with the lock held.
2805 * The current thread must be the holder of the gate.
2808 * KERN_SUCCESS in case one of the waiters became the new holder.
2809 * KERN_NOT_WAITING in case there were no waiters.
2813 lck_rw_gate_handoff(__assert_only lck_rw_t
*lock
, gate_t
*gate
, int flags
)
2815 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2817 return gate_handoff(gate
, flags
);
2821 * Name: lck_rw_gate_steal
2823 * Description: Set the current ownership of the gate. It sets the current thread as the
2824 * new holder of the gate.
2825 * A matching lck_rw_gate_open() or lck_rw_gate_handoff() needs to be called later on
2826 * to wake up possible waiters on the gate before returning to userspace.
2827 * NOTE: the previous holder should not call lck_rw_gate_open() or lck_rw_gate_handoff()
2832 * Arg1: lck_rw_t lock used to protect the gate.
2833 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2835 * Conditions: Lock must be held. Returns with the lock held.
2836 * The gate must be closed and the current thread must not already be the holder.
2840 lck_rw_gate_steal(__assert_only lck_rw_t
*lock
, gate_t
*gate
)
2842 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2848 * Name: lck_rw_gate_wait
2850 * Description: Waits for the current thread to become the holder of the gate or for the
2851 * gate to become open. An interruptible mode and deadline can be specified
2852 * to return earlier from the wait.
2855 * Arg1: lck_rw_t lock used to protect the gate.
2856 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2857 * Arg3: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_SHARED, LCK_SLEEP_EXCLUSIVE.
2858 * Arg3: interruptible flag for wait.
2861 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
2862 * Lock will be dropped while waiting.
2863 * The gate must be closed.
2865 * Returns: Reason why the thread was woken up.
2866 * GATE_HANDOFF - the current thread was handed off the ownership of the gate.
2867 * A matching lck_rw_gate_open() or lck_rw_gate_handoff() needs to be called later on
2868 * to wake up possible waiters on the gate before returning to userspace.
2869 * GATE_OPENED - the gate was opened by the holder.
2870 * GATE_TIMED_OUT - the thread was woken up by a timeout.
2871 * GATE_INTERRUPTED - the thread was interrupted while sleeping.
2875 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
)
2877 __block lck_rw_type_t lck_rw_type
= LCK_RW_TYPE_EXCLUSIVE
;
2879 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2881 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
2882 return gate_wait(gate
,
2885 ^{lck_rw_type
= lck_rw_done(lock
);},
2887 } else if (!(lck_sleep_action
& (LCK_SLEEP_SHARED
| LCK_SLEEP_EXCLUSIVE
))) {
2888 return gate_wait(gate
,
2891 ^{lck_rw_type
= lck_rw_done(lock
);},
2892 ^{lck_rw_lock(lock
, lck_rw_type
);});
2893 } else if (lck_sleep_action
& LCK_SLEEP_EXCLUSIVE
) {
2894 return gate_wait(gate
,
2897 ^{lck_rw_type
= lck_rw_done(lock
);},
2898 ^{lck_rw_lock_exclusive(lock
);});
2900 return gate_wait(gate
,
2903 ^{lck_rw_type
= lck_rw_done(lock
);},
2904 ^{lck_rw_lock_shared(lock
);});
2909 * Name: lck_rw_gate_assert
2911 * Description: asserts that the gate is in the specified state.
2914 * Arg1: lck_rw_t lock used to protect the gate.
2915 * Arg2: pointer to the gate data declared with decl_lck_rw_gate_data.
2916 * Arg3: flags to specified assert type.
2917 * GATE_ASSERT_CLOSED - the gate is currently closed
2918 * GATE_ASSERT_OPEN - the gate is currently opened
2919 * GATE_ASSERT_HELD - the gate is currently closed and the current thread is the holder
2922 lck_rw_gate_assert(__assert_only lck_rw_t
*lock
, gate_t
*gate
, int flags
)
2924 LCK_RW_ASSERT(lock
, LCK_RW_ASSERT_HELD
);
2926 gate_assert(gate
, flags
);
2931 * Name: lck_mtx_gate_init
2933 * Description: initializes a variable declared with decl_lck_mtx_gate_data.
2936 * Arg1: lck_mtx_t lock used to protect the gate.
2937 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
2940 lck_mtx_gate_init(lck_mtx_t
*lock
, gate_t
*gate
)
2947 * Name: lck_mtx_gate_destroy
2949 * Description: destroys a variable previously initialized
2952 * Arg1: lck_mtx_t lock used to protect the gate.
2953 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
2956 lck_mtx_gate_destroy(lck_mtx_t
*lock
, gate_t
*gate
)
2963 * Name: lck_mtx_gate_try_close
2965 * Description: Tries to close the gate.
2966 * In case of success the current thread will be set as
2967 * the holder of the gate.
2970 * Arg1: lck_mtx_t lock used to protect the gate.
2971 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
2973 * Conditions: Lock must be held. Returns with the lock held.
2976 * KERN_SUCCESS in case the gate was successfully closed. The current thread is the new holder
2978 * A matching lck_mtx_gate_open() or lck_mtx_gate_handoff() needs to be called later on
2979 * to wake up possible waiters on the gate before returning to userspace.
2980 * If the intent is to conditionally probe the gate before waiting, the lock must not be dropped
2981 * between the calls to lck_mtx_gate_try_close() and lck_mtx_gate_wait().
2983 * KERN_FAILURE in case the gate was already closed. Will panic if the current thread was already the holder of the gate.
2984 * lck_mtx_gate_wait() should be called instead if the intent is to unconditionally wait on this gate.
2985 * The calls to lck_mtx_gate_try_close() and lck_mtx_gate_wait() should
2986 * be done without dropping the lock that is protecting the gate in between.
2989 lck_mtx_gate_try_close(__assert_only lck_mtx_t
*lock
, gate_t
*gate
)
2991 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
2993 return gate_try_close(gate
);
2997 * Name: lck_mtx_gate_close
2999 * Description: Closes the gate. The current thread will be set as
3000 * the holder of the gate. Will panic if the gate is already closed.
3001 * A matching lck_mtx_gate_open() or lck_mtx_gate_handoff() needs to be called later on
3002 * to wake up possible waiters on the gate before returning to userspace.
3005 * Arg1: lck_mtx_t lock used to protect the gate.
3006 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3008 * Conditions: Lock must be held. Returns with the lock held.
3009 * The gate must be open.
3013 lck_mtx_gate_close(__assert_only lck_mtx_t
*lock
, gate_t
*gate
)
3015 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3017 return gate_close(gate
);
3021 * Name: lck_mtx_gate_open
3023 * Description: Opens of the gate and wakes up possible waiters.
3026 * Arg1: lck_mtx_t lock used to protect the gate.
3027 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3029 * Conditions: Lock must be held. Returns with the lock held.
3030 * The current thread must be the holder of the gate.
3034 lck_mtx_gate_open(__assert_only lck_mtx_t
*lock
, gate_t
*gate
)
3036 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3042 * Name: lck_mtx_gate_handoff
3044 * Description: Set the current ownership of the gate. The waiter with highest sched
3045 * priority will be selected as the new holder of the gate, and woken up,
3046 * with the gate remaining in the closed state throughout.
3047 * If no waiters are present, the gate will be kept closed and KERN_NOT_WAITING
3049 * OPEN_ON_FAILURE flag can be used to specify if the gate should be opened in
3050 * case no waiters were found.
3054 * Arg1: lck_mtx_t lock used to protect the gate.
3055 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3056 * Arg3: flags - GATE_NO_FALGS or OPEN_ON_FAILURE
3058 * Conditions: Lock must be held. Returns with the lock held.
3059 * The current thread must be the holder of the gate.
3062 * KERN_SUCCESS in case one of the waiters became the new holder.
3063 * KERN_NOT_WAITING in case there were no waiters.
3067 lck_mtx_gate_handoff(__assert_only lck_mtx_t
*lock
, gate_t
*gate
, int flags
)
3069 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3071 return gate_handoff(gate
, flags
);
3075 * Name: lck_mtx_gate_steal
3077 * Description: Steals the ownership of the gate. It sets the current thread as the
3078 * new holder of the gate.
3079 * A matching lck_mtx_gate_open() or lck_mtx_gate_handoff() needs to be called later on
3080 * to wake up possible waiters on the gate before returning to userspace.
3081 * NOTE: the previous holder should not call lck_mtx_gate_open() or lck_mtx_gate_handoff()
3086 * Arg1: lck_mtx_t lock used to protect the gate.
3087 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3089 * Conditions: Lock must be held. Returns with the lock held.
3090 * The gate must be closed and the current thread must not already be the holder.
3094 lck_mtx_gate_steal(__assert_only lck_mtx_t
*lock
, gate_t
*gate
)
3096 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3102 * Name: lck_mtx_gate_wait
3104 * Description: Waits for the current thread to become the holder of the gate or for the
3105 * gate to become open. An interruptible mode and deadline can be specified
3106 * to return earlier from the wait.
3109 * Arg1: lck_mtx_t lock used to protect the gate.
3110 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3111 * Arg3: sleep action. LCK_SLEEP_DEFAULT, LCK_SLEEP_UNLOCK, LCK_SLEEP_SPIN, LCK_SLEEP_SPIN_ALWAYS.
3112 * Arg3: interruptible flag for wait.
3115 * Conditions: Lock must be held. Returns with the lock held according to the sleep action specified.
3116 * Lock will be dropped while waiting.
3117 * The gate must be closed.
3119 * Returns: Reason why the thread was woken up.
3120 * GATE_HANDOFF - the current thread was handed off the ownership of the gate.
3121 * A matching lck_mtx_gate_open() or lck_mtx_gate_handoff() needs to be called later on
3122 * to wake up possible waiters on the gate before returning to userspace.
3123 * GATE_OPENED - the gate was opened by the holder.
3124 * GATE_TIMED_OUT - the thread was woken up by a timeout.
3125 * GATE_INTERRUPTED - the thread was interrupted while sleeping.
3129 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
)
3131 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3133 if (lck_sleep_action
& LCK_SLEEP_UNLOCK
) {
3134 return gate_wait(gate
,
3137 ^{lck_mtx_unlock(lock
);},
3139 } else if (lck_sleep_action
& LCK_SLEEP_SPIN
) {
3140 return gate_wait(gate
,
3143 ^{lck_mtx_unlock(lock
);},
3144 ^{lck_mtx_lock_spin(lock
);});
3145 } else if (lck_sleep_action
& LCK_SLEEP_SPIN_ALWAYS
) {
3146 return gate_wait(gate
,
3149 ^{lck_mtx_unlock(lock
);},
3150 ^{lck_mtx_lock_spin_always(lock
);});
3152 return gate_wait(gate
,
3155 ^{lck_mtx_unlock(lock
);},
3156 ^{lck_mtx_lock(lock
);});
3161 * Name: lck_mtx_gate_assert
3163 * Description: asserts that the gate is in the specified state.
3166 * Arg1: lck_mtx_t lock used to protect the gate.
3167 * Arg2: pointer to the gate data declared with decl_lck_mtx_gate_data.
3168 * Arg3: flags to specified assert type.
3169 * GATE_ASSERT_CLOSED - the gate is currently closed
3170 * GATE_ASSERT_OPEN - the gate is currently opened
3171 * GATE_ASSERT_HELD - the gate is currently closed and the current thread is the holder
3174 lck_mtx_gate_assert(__assert_only lck_mtx_t
*lock
, gate_t
*gate
, int flags
)
3176 LCK_MTX_ASSERT(lock
, LCK_MTX_ASSERT_OWNED
);
3178 gate_assert(gate
, flags
);
3181 #pragma mark - LCK_*_DECLARE support
3185 lck_grp_attr_startup_init(struct lck_grp_attr_startup_spec
*sp
)
3187 lck_grp_attr_t
*attr
= sp
->grp_attr
;
3188 lck_grp_attr_setdefault(attr
);
3189 attr
->grp_attr_val
|= sp
->grp_attr_set_flags
;
3190 attr
->grp_attr_val
&= ~sp
->grp_attr_clear_flags
;
3195 lck_grp_startup_init(struct lck_grp_startup_spec
*sp
)
3197 lck_grp_init(sp
->grp
, sp
->grp_name
, sp
->grp_attr
);
3202 lck_attr_startup_init(struct lck_attr_startup_spec
*sp
)
3204 lck_attr_t
*attr
= sp
->lck_attr
;
3205 lck_attr_setdefault(attr
);
3206 attr
->lck_attr_val
|= sp
->lck_attr_set_flags
;
3207 attr
->lck_attr_val
&= ~sp
->lck_attr_clear_flags
;
3212 lck_spin_startup_init(struct lck_spin_startup_spec
*sp
)
3214 lck_spin_init(sp
->lck
, sp
->lck_grp
, sp
->lck_attr
);
3219 lck_mtx_startup_init(struct lck_mtx_startup_spec
*sp
)
3222 lck_mtx_init_ext(sp
->lck
, sp
->lck_ext
, sp
->lck_grp
, sp
->lck_attr
);
3224 lck_mtx_init(sp
->lck
, sp
->lck_grp
, sp
->lck_attr
);
3230 lck_rw_startup_init(struct lck_rw_startup_spec
*sp
)
3232 lck_rw_init(sp
->lck
, sp
->lck_grp
, sp
->lck_attr
);
3237 usimple_lock_startup_init(struct usimple_lock_startup_spec
*sp
)
3239 simple_lock_init(sp
->lck
, sp
->lck_init_arg
);