]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/locks.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / kern / locks.c
CommitLineData
91447636 1/*
cb323159 2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
91447636 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
0a7de745 31/*
91447636
A
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
0a7de745 35 *
91447636
A
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.
0a7de745 41 *
91447636
A
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.
0a7de745 45 *
91447636 46 * Carnegie Mellon requests users of this software to return to
0a7de745 47 *
91447636
A
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
0a7de745 52 *
91447636
A
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
39037602 56
39037602
A
57#define LOCK_PRIVATE 1
58
91447636
A
59#include <mach_ldebug.h>
60#include <debug.h>
61
62#include <mach/kern_return.h>
63#include <mach/mach_host_server.h>
64#include <mach_debug/lockgroup_info.h>
65
0a7de745 66#include <kern/lock_stat.h>
91447636
A
67#include <kern/locks.h>
68#include <kern/misc_protos.h>
f427ee49 69#include <kern/zalloc.h>
91447636
A
70#include <kern/thread.h>
71#include <kern/processor.h>
72#include <kern/sched_prim.h>
73#include <kern/debug.h>
d9a64523 74#include <libkern/section_keywords.h>
39037602
A
75#include <machine/atomic.h>
76#include <machine/machine_cpu.h>
91447636
A
77#include <string.h>
78
91447636
A
79#include <sys/kdebug.h>
80
0a7de745
A
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
91447636 85
39037602 86#if MACH_LDEBUG
0a7de745 87#define ALIGN_TEST(p, t) do{if((uintptr_t)p&(sizeof(t)-1)) __builtin_trap();}while(0)
39037602 88#else
0a7de745 89#define ALIGN_TEST(p, t) do{}while(0)
39037602
A
90#endif
91
0a7de745 92#define NOINLINE __attribute__((noinline))
39037602 93
cb323159
A
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)
96
39037602 97
0a7de745
A
98queue_head_t lck_grp_queue;
99unsigned int lck_grp_cnt;
91447636 100
cb323159 101decl_lck_mtx_data(, lck_grp_lock);
b0d623f7 102static lck_mtx_ext_t lck_grp_lock_ext;
91447636 103
d9a64523
A
104SECURITY_READ_ONLY_LATE(boolean_t) spinlock_timeout_panic = TRUE;
105
f427ee49
A
106/* Obtain "lcks" options:this currently controls lock statistics */
107TUNABLE(uint32_t, LcksOpts, "lcks", 0);
108
109ZONE_VIEW_DEFINE(ZV_LCK_GRP_ATTR, "lck_grp_attr",
110 KHEAP_ID_DEFAULT, sizeof(lck_grp_attr_t));
111
112ZONE_VIEW_DEFINE(ZV_LCK_GRP, "lck_grp",
113 KHEAP_ID_DEFAULT, sizeof(lck_grp_t));
114
115ZONE_VIEW_DEFINE(ZV_LCK_ATTR, "lck_attr",
116 KHEAP_ID_DEFAULT, sizeof(lck_attr_t));
117
0a7de745 118lck_grp_attr_t LockDefaultGroupAttr;
f427ee49
A
119lck_grp_t LockCompatGroup;
120lck_attr_t LockDefaultLckAttr;
91447636 121
f427ee49 122#if CONFIG_DTRACE
5ba3f43e
A
123#if defined (__x86_64__)
124uint64_t dtrace_spin_threshold = 500; // 500ns
125#elif defined(__arm__) || defined(__arm64__)
126uint64_t dtrace_spin_threshold = LOCK_PANIC_TIMEOUT / 1000000; // 500ns
127#endif
128#endif
129
d9a64523 130uintptr_t
0a7de745
A
131unslide_for_kdebug(void* object)
132{
133 if (__improbable(kdebug_enable)) {
d9a64523 134 return VM_KERNEL_UNSLIDE_OR_PERM(object);
0a7de745 135 } else {
d9a64523 136 return 0;
0a7de745 137 }
d9a64523
A
138}
139
f427ee49
A
140__startup_func
141static void
142lck_mod_init(void)
91447636
A
143{
144 queue_init(&lck_grp_queue);
0a7de745
A
145
146 /*
b0d623f7
A
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.
149 */
0a7de745 150
b0d623f7
A
151 bzero(&LockCompatGroup, sizeof(lck_grp_t));
152 (void) strncpy(LockCompatGroup.lck_grp_name, "Compatibility APIs", LCK_GRP_MAX_NAME);
0a7de745
A
153
154 LockCompatGroup.lck_grp_attr = LCK_ATTR_NONE;
f427ee49 155
0a7de745
A
156 if (LcksOpts & enaLkStat) {
157 LockCompatGroup.lck_grp_attr |= LCK_GRP_ATTR_STAT;
158 }
159 if (LcksOpts & enaLkTimeStat) {
160 LockCompatGroup.lck_grp_attr |= LCK_GRP_ATTR_TIME_STAT;
161 }
162
cb323159 163 os_ref_init(&LockCompatGroup.lck_grp_refcnt, NULL);
0a7de745 164
b0d623f7
A
165 enqueue_tail(&lck_grp_queue, (queue_entry_t)&LockCompatGroup);
166 lck_grp_cnt = 1;
0a7de745 167
b0d623f7 168 lck_grp_attr_setdefault(&LockDefaultGroupAttr);
91447636 169 lck_attr_setdefault(&LockDefaultLckAttr);
0a7de745 170
b0d623f7 171 lck_mtx_init_ext(&lck_grp_lock, &lck_grp_lock_ext, &LockCompatGroup, &LockDefaultLckAttr);
91447636 172}
f427ee49 173STARTUP(LOCKS_EARLY, STARTUP_RANK_FIRST, lck_mod_init);
91447636
A
174
175/*
176 * Routine: lck_grp_attr_alloc_init
177 */
178
0a7de745 179lck_grp_attr_t *
91447636
A
180lck_grp_attr_alloc_init(
181 void)
182{
0a7de745 183 lck_grp_attr_t *attr;
91447636 184
f427ee49
A
185 attr = zalloc(ZV_LCK_GRP_ATTR);
186 lck_grp_attr_setdefault(attr);
0a7de745 187 return attr;
91447636
A
188}
189
190
191/*
192 * Routine: lck_grp_attr_setdefault
193 */
194
195void
196lck_grp_attr_setdefault(
0a7de745 197 lck_grp_attr_t *attr)
91447636 198{
0a7de745 199 if (LcksOpts & enaLkStat) {
91447636 200 attr->grp_attr_val = LCK_GRP_ATTR_STAT;
0a7de745 201 } else {
91447636 202 attr->grp_attr_val = 0;
0a7de745 203 }
91447636
A
204}
205
206
207/*
0a7de745 208 * Routine: lck_grp_attr_setstat
91447636
A
209 */
210
211void
212lck_grp_attr_setstat(
0a7de745 213 lck_grp_attr_t *attr)
91447636 214{
f427ee49 215#pragma unused(attr)
cb323159 216 os_atomic_or(&attr->grp_attr_val, LCK_GRP_ATTR_STAT, relaxed);
91447636
A
217}
218
219
220/*
0a7de745 221 * Routine: lck_grp_attr_free
91447636
A
222 */
223
224void
225lck_grp_attr_free(
0a7de745 226 lck_grp_attr_t *attr)
91447636 227{
f427ee49 228 zfree(ZV_LCK_GRP_ATTR, attr);
91447636
A
229}
230
231
232/*
3e170ce0 233 * Routine: lck_grp_alloc_init
91447636
A
234 */
235
236lck_grp_t *
237lck_grp_alloc_init(
0a7de745
A
238 const char* grp_name,
239 lck_grp_attr_t *attr)
91447636 240{
0a7de745 241 lck_grp_t *grp;
91447636 242
f427ee49
A
243 grp = zalloc(ZV_LCK_GRP);
244 lck_grp_init(grp, grp_name, attr);
0a7de745 245 return grp;
91447636
A
246}
247
91447636 248/*
3e170ce0 249 * Routine: lck_grp_init
91447636
A
250 */
251
252void
3e170ce0 253lck_grp_init(lck_grp_t * grp, const char * grp_name, lck_grp_attr_t * attr)
91447636 254{
39037602
A
255 /* make sure locking infrastructure has been initialized */
256 assert(lck_grp_cnt > 0);
257
91447636
A
258 bzero((void *)grp, sizeof(lck_grp_t));
259
3e170ce0 260 (void)strlcpy(grp->lck_grp_name, grp_name, LCK_GRP_MAX_NAME);
91447636 261
0a7de745 262 if (attr != LCK_GRP_ATTR_NULL) {
91447636 263 grp->lck_grp_attr = attr->grp_attr_val;
0a7de745
A
264 } else {
265 grp->lck_grp_attr = 0;
266 if (LcksOpts & enaLkStat) {
267 grp->lck_grp_attr |= LCK_GRP_ATTR_STAT;
268 }
269 if (LcksOpts & enaLkTimeStat) {
270 grp->lck_grp_attr |= LCK_GRP_ATTR_TIME_STAT;
271 }
272 }
273
274 if (grp->lck_grp_attr & LCK_GRP_ATTR_STAT) {
275 lck_grp_stats_t *stats = &grp->lck_grp_stats;
276
277#if LOCK_STATS
278 lck_grp_stat_enable(&stats->lgss_spin_held);
279 lck_grp_stat_enable(&stats->lgss_spin_miss);
280#endif /* LOCK_STATS */
281
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);
f427ee49 285 lck_grp_stat_enable(&stats->lgss_mtx_wait);
0a7de745 286 }
f427ee49 287 if (grp->lck_grp_attr & LCK_GRP_ATTR_TIME_STAT) {
0a7de745
A
288#if LOCK_STATS
289 lck_grp_stats_t *stats = &grp->lck_grp_stats;
290 lck_grp_stat_enable(&stats->lgss_spin_spin);
291#endif /* LOCK_STATS */
292 }
91447636 293
cb323159 294 os_ref_init(&grp->lck_grp_refcnt, NULL);
91447636 295
b0d623f7 296 lck_mtx_lock(&lck_grp_lock);
91447636
A
297 enqueue_tail(&lck_grp_queue, (queue_entry_t)grp);
298 lck_grp_cnt++;
b0d623f7 299 lck_mtx_unlock(&lck_grp_lock);
91447636
A
300}
301
91447636 302/*
0a7de745 303 * Routine: lck_grp_free
91447636
A
304 */
305
306void
307lck_grp_free(
0a7de745 308 lck_grp_t *grp)
91447636 309{
b0d623f7 310 lck_mtx_lock(&lck_grp_lock);
91447636
A
311 lck_grp_cnt--;
312 (void)remque((queue_entry_t)grp);
b0d623f7 313 lck_mtx_unlock(&lck_grp_lock);
91447636
A
314 lck_grp_deallocate(grp);
315}
316
317
318/*
0a7de745 319 * Routine: lck_grp_reference
91447636
A
320 */
321
322void
323lck_grp_reference(
0a7de745 324 lck_grp_t *grp)
91447636 325{
cb323159 326 os_ref_retain(&grp->lck_grp_refcnt);
91447636
A
327}
328
329
330/*
0a7de745 331 * Routine: lck_grp_deallocate
91447636
A
332 */
333
334void
335lck_grp_deallocate(
0a7de745 336 lck_grp_t *grp)
91447636 337{
cb323159
A
338 if (os_ref_release(&grp->lck_grp_refcnt) != 0) {
339 return;
0a7de745 340 }
cb323159 341
f427ee49 342 zfree(ZV_LCK_GRP, grp);
91447636
A
343}
344
345/*
346 * Routine: lck_grp_lckcnt_incr
347 */
348
349void
350lck_grp_lckcnt_incr(
0a7de745
A
351 lck_grp_t *grp,
352 lck_type_t lck_type)
91447636 353{
0a7de745 354 unsigned int *lckcnt;
91447636
A
355
356 switch (lck_type) {
357 case LCK_TYPE_SPIN:
358 lckcnt = &grp->lck_grp_spincnt;
359 break;
360 case LCK_TYPE_MTX:
361 lckcnt = &grp->lck_grp_mtxcnt;
362 break;
363 case LCK_TYPE_RW:
364 lckcnt = &grp->lck_grp_rwcnt;
365 break;
f427ee49
A
366 case LCK_TYPE_TICKET:
367 lckcnt = &grp->lck_grp_ticketcnt;
368 break;
91447636
A
369 default:
370 return panic("lck_grp_lckcnt_incr(): invalid lock type: %d\n", lck_type);
371 }
372
cb323159 373 os_atomic_inc(lckcnt, relaxed);
91447636
A
374}
375
376/*
377 * Routine: lck_grp_lckcnt_decr
378 */
379
380void
381lck_grp_lckcnt_decr(
0a7de745
A
382 lck_grp_t *grp,
383 lck_type_t lck_type)
91447636 384{
0a7de745
A
385 unsigned int *lckcnt;
386 int updated;
91447636
A
387
388 switch (lck_type) {
389 case LCK_TYPE_SPIN:
390 lckcnt = &grp->lck_grp_spincnt;
391 break;
392 case LCK_TYPE_MTX:
393 lckcnt = &grp->lck_grp_mtxcnt;
394 break;
395 case LCK_TYPE_RW:
396 lckcnt = &grp->lck_grp_rwcnt;
397 break;
f427ee49
A
398 case LCK_TYPE_TICKET:
399 lckcnt = &grp->lck_grp_ticketcnt;
400 break;
91447636 401 default:
39037602
A
402 panic("lck_grp_lckcnt_decr(): invalid lock type: %d\n", lck_type);
403 return;
91447636
A
404 }
405
cb323159 406 updated = os_atomic_dec(lckcnt, relaxed);
39037602 407 assert(updated >= 0);
91447636
A
408}
409
410/*
411 * Routine: lck_attr_alloc_init
412 */
413
414lck_attr_t *
415lck_attr_alloc_init(
416 void)
417{
0a7de745 418 lck_attr_t *attr;
91447636 419
f427ee49
A
420 attr = zalloc(ZV_LCK_ATTR);
421 lck_attr_setdefault(attr);
0a7de745 422 return attr;
91447636
A
423}
424
425
426/*
427 * Routine: lck_attr_setdefault
428 */
429
430void
431lck_attr_setdefault(
0a7de745 432 lck_attr_t *attr)
91447636 433{
5ba3f43e
A
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__
91447636 438#if !DEBUG
0a7de745
A
439 if (LcksOpts & enaLkDeb) {
440 attr->lck_attr_val = LCK_ATTR_DEBUG;
441 } else {
442 attr->lck_attr_val = LCK_ATTR_NONE;
443 }
91447636 444#else
0a7de745
A
445 attr->lck_attr_val = LCK_ATTR_DEBUG;
446#endif /* !DEBUG */
316670eb
A
447#else
448#error Unknown architecture.
0a7de745 449#endif /* __arm__ */
91447636
A
450}
451
452
453/*
454 * Routine: lck_attr_setdebug
455 */
456void
457lck_attr_setdebug(
0a7de745 458 lck_attr_t *attr)
91447636 459{
cb323159 460 os_atomic_or(&attr->lck_attr_val, LCK_ATTR_DEBUG, relaxed);
2d21ac55
A
461}
462
463/*
464 * Routine: lck_attr_setdebug
465 */
466void
467lck_attr_cleardebug(
0a7de745 468 lck_attr_t *attr)
2d21ac55 469{
cb323159 470 os_atomic_andnot(&attr->lck_attr_val, LCK_ATTR_DEBUG, relaxed);
91447636
A
471}
472
473
0c530ab8
A
474/*
475 * Routine: lck_attr_rw_shared_priority
476 */
477void
478lck_attr_rw_shared_priority(
0a7de745 479 lck_attr_t *attr)
0c530ab8 480{
cb323159 481 os_atomic_or(&attr->lck_attr_val, LCK_ATTR_RW_SHARED_PRIORITY, relaxed);
0c530ab8
A
482}
483
484
91447636
A
485/*
486 * Routine: lck_attr_free
487 */
488void
489lck_attr_free(
0a7de745 490 lck_attr_t *attr)
91447636 491{
f427ee49 492 zfree(ZV_LCK_ATTR, attr);
91447636
A
493}
494
39037602
A
495/*
496 * Routine: hw_lock_init
497 *
498 * Initialize a hardware lock.
499 */
c3c9b80d 500MARK_AS_HIBERNATE_TEXT void
39037602
A
501hw_lock_init(hw_lock_t lock)
502{
503 ordered_store_hw(lock, 0);
504}
505
cb323159
A
506static inline bool
507hw_lock_trylock_contended(hw_lock_t lock, uintptr_t newval)
508{
509#if OS_ATOMIC_USE_LLSC
510 uintptr_t oldval;
511 os_atomic_rmw_loop(&lock->lock_data, oldval, newval, acquire, {
512 if (oldval != 0) {
513 wait_for_event(); // clears the monitor so we don't need give_up()
514 return false;
515 }
516 });
517 return true;
518#else // !OS_ATOMIC_USE_LLSC
519#if OS_ATOMIC_HAS_LLSC
520 uintptr_t oldval = os_atomic_load_exclusive(&lock->lock_data, relaxed);
521 if (oldval != 0) {
522 wait_for_event(); // clears the monitor so we don't need give_up()
523 return false;
524 }
525#endif // OS_ATOMIC_HAS_LLSC
526 return os_atomic_cmpxchg(&lock->lock_data, 0, newval, acquire);
527#endif // !OS_ATOMIC_USE_LLSC
528}
529
39037602
A
530/*
531 * Routine: hw_lock_lock_contended
532 *
533 * Spin until lock is acquired or timeout expires.
5ba3f43e
A
534 * timeout is in mach_absolute_time ticks. Called with
535 * preemption disabled.
39037602 536 */
39037602 537static unsigned int NOINLINE
0a7de745 538hw_lock_lock_contended(hw_lock_t lock, uintptr_t data, uint64_t timeout, boolean_t do_panic LCK_GRP_ARG(lck_grp_t *grp))
39037602 539{
0a7de745
A
540 uint64_t end = 0;
541 uintptr_t holder = lock->lock_data;
542 int i;
39037602 543
0a7de745 544 if (timeout == 0) {
39037602 545 timeout = LOCK_PANIC_TIMEOUT;
0a7de745
A
546 }
547#if CONFIG_DTRACE || LOCK_STATS
548 uint64_t begin = 0;
549 boolean_t stat_enabled = lck_grp_spin_spin_enabled(lock LCK_GRP_ARG(grp));
550#endif /* CONFIG_DTRACE || LOCK_STATS */
551
552#if LOCK_STATS || CONFIG_DTRACE
553 if (__improbable(stat_enabled)) {
5ba3f43e 554 begin = mach_absolute_time();
0a7de745
A
555 }
556#endif /* LOCK_STATS || CONFIG_DTRACE */
557 for (;;) {
39037602 558 for (i = 0; i < LOCK_SNOOP_SPINS; i++) {
39037602
A
559 cpu_pause();
560#if (!__ARM_ENABLE_WFE_) || (LOCK_PRETEST)
561 holder = ordered_load_hw(lock);
0a7de745 562 if (holder != 0) {
39037602 563 continue;
0a7de745 564 }
39037602 565#endif
cb323159 566 if (hw_lock_trylock_contended(lock, data)) {
0a7de745
A
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);
5ba3f43e 570 }
0a7de745
A
571 lck_grp_spin_update_miss(lock LCK_GRP_ARG(grp));
572#endif /* CONFIG_DTRACE || LOCK_STATS */
39037602 573 return 1;
5ba3f43e 574 }
39037602 575 }
5ba3f43e 576 if (end == 0) {
39037602 577 end = ml_get_timebase() + timeout;
0a7de745 578 } else if (ml_get_timebase() >= end) {
39037602 579 break;
0a7de745 580 }
39037602
A
581 }
582 if (do_panic) {
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",
0a7de745 586 (ml_get_timebase() - end + timeout), lock, holder);
39037602
A
587 }
588 return 0;
589}
39037602 590
cb323159
A
591void *
592hw_wait_while_equals(void **address, void *current)
593{
cb323159
A
594 void *v;
595 uint64_t end = 0;
596
597 for (;;) {
598 for (int i = 0; i < LOCK_SNOOP_SPINS; i++) {
599 cpu_pause();
600#if OS_ATOMIC_HAS_LLSC
601 v = os_atomic_load_exclusive(address, relaxed);
602 if (__probable(v != current)) {
603 os_atomic_clear_exclusive();
604 return v;
605 }
606 wait_for_event();
607#else
608 v = os_atomic_load(address, relaxed);
609 if (__probable(v != current)) {
610 return v;
611 }
612#endif // OS_ATOMIC_HAS_LLSC
613 }
614 if (end == 0) {
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);
618 }
619 }
cb323159
A
620}
621
d9a64523 622static inline void
0a7de745 623hw_lock_lock_internal(hw_lock_t lock, thread_t thread LCK_GRP_ARG(lck_grp_t *grp))
39037602 624{
0a7de745 625 uintptr_t state;
39037602 626
39037602 627 state = LCK_MTX_THREAD_TO_STATE(thread) | PLATFORM_LCK_ILOCK;
0a7de745
A
628#if LOCK_PRETEST
629 if (ordered_load_hw(lock)) {
39037602 630 goto contended;
0a7de745
A
631 }
632#endif // LOCK_PRETEST
cb323159 633 if (hw_lock_trylock_contended(lock, state)) {
5ba3f43e
A
634 goto end;
635 }
0a7de745 636#if LOCK_PRETEST
39037602 637contended:
0a7de745
A
638#endif // LOCK_PRETEST
639 hw_lock_lock_contended(lock, state, 0, spinlock_timeout_panic LCK_GRP_ARG(grp));
5ba3f43e 640end:
0a7de745
A
641 lck_grp_spin_update_held(lock LCK_GRP_ARG(grp));
642
39037602
A
643 return;
644}
645
d9a64523
A
646/*
647 * Routine: hw_lock_lock
648 *
649 * Acquire lock, spinning until it becomes available,
650 * return with preemption disabled.
651 */
652void
0a7de745 653(hw_lock_lock)(hw_lock_t lock LCK_GRP_ARG(lck_grp_t *grp))
d9a64523
A
654{
655 thread_t thread = current_thread();
656 disable_preemption_for_thread(thread);
0a7de745 657 hw_lock_lock_internal(lock, thread LCK_GRP_ARG(grp));
d9a64523
A
658}
659
660/*
661 * Routine: hw_lock_lock_nopreempt
662 *
663 * Acquire lock, spinning until it becomes available.
664 */
665void
0a7de745 666(hw_lock_lock_nopreempt)(hw_lock_t lock LCK_GRP_ARG(lck_grp_t *grp))
d9a64523
A
667{
668 thread_t thread = current_thread();
0a7de745 669 if (__improbable(!preemption_disabled_for_thread(thread))) {
d9a64523 670 panic("Attempt to take no-preempt spinlock %p in preemptible context", lock);
0a7de745
A
671 }
672 hw_lock_lock_internal(lock, thread LCK_GRP_ARG(grp));
d9a64523
A
673}
674
c3c9b80d
A
675static inline unsigned int
676hw_lock_to_internal(hw_lock_t lock, uint64_t timeout, thread_t thread
677 LCK_GRP_ARG(lck_grp_t *grp))
39037602 678{
c3c9b80d 679 uintptr_t state;
5ba3f43e 680 unsigned int success = 0;
39037602 681
39037602 682 state = LCK_MTX_THREAD_TO_STATE(thread) | PLATFORM_LCK_ILOCK;
0a7de745
A
683#if LOCK_PRETEST
684 if (ordered_load_hw(lock)) {
39037602 685 goto contended;
0a7de745
A
686 }
687#endif // LOCK_PRETEST
cb323159 688 if (hw_lock_trylock_contended(lock, state)) {
5ba3f43e
A
689 success = 1;
690 goto end;
691 }
0a7de745 692#if LOCK_PRETEST
39037602 693contended:
0a7de745
A
694#endif // LOCK_PRETEST
695 success = hw_lock_lock_contended(lock, state, timeout, FALSE LCK_GRP_ARG(grp));
5ba3f43e 696end:
0a7de745
A
697 if (success) {
698 lck_grp_spin_update_held(lock LCK_GRP_ARG(grp));
699 }
5ba3f43e 700 return success;
39037602
A
701}
702
c3c9b80d
A
703/*
704 * Routine: hw_lock_to
705 *
706 * Acquire lock, spinning until it becomes available or timeout.
707 * Timeout is in mach_absolute_time ticks, return with
708 * preemption disabled.
709 */
710unsigned
711int
712(hw_lock_to)(hw_lock_t lock, uint64_t timeout LCK_GRP_ARG(lck_grp_t *grp))
713{
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));
717}
718
719/*
720 * Routine: hw_lock_to_nopreempt
721 *
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.
725 */
726unsigned
727int
728(hw_lock_to_nopreempt)(hw_lock_t lock, uint64_t timeout LCK_GRP_ARG(lck_grp_t *grp))
729{
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);
733 }
734 return hw_lock_to_internal(lock, timeout, thread LCK_GRP_ARG(grp));
735}
736
39037602
A
737/*
738 * Routine: hw_lock_try
5ba3f43e
A
739 *
740 * returns with preemption disabled on success.
39037602 741 */
d9a64523 742static inline unsigned int
0a7de745 743hw_lock_try_internal(hw_lock_t lock, thread_t thread LCK_GRP_ARG(lck_grp_t *grp))
39037602 744{
0a7de745 745 int success = 0;
39037602 746
0a7de745
A
747#if LOCK_PRETEST
748 if (ordered_load_hw(lock)) {
39037602 749 goto failed;
0a7de745
A
750 }
751#endif // LOCK_PRETEST
cb323159
A
752 success = os_atomic_cmpxchg(&lock->lock_data, 0,
753 LCK_MTX_THREAD_TO_STATE(thread) | PLATFORM_LCK_ILOCK, acquire);
39037602 754
0a7de745 755#if LOCK_PRETEST
39037602 756failed:
0a7de745
A
757#endif // LOCK_PRETEST
758 if (success) {
759 lck_grp_spin_update_held(lock LCK_GRP_ARG(grp));
760 }
39037602
A
761 return success;
762}
763
0a7de745
A
764unsigned
765int
766(hw_lock_try)(hw_lock_t lock LCK_GRP_ARG(lck_grp_t *grp))
d9a64523
A
767{
768 thread_t thread = current_thread();
769 disable_preemption_for_thread(thread);
0a7de745
A
770 unsigned int success = hw_lock_try_internal(lock, thread LCK_GRP_ARG(grp));
771 if (!success) {
d9a64523 772 enable_preemption();
0a7de745 773 }
d9a64523
A
774 return success;
775}
776
0a7de745
A
777unsigned
778int
779(hw_lock_try_nopreempt)(hw_lock_t lock LCK_GRP_ARG(lck_grp_t *grp))
d9a64523
A
780{
781 thread_t thread = current_thread();
0a7de745 782 if (__improbable(!preemption_disabled_for_thread(thread))) {
d9a64523 783 panic("Attempt to test no-preempt spinlock %p in preemptible context", lock);
0a7de745
A
784 }
785 return hw_lock_try_internal(lock, thread LCK_GRP_ARG(grp));
d9a64523
A
786}
787
39037602
A
788/*
789 * Routine: hw_lock_unlock
790 *
5ba3f43e 791 * Unconditionally release lock, release preemption level.
39037602 792 */
d9a64523
A
793static inline void
794hw_lock_unlock_internal(hw_lock_t lock)
39037602 795{
cb323159 796 os_atomic_store(&lock->lock_data, 0, release);
5ba3f43e
A
797#if __arm__ || __arm64__
798 // ARM tests are only for open-source exclusion
799 set_event();
0a7de745
A
800#endif // __arm__ || __arm64__
801#if CONFIG_DTRACE
5ba3f43e
A
802 LOCKSTAT_RECORD(LS_LCK_SPIN_UNLOCK_RELEASE, lock, 0);
803#endif /* CONFIG_DTRACE */
d9a64523
A
804}
805
806void
0a7de745 807(hw_lock_unlock)(hw_lock_t lock)
d9a64523
A
808{
809 hw_lock_unlock_internal(lock);
39037602
A
810 enable_preemption();
811}
812
d9a64523 813void
0a7de745 814(hw_lock_unlock_nopreempt)(hw_lock_t lock)
d9a64523 815{
0a7de745 816 if (__improbable(!preemption_disabled_for_thread(current_thread()))) {
d9a64523 817 panic("Attempt to release no-preempt spinlock %p in preemptible context", lock);
0a7de745 818 }
d9a64523
A
819 hw_lock_unlock_internal(lock);
820}
821
39037602 822/*
5ba3f43e 823 * Routine hw_lock_held, doesn't change preemption state.
39037602
A
824 * N.B. Racy, of course.
825 */
826unsigned int
827hw_lock_held(hw_lock_t lock)
828{
0a7de745 829 return ordered_load_hw(lock) != 0;
39037602 830}
91447636 831
cb323159
A
832static unsigned int
833hw_lock_bit_to_contended(hw_lock_bit_t *lock, uint32_t mask, uint32_t timeout LCK_GRP_ARG(lck_grp_t *grp));
cb323159
A
834
835static inline unsigned int
836hw_lock_bit_to_internal(hw_lock_bit_t *lock, unsigned int bit, uint32_t timeout LCK_GRP_ARG(lck_grp_t *grp))
837{
838 unsigned int success = 0;
839 uint32_t mask = (1 << bit);
cb323159 840
cb323159
A
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));
843 } else {
844 success = 1;
845 }
cb323159
A
846
847 if (success) {
848 lck_grp_spin_update_held(lock LCK_GRP_ARG(grp));
849 }
850
851 return success;
852}
853
854unsigned
855int
856(hw_lock_bit_to)(hw_lock_bit_t * lock, unsigned int bit, uint32_t timeout LCK_GRP_ARG(lck_grp_t *grp))
857{
858 _disable_preemption();
859 return hw_lock_bit_to_internal(lock, bit, timeout LCK_GRP_ARG(grp));
860}
861
cb323159
A
862static unsigned int NOINLINE
863hw_lock_bit_to_contended(hw_lock_bit_t *lock, uint32_t mask, uint32_t timeout LCK_GRP_ARG(lck_grp_t *grp))
864{
865 uint64_t end = 0;
866 int i;
867#if CONFIG_DTRACE || LOCK_STATS
868 uint64_t begin = 0;
869 boolean_t stat_enabled = lck_grp_spin_spin_enabled(lock LCK_GRP_ARG(grp));
870#endif /* CONFIG_DTRACE || LOCK_STATS */
871
872#if LOCK_STATS || CONFIG_DTRACE
873 if (__improbable(stat_enabled)) {
874 begin = mach_absolute_time();
875 }
876#endif /* LOCK_STATS || CONFIG_DTRACE */
877 for (;;) {
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)) {
882 goto end;
883 }
884 }
885 if (end == 0) {
886 end = ml_get_timebase() + timeout;
887 } else if (ml_get_timebase() >= end) {
888 break;
889 }
890 }
891 return 0;
892end:
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);
896 }
897 lck_grp_spin_update_miss(lock LCK_GRP_ARG(grp));
898#endif /* CONFIG_DTRACE || LCK_GRP_STAT */
899
900 return 1;
901}
cb323159
A
902
903void
904(hw_lock_bit)(hw_lock_bit_t * lock, unsigned int bit LCK_GRP_ARG(lck_grp_t *grp))
905{
906 if (hw_lock_bit_to(lock, bit, LOCK_PANIC_TIMEOUT, LCK_GRP_PROBEARG(grp))) {
907 return;
908 }
cb323159 909 panic("hw_lock_bit(): timed out (%p)", lock);
cb323159
A
910}
911
912void
913(hw_lock_bit_nopreempt)(hw_lock_bit_t * lock, unsigned int bit LCK_GRP_ARG(lck_grp_t *grp))
914{
915 if (__improbable(get_preemption_level() == 0)) {
916 panic("Attempt to take no-preempt bitlock %p in preemptible context", lock);
917 }
918 if (hw_lock_bit_to_internal(lock, bit, LOCK_PANIC_TIMEOUT LCK_GRP_ARG(grp))) {
919 return;
920 }
cb323159 921 panic("hw_lock_bit_nopreempt(): timed out (%p)", lock);
cb323159
A
922}
923
924unsigned
925int
926(hw_lock_bit_try)(hw_lock_bit_t * lock, unsigned int bit LCK_GRP_ARG(lck_grp_t *grp))
927{
928 uint32_t mask = (1 << bit);
cb323159
A
929 boolean_t success = FALSE;
930
931 _disable_preemption();
cb323159
A
932 // TODO: consider weak (non-looping) atomic test-and-set
933 success = hw_atomic_test_and_set32(lock, mask, mask, memory_order_acquire, FALSE);
cb323159
A
934 if (!success) {
935 _enable_preemption();
936 }
937
938 if (success) {
939 lck_grp_spin_update_held(lock LCK_GRP_ARG(grp));
940 }
941
942 return success;
943}
944
945static inline void
946hw_unlock_bit_internal(hw_lock_bit_t *lock, unsigned int bit)
947{
948 uint32_t mask = (1 << bit);
cb323159 949
cb323159
A
950 os_atomic_andnot(lock, mask, release);
951#if __arm__
952 set_event();
953#endif
cb323159
A
954#if CONFIG_DTRACE
955 LOCKSTAT_RECORD(LS_LCK_SPIN_UNLOCK_RELEASE, lock, bit);
956#endif
957}
958
959/*
960 * Routine: hw_unlock_bit
961 *
962 * Release spin-lock. The second parameter is the bit number to test and set.
963 * Decrement the preemption level.
964 */
965void
966hw_unlock_bit(hw_lock_bit_t * lock, unsigned int bit)
967{
968 hw_unlock_bit_internal(lock, bit);
969 _enable_preemption();
970}
971
972void
973hw_unlock_bit_nopreempt(hw_lock_bit_t * lock, unsigned int bit)
974{
975 if (__improbable(get_preemption_level() == 0)) {
976 panic("Attempt to release no-preempt bitlock %p in preemptible context", lock);
977 }
978 hw_unlock_bit_internal(lock, bit);
979}
980
91447636
A
981/*
982 * Routine: lck_spin_sleep
983 */
984wait_result_t
0a7de745
A
985lck_spin_sleep_grp(
986 lck_spin_t *lck,
987 lck_sleep_action_t lck_sleep_action,
988 event_t event,
989 wait_interrupt_t interruptible,
990 lck_grp_t *grp)
91447636 991{
0a7de745
A
992 wait_result_t res;
993
994 if ((lck_sleep_action & ~LCK_SLEEP_MASK) != 0) {
91447636 995 panic("Invalid lock sleep action %x\n", lck_sleep_action);
0a7de745 996 }
91447636
A
997
998 res = assert_wait(event, interruptible);
999 if (res == THREAD_WAITING) {
1000 lck_spin_unlock(lck);
1001 res = thread_block(THREAD_CONTINUE_NULL);
0a7de745
A
1002 if (!(lck_sleep_action & LCK_SLEEP_UNLOCK)) {
1003 lck_spin_lock_grp(lck, grp);
1004 }
1005 } else if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
91447636 1006 lck_spin_unlock(lck);
0a7de745 1007 }
91447636
A
1008
1009 return res;
1010}
1011
0a7de745
A
1012wait_result_t
1013lck_spin_sleep(
1014 lck_spin_t *lck,
1015 lck_sleep_action_t lck_sleep_action,
1016 event_t event,
1017 wait_interrupt_t interruptible)
1018{
1019 return lck_spin_sleep_grp(lck, lck_sleep_action, event, interruptible, LCK_GRP_NULL);
1020}
91447636
A
1021
1022/*
1023 * Routine: lck_spin_sleep_deadline
1024 */
1025wait_result_t
1026lck_spin_sleep_deadline(
0a7de745
A
1027 lck_spin_t *lck,
1028 lck_sleep_action_t lck_sleep_action,
1029 event_t event,
1030 wait_interrupt_t interruptible,
1031 uint64_t deadline)
91447636
A
1032{
1033 wait_result_t res;
1034
0a7de745 1035 if ((lck_sleep_action & ~LCK_SLEEP_MASK) != 0) {
91447636 1036 panic("Invalid lock sleep action %x\n", lck_sleep_action);
0a7de745 1037 }
91447636
A
1038
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);
0a7de745 1043 if (!(lck_sleep_action & LCK_SLEEP_UNLOCK)) {
91447636 1044 lck_spin_lock(lck);
0a7de745
A
1045 }
1046 } else if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
91447636 1047 lck_spin_unlock(lck);
0a7de745 1048 }
91447636
A
1049
1050 return res;
1051}
1052
91447636
A
1053/*
1054 * Routine: lck_mtx_sleep
1055 */
1056wait_result_t
1057lck_mtx_sleep(
0a7de745
A
1058 lck_mtx_t *lck,
1059 lck_sleep_action_t lck_sleep_action,
1060 event_t event,
1061 wait_interrupt_t interruptible)
91447636 1062{
0a7de745
A
1063 wait_result_t res;
1064 thread_t thread = current_thread();
1065
91447636 1066 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS, LCK_MTX_SLEEP_CODE) | DBG_FUNC_START,
0a7de745 1067 VM_KERNEL_UNSLIDE_OR_PERM(lck), (int)lck_sleep_action, VM_KERNEL_UNSLIDE_OR_PERM(event), (int)interruptible, 0);
91447636 1068
0a7de745 1069 if ((lck_sleep_action & ~LCK_SLEEP_MASK) != 0) {
91447636 1070 panic("Invalid lock sleep action %x\n", lck_sleep_action);
0a7de745 1071 }
91447636 1072
fe8ab488
A
1073 if (lck_sleep_action & LCK_SLEEP_PROMOTED_PRI) {
1074 /*
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.
1079 */
1080 thread->rwlock_count++;
1081 }
1082
91447636
A
1083 res = assert_wait(event, interruptible);
1084 if (res == THREAD_WAITING) {
1085 lck_mtx_unlock(lck);
1086 res = thread_block(THREAD_CONTINUE_NULL);
b0d623f7 1087 if (!(lck_sleep_action & LCK_SLEEP_UNLOCK)) {
0a7de745 1088 if ((lck_sleep_action & LCK_SLEEP_SPIN)) {
b0d623f7 1089 lck_mtx_lock_spin(lck);
0a7de745 1090 } else if ((lck_sleep_action & LCK_SLEEP_SPIN_ALWAYS)) {
5ba3f43e 1091 lck_mtx_lock_spin_always(lck);
0a7de745 1092 } else {
b0d623f7 1093 lck_mtx_lock(lck);
0a7de745 1094 }
b0d623f7 1095 }
0a7de745 1096 } else if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
91447636 1097 lck_mtx_unlock(lck);
0a7de745 1098 }
91447636 1099
fe8ab488
A
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 */
d9a64523 1103 lck_rw_clear_promotion(thread, unslide_for_kdebug(event));
fe8ab488
A
1104 }
1105 }
1106
91447636
A
1107 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS, LCK_MTX_SLEEP_CODE) | DBG_FUNC_END, (int)res, 0, 0, 0, 0);
1108
1109 return res;
1110}
1111
1112
1113/*
1114 * Routine: lck_mtx_sleep_deadline
1115 */
1116wait_result_t
1117lck_mtx_sleep_deadline(
0a7de745
A
1118 lck_mtx_t *lck,
1119 lck_sleep_action_t lck_sleep_action,
1120 event_t event,
1121 wait_interrupt_t interruptible,
1122 uint64_t deadline)
91447636
A
1123{
1124 wait_result_t res;
0a7de745 1125 thread_t thread = current_thread();
91447636
A
1126
1127 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS, LCK_MTX_SLEEP_DEADLINE_CODE) | DBG_FUNC_START,
0a7de745 1128 VM_KERNEL_UNSLIDE_OR_PERM(lck), (int)lck_sleep_action, VM_KERNEL_UNSLIDE_OR_PERM(event), (int)interruptible, 0);
91447636 1129
0a7de745 1130 if ((lck_sleep_action & ~LCK_SLEEP_MASK) != 0) {
91447636 1131 panic("Invalid lock sleep action %x\n", lck_sleep_action);
0a7de745 1132 }
91447636 1133
fe8ab488
A
1134 if (lck_sleep_action & LCK_SLEEP_PROMOTED_PRI) {
1135 /*
1136 * See lck_mtx_sleep().
1137 */
1138 thread->rwlock_count++;
1139 }
1140
91447636
A
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);
6d2010ae 1145 if (!(lck_sleep_action & LCK_SLEEP_UNLOCK)) {
0a7de745 1146 if ((lck_sleep_action & LCK_SLEEP_SPIN)) {
6d2010ae 1147 lck_mtx_lock_spin(lck);
0a7de745 1148 } else {
6d2010ae 1149 lck_mtx_lock(lck);
0a7de745 1150 }
6d2010ae 1151 }
0a7de745 1152 } else if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
91447636 1153 lck_mtx_unlock(lck);
0a7de745 1154 }
91447636 1155
fe8ab488
A
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 */
d9a64523 1159 lck_rw_clear_promotion(thread, unslide_for_kdebug(event));
fe8ab488
A
1160 }
1161 }
1162
91447636
A
1163 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS, LCK_MTX_SLEEP_DEADLINE_CODE) | DBG_FUNC_END, (int)res, 0, 0, 0, 0);
1164
1165 return res;
1166}
1167
1168/*
d9a64523
A
1169 * Lock Boosting Invariants:
1170 *
1171 * The lock owner is always promoted to the max priority of all its waiters.
1172 * Max priority is capped at MAXPRI_PROMOTE.
1173 *
d9a64523
A
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.
d9a64523
A
1177 */
1178
1179/*
1180 * Routine: lck_mtx_lock_wait
91447636
A
1181 *
1182 * Invoked in order to wait on contention.
1183 *
1184 * Called with the interlock locked and
1185 * returns it unlocked.
d9a64523
A
1186 *
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
1190 *
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
91447636
A
1193 */
1194void
0a7de745
A
1195lck_mtx_lock_wait(
1196 lck_mtx_t *lck,
cb323159
A
1197 thread_t holder,
1198 struct turnstile **ts)
91447636 1199{
cb323159 1200 thread_t thread = current_thread();
0a7de745 1201 lck_mtx_t *mutex;
d9a64523
A
1202 __kdebug_only uintptr_t trace_lck = unslide_for_kdebug(lck);
1203
0a7de745
A
1204#if CONFIG_DTRACE
1205 uint64_t sleep_start = 0;
2d21ac55
A
1206
1207 if (lockstat_probemap[LS_LCK_MTX_LOCK_BLOCK] || lockstat_probemap[LS_LCK_MTX_EXT_LOCK_BLOCK]) {
1208 sleep_start = mach_absolute_time();
1209 }
1210#endif
91447636 1211
0a7de745 1212 if (lck->lck_mtx_tag != LCK_MTX_TAG_INDIRECT) {
91447636 1213 mutex = lck;
0a7de745 1214 } else {
91447636 1215 mutex = &lck->lck_mtx_ptr->lck_mtx;
0a7de745 1216 }
91447636 1217
d9a64523 1218 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS, LCK_MTX_LCK_WAIT_CODE) | DBG_FUNC_START,
0a7de745 1219 trace_lck, (uintptr_t)thread_tid(thread), 0, 0, 0);
d9a64523 1220
cb323159
A
1221 assert(thread->waiting_for_mutex == NULL);
1222 thread->waiting_for_mutex = mutex;
1223 mutex->lck_mtx_waiters++;
91447636 1224
cb323159
A
1225 if (*ts == NULL) {
1226 *ts = turnstile_prepare((uintptr_t)mutex, NULL, TURNSTILE_NULL, TURNSTILE_KERNEL_MUTEX);
0a7de745 1227 }
d9a64523 1228
cb323159
A
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));
91447636 1232
cb323159 1233 waitq_assert_wait64(&turnstile->ts_waitq, CAST_EVENT64_T(LCK_MTX_EVENT(mutex)), THREAD_UNINT | THREAD_WAIT_NOREPORT_USER, TIMEOUT_WAIT_FOREVER);
d9a64523 1234
91447636
A
1235 lck_mtx_ilk_unlock(mutex);
1236
cb323159
A
1237 turnstile_update_inheritor_complete(turnstile, TURNSTILE_INTERLOCK_NOT_HELD);
1238
91447636
A
1239 thread_block(THREAD_CONTINUE_NULL);
1240
cb323159 1241 thread->waiting_for_mutex = NULL;
d9a64523 1242
91447636 1243 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS, LCK_MTX_LCK_WAIT_CODE) | DBG_FUNC_END, 0, 0, 0, 0, 0);
0a7de745 1244#if CONFIG_DTRACE
2d21ac55 1245 /*
5ba3f43e 1246 * Record the DTrace lockstat probe for blocking, block time
2d21ac55
A
1247 * measured from when we were entered.
1248 */
1249 if (sleep_start) {
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);
1253 } else {
1254 LOCKSTAT_RECORD(LS_LCK_MTX_EXT_LOCK_BLOCK, lck,
1255 mach_absolute_time() - sleep_start);
1256 }
1257 }
1258#endif
91447636
A
1259}
1260
1261/*
0a7de745 1262 * Routine: lck_mtx_lock_acquire
91447636
A
1263 *
1264 * Invoked on acquiring the mutex when there is
1265 * contention.
1266 *
1267 * Returns the current number of waiters.
1268 *
1269 * Called with the interlock locked.
1270 */
1271int
1272lck_mtx_lock_acquire(
cb323159
A
1273 lck_mtx_t *lck,
1274 struct turnstile *ts)
91447636 1275{
0a7de745
A
1276 thread_t thread = current_thread();
1277 lck_mtx_t *mutex;
91447636 1278
0a7de745 1279 if (lck->lck_mtx_tag != LCK_MTX_TAG_INDIRECT) {
91447636 1280 mutex = lck;
0a7de745 1281 } else {
91447636 1282 mutex = &lck->lck_mtx_ptr->lck_mtx;
0a7de745 1283 }
91447636 1284
d9a64523
A
1285 assert(thread->waiting_for_mutex == NULL);
1286
1287 if (mutex->lck_mtx_waiters > 0) {
cb323159
A
1288 if (ts == NULL) {
1289 ts = turnstile_prepare((uintptr_t)mutex, NULL, TURNSTILE_NULL, TURNSTILE_KERNEL_MUTEX);
0a7de745 1290 }
d9a64523 1291
cb323159
A
1292 turnstile_update_inheritor(ts, thread, (TURNSTILE_IMMEDIATE_UPDATE | TURNSTILE_INHERITOR_THREAD));
1293 turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_HELD);
1294 }
d9a64523 1295
cb323159
A
1296 if (ts != NULL) {
1297 turnstile_complete((uintptr_t)mutex, NULL, NULL, TURNSTILE_KERNEL_MUTEX);
91447636 1298 }
91447636 1299
0a7de745 1300 return mutex->lck_mtx_waiters;
91447636
A
1301}
1302
1303/*
0a7de745 1304 * Routine: lck_mtx_unlock_wakeup
91447636
A
1305 *
1306 * Invoked on unlock when there is contention.
1307 *
1308 * Called with the interlock locked.
d9a64523 1309 *
cb323159
A
1310 * NOTE: callers should call turnstile_clenup after
1311 * dropping the interlock.
91447636 1312 */
cb323159 1313boolean_t
0a7de745
A
1314lck_mtx_unlock_wakeup(
1315 lck_mtx_t *lck,
1316 thread_t holder)
91447636 1317{
0a7de745
A
1318 thread_t thread = current_thread();
1319 lck_mtx_t *mutex;
d9a64523 1320 __kdebug_only uintptr_t trace_lck = unslide_for_kdebug(lck);
cb323159
A
1321 struct turnstile *ts;
1322 kern_return_t did_wake;
91447636 1323
0a7de745 1324 if (lck->lck_mtx_tag != LCK_MTX_TAG_INDIRECT) {
91447636 1325 mutex = lck;
0a7de745 1326 } else {
91447636 1327 mutex = &lck->lck_mtx_ptr->lck_mtx;
0a7de745 1328 }
91447636 1329
0a7de745 1330 if (thread != holder) {
6d2010ae 1331 panic("lck_mtx_unlock_wakeup: mutex %p holder %p\n", mutex, holder);
0a7de745 1332 }
91447636 1333
d9a64523 1334 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS, LCK_MTX_UNLCK_WAKEUP_CODE) | DBG_FUNC_START,
0a7de745 1335 trace_lck, (uintptr_t)thread_tid(thread), 0, 0, 0);
91447636 1336
6d2010ae 1337 assert(mutex->lck_mtx_waiters > 0);
d9a64523
A
1338 assert(thread->waiting_for_mutex == NULL);
1339
cb323159
A
1340 ts = turnstile_prepare((uintptr_t)mutex, NULL, TURNSTILE_NULL, TURNSTILE_KERNEL_MUTEX);
1341
0a7de745 1342 if (mutex->lck_mtx_waiters > 1) {
cb323159
A
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);
0a7de745 1345 } else {
cb323159
A
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);
0a7de745 1348 }
cb323159 1349 assert(did_wake == KERN_SUCCESS);
91447636 1350
cb323159
A
1351 turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_HELD);
1352 turnstile_complete((uintptr_t)mutex, NULL, NULL, TURNSTILE_KERNEL_MUTEX);
d9a64523 1353
cb323159 1354 mutex->lck_mtx_waiters--;
91447636
A
1355
1356 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS, LCK_MTX_UNLCK_WAKEUP_CODE) | DBG_FUNC_END, 0, 0, 0, 0, 0);
d9a64523 1357
cb323159 1358 return mutex->lck_mtx_waiters > 0;
2d21ac55
A
1359}
1360
91447636 1361/*
0a7de745 1362 * Routine: mutex_pause
91447636
A
1363 *
1364 * Called by former callers of simple_lock_pause().
1365 */
0a7de745
A
1366#define MAX_COLLISION_COUNTS 32
1367#define MAX_COLLISION 8
2d21ac55
A
1368
1369unsigned int max_collision_count[MAX_COLLISION_COUNTS];
1370
1371uint32_t collision_backoffs[MAX_COLLISION] = {
0a7de745 1372 10, 50, 100, 200, 400, 600, 800, 1000
2d21ac55
A
1373};
1374
91447636
A
1375
1376void
2d21ac55 1377mutex_pause(uint32_t collisions)
91447636
A
1378{
1379 wait_result_t wait_result;
0a7de745 1380 uint32_t back_off;
91447636 1381
0a7de745
A
1382 if (collisions >= MAX_COLLISION_COUNTS) {
1383 collisions = MAX_COLLISION_COUNTS - 1;
1384 }
2d21ac55
A
1385 max_collision_count[collisions]++;
1386
0a7de745
A
1387 if (collisions >= MAX_COLLISION) {
1388 collisions = MAX_COLLISION - 1;
1389 }
2d21ac55
A
1390 back_off = collision_backoffs[collisions];
1391
1392 wait_result = assert_wait_timeout((event_t)mutex_pause, THREAD_UNINT, back_off, NSEC_PER_USEC);
91447636
A
1393 assert(wait_result == THREAD_WAITING);
1394
1395 wait_result = thread_block(THREAD_CONTINUE_NULL);
1396 assert(wait_result == THREAD_TIMED_OUT);
1397}
1398
2d21ac55
A
1399
1400unsigned int mutex_yield_wait = 0;
1401unsigned int mutex_yield_no_wait = 0;
1402
1403void
b0d623f7 1404lck_mtx_yield(
0a7de745 1405 lck_mtx_t *lck)
2d21ac55 1406{
0a7de745
A
1407 int waiters;
1408
2d21ac55 1409#if DEBUG
b0d623f7 1410 lck_mtx_assert(lck, LCK_MTX_ASSERT_OWNED);
2d21ac55 1411#endif /* DEBUG */
0a7de745
A
1412
1413 if (lck->lck_mtx_tag == LCK_MTX_TAG_INDIRECT) {
1414 waiters = lck->lck_mtx_ptr->lck_mtx.lck_mtx_waiters;
1415 } else {
1416 waiters = lck->lck_mtx_waiters;
1417 }
1418
1419 if (!waiters) {
1420 mutex_yield_no_wait++;
2d21ac55 1421 } else {
0a7de745 1422 mutex_yield_wait++;
b0d623f7 1423 lck_mtx_unlock(lck);
2d21ac55 1424 mutex_pause(0);
b0d623f7 1425 lck_mtx_lock(lck);
2d21ac55
A
1426 }
1427}
1428
1429
91447636
A
1430/*
1431 * Routine: lck_rw_sleep
1432 */
1433wait_result_t
1434lck_rw_sleep(
0a7de745
A
1435 lck_rw_t *lck,
1436 lck_sleep_action_t lck_sleep_action,
1437 event_t event,
1438 wait_interrupt_t interruptible)
91447636 1439{
0a7de745
A
1440 wait_result_t res;
1441 lck_rw_type_t lck_rw_type;
1442 thread_t thread = current_thread();
fe8ab488 1443
0a7de745 1444 if ((lck_sleep_action & ~LCK_SLEEP_MASK) != 0) {
91447636 1445 panic("Invalid lock sleep action %x\n", lck_sleep_action);
0a7de745 1446 }
91447636 1447
fe8ab488
A
1448 if (lck_sleep_action & LCK_SLEEP_PROMOTED_PRI) {
1449 /*
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.
1456 */
1457 thread->rwlock_count++;
1458 }
1459
91447636
A
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)) {
0a7de745 1465 if (!(lck_sleep_action & (LCK_SLEEP_SHARED | LCK_SLEEP_EXCLUSIVE))) {
91447636 1466 lck_rw_lock(lck, lck_rw_type);
0a7de745 1467 } else if (lck_sleep_action & LCK_SLEEP_EXCLUSIVE) {
91447636 1468 lck_rw_lock_exclusive(lck);
0a7de745 1469 } else {
91447636 1470 lck_rw_lock_shared(lck);
0a7de745 1471 }
91447636 1472 }
0a7de745 1473 } else if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
91447636 1474 (void)lck_rw_done(lck);
0a7de745 1475 }
91447636 1476
fe8ab488
A
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 */
1480
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);
1483
d9a64523 1484 lck_rw_clear_promotion(thread, unslide_for_kdebug(event));
fe8ab488
A
1485 }
1486 }
1487
91447636
A
1488 return res;
1489}
1490
1491
1492/*
1493 * Routine: lck_rw_sleep_deadline
1494 */
1495wait_result_t
1496lck_rw_sleep_deadline(
0a7de745
A
1497 lck_rw_t *lck,
1498 lck_sleep_action_t lck_sleep_action,
1499 event_t event,
1500 wait_interrupt_t interruptible,
1501 uint64_t deadline)
91447636
A
1502{
1503 wait_result_t res;
0a7de745
A
1504 lck_rw_type_t lck_rw_type;
1505 thread_t thread = current_thread();
91447636 1506
0a7de745 1507 if ((lck_sleep_action & ~LCK_SLEEP_MASK) != 0) {
91447636 1508 panic("Invalid lock sleep action %x\n", lck_sleep_action);
0a7de745 1509 }
91447636 1510
fe8ab488
A
1511 if (lck_sleep_action & LCK_SLEEP_PROMOTED_PRI) {
1512 thread->rwlock_count++;
1513 }
1514
91447636
A
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)) {
0a7de745 1520 if (!(lck_sleep_action & (LCK_SLEEP_SHARED | LCK_SLEEP_EXCLUSIVE))) {
91447636 1521 lck_rw_lock(lck, lck_rw_type);
0a7de745 1522 } else if (lck_sleep_action & LCK_SLEEP_EXCLUSIVE) {
91447636 1523 lck_rw_lock_exclusive(lck);
0a7de745 1524 } else {
91447636 1525 lck_rw_lock_shared(lck);
0a7de745 1526 }
91447636 1527 }
0a7de745 1528 } else if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
91447636 1529 (void)lck_rw_done(lck);
0a7de745 1530 }
91447636 1531
fe8ab488
A
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 */
1535
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);
1538
d9a64523 1539 lck_rw_clear_promotion(thread, unslide_for_kdebug(event));
fe8ab488
A
1540 }
1541 }
1542
91447636
A
1543 return res;
1544}
1545
39236c6e
A
1546/*
1547 * Reader-writer lock promotion
1548 *
1549 * We support a limited form of reader-writer
1550 * lock promotion whose effects are:
d9a64523 1551 *
39236c6e
A
1552 * * Qualifying threads have decay disabled
1553 * * Scheduler priority is reset to a floor of
1554 * of their statically assigned priority
d9a64523 1555 * or MINPRI_RWLOCK
39236c6e
A
1556 *
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.
1563 *
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).
1577 *
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
1585 * indefinitely.
1586 *
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).
1594 *
1595 */
1596
1597/*
1598 * lck_rw_clear_promotion: Undo priority promotions when the last RW
1599 * lock is released by a thread (if a promotion was active)
1600 */
0a7de745
A
1601void
1602lck_rw_clear_promotion(thread_t thread, uintptr_t trace_obj)
39236c6e
A
1603{
1604 assert(thread->rwlock_count == 0);
1605
1606 /* Cancel any promotions if the thread had actually blocked while holding a RW lock */
1607 spl_t s = splsched();
39236c6e
A
1608 thread_lock(thread);
1609
0a7de745 1610 if (thread->sched_flags & TH_SFLAG_RW_PROMOTED) {
d9a64523 1611 sched_thread_unpromote_reason(thread, TH_SFLAG_RW_PROMOTED, trace_obj);
0a7de745 1612 }
39236c6e
A
1613
1614 thread_unlock(thread);
1615 splx(s);
1616}
1617
39037602
A
1618/*
1619 * Callout from context switch if the thread goes
1620 * off core with a positive rwlock_count
1621 *
1622 * Called at splsched with the thread locked
1623 */
1624void
1625lck_rw_set_promotion_locked(thread_t thread)
1626{
0a7de745 1627 if (LcksOpts & disLkRWPrio) {
39037602 1628 return;
0a7de745 1629 }
39037602 1630
d9a64523 1631 assert(thread->rwlock_count > 0);
39037602 1632
0a7de745 1633 if (!(thread->sched_flags & TH_SFLAG_RW_PROMOTED)) {
d9a64523 1634 sched_thread_promote_reason(thread, TH_SFLAG_RW_PROMOTED, 0);
0a7de745 1635 }
39037602
A
1636}
1637
91447636
A
1638kern_return_t
1639host_lockgroup_info(
0a7de745
A
1640 host_t host,
1641 lockgroup_info_array_t *lockgroup_infop,
1642 mach_msg_type_number_t *lockgroup_infoCntp)
91447636 1643{
0a7de745
A
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;
1649 lck_grp_t *lck_grp;
1650 unsigned int i;
1651 vm_map_copy_t copy;
1652 kern_return_t kr;
1653
1654 if (host == HOST_NULL) {
91447636 1655 return KERN_INVALID_HOST;
0a7de745 1656 }
91447636 1657
b0d623f7 1658 lck_mtx_lock(&lck_grp_lock);
91447636 1659
2dced7af
A
1660 lockgroup_info_size = lck_grp_cnt * sizeof(*lockgroup_info);
1661 lockgroup_info_vmsize = round_page(lockgroup_info_size);
91447636 1662 kr = kmem_alloc_pageable(ipc_kernel_map,
0a7de745 1663 &lockgroup_info_addr, lockgroup_info_vmsize, VM_KERN_MEMORY_IPC);
91447636 1664 if (kr != KERN_SUCCESS) {
b0d623f7 1665 lck_mtx_unlock(&lck_grp_lock);
0a7de745 1666 return kr;
91447636
A
1667 }
1668
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;
1672
1673 for (i = 0; i < lck_grp_cnt; i++) {
91447636 1674 lockgroup_info->lock_spin_cnt = lck_grp->lck_grp_spincnt;
0a7de745 1675 lockgroup_info->lock_rw_cnt = lck_grp->lck_grp_rwcnt;
91447636 1676 lockgroup_info->lock_mtx_cnt = lck_grp->lck_grp_mtxcnt;
91447636 1677
0a7de745
A
1678#if LOCK_STATS
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 */
91447636 1682
0a7de745
A
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;
1688
1689 (void) strncpy(lockgroup_info->lockgroup_name, lck_grp->lck_grp_name, LOCKGROUP_MAX_NAME);
91447636
A
1690
1691 lck_grp = (lck_grp_t *)(queue_next((queue_entry_t)(lck_grp)));
1692 lockgroup_info++;
1693 }
1694
1695 *lockgroup_infoCntp = lck_grp_cnt;
b0d623f7 1696 lck_mtx_unlock(&lck_grp_lock);
91447636 1697
0a7de745 1698 if (lockgroup_info_size != lockgroup_info_vmsize) {
2dced7af 1699 bzero((char *)lockgroup_info, lockgroup_info_vmsize - lockgroup_info_size);
0a7de745 1700 }
91447636
A
1701
1702 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)lockgroup_info_addr,
0a7de745 1703 (vm_map_size_t)lockgroup_info_size, TRUE, &copy);
91447636
A
1704 assert(kr == KERN_SUCCESS);
1705
1706 *lockgroup_infop = (lockgroup_info_t *) copy;
1707
0a7de745 1708 return KERN_SUCCESS;
91447636
A
1709}
1710
39037602 1711/*
cb323159
A
1712 * sleep_with_inheritor and wakeup_with_inheritor KPI
1713 *
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.
1716 *
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.
1720 *
1721 * sleep_with_inheritor requires to hold a locking primitive while invoked, but wakeup_with_inheritor and change_sleep_inheritor don't require it.
1722 *
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.
1727 *
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.
1731 * Also:
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.
1734 *
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.
39037602 1737 */
0a7de745 1738
cb323159
A
1739kern_return_t
1740wakeup_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)
39037602 1741{
cb323159
A
1742 uint32_t index;
1743 struct turnstile *ts = NULL;
1744 kern_return_t ret = KERN_NOT_WAITING;
1745 int priority;
1746 thread_t wokeup;
39037602 1747
cb323159
A
1748 /*
1749 * the hash bucket spinlock is used as turnstile interlock
1750 */
1751 turnstile_hash_bucket_lock((uintptr_t)event, &index, type);
39037602 1752
cb323159 1753 ts = turnstile_prepare((uintptr_t)event, NULL, TURNSTILE_NULL, type);
39037602 1754
cb323159
A
1755 if (wake_one) {
1756 if (action == LCK_WAKE_DEFAULT) {
1757 priority = WAITQ_PROMOTE_ON_WAKE;
1758 } else {
1759 assert(action == LCK_WAKE_DO_NOT_TRANSFER_PUSH);
1760 priority = WAITQ_ALL_PRIORITIES;
1761 }
1762
1763 /*
1764 * WAITQ_PROMOTE_ON_WAKE will call turnstile_update_inheritor
1765 * if it finds a thread
1766 */
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;
1771 } else {
1772 thread_deallocate_safe(wokeup);
1773 }
1774 ret = KERN_SUCCESS;
1775 if (action == LCK_WAKE_DO_NOT_TRANSFER_PUSH) {
1776 goto complete;
1777 }
1778 } else {
1779 if (thread_wokenup != NULL) {
1780 *thread_wokenup = NULL;
1781 }
1782 turnstile_update_inheritor(ts, TURNSTILE_INHERITOR_NULL, TURNSTILE_IMMEDIATE_UPDATE);
1783 ret = KERN_NOT_WAITING;
1784 }
1785 } else {
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);
1788 }
1789
1790 /*
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
1794 * after the wait.
1795 * So there is no chain to update for the new inheritor.
1796 *
1797 * However unless the current thread is the old inheritor,
1798 * old inheritor can be blocked and requires a chain update.
1799 *
1800 * The chain should be short because kernel turnstiles cannot have user turnstiles
1801 * chained after them.
1802 *
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.
1806 */
1807 turnstile_hash_bucket_unlock((uintptr_t)NULL, &index, type, 0);
1808
1809 turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_NOT_HELD);
1810
1811 turnstile_hash_bucket_lock((uintptr_t)NULL, &index, type);
1812
1813complete:
1814 turnstile_complete((uintptr_t)event, NULL, NULL, type);
1815
1816 turnstile_hash_bucket_unlock((uintptr_t)NULL, &index, type, 0);
1817
1818 turnstile_cleanup();
1819
1820 return ret;
1821}
1822
1823static wait_result_t
1824sleep_with_inheritor_and_turnstile_type(event_t event,
1825 thread_t inheritor,
1826 wait_interrupt_t interruptible,
1827 uint64_t deadline,
1828 turnstile_type_t type,
1829 void (^primitive_lock)(void),
1830 void (^primitive_unlock)(void))
1831{
1832 wait_result_t ret;
1833 uint32_t index;
1834 struct turnstile *ts = NULL;
1835
1836 /*
1837 * the hash bucket spinlock is used as turnstile interlock,
1838 * lock it before releasing the primitive lock
1839 */
1840 turnstile_hash_bucket_lock((uintptr_t)event, &index, type);
1841
1842 primitive_unlock();
1843
1844 ts = turnstile_prepare((uintptr_t)event, NULL, TURNSTILE_NULL, type);
1845
1846 thread_set_pending_block_hint(current_thread(), kThreadWaitSleepWithInheritor);
1847 /*
1848 * We need TURNSTILE_DELAYED_UPDATE because we will call
1849 * waitq_assert_wait64 after.
1850 */
1851 turnstile_update_inheritor(ts, inheritor, (TURNSTILE_DELAYED_UPDATE | TURNSTILE_INHERITOR_THREAD));
1852
1853 ret = waitq_assert_wait64(&ts->ts_waitq, CAST_EVENT64_T(event), interruptible, deadline);
1854
1855 turnstile_hash_bucket_unlock((uintptr_t)NULL, &index, type, 0);
1856
1857 /*
1858 * Update new and old inheritor chains outside the interlock;
1859 */
1860 turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_NOT_HELD);
1861
1862 if (ret == THREAD_WAITING) {
1863 ret = thread_block(THREAD_CONTINUE_NULL);
1864 }
1865
1866 turnstile_hash_bucket_lock((uintptr_t)NULL, &index, type);
1867
1868 turnstile_complete((uintptr_t)event, NULL, NULL, type);
1869
1870 turnstile_hash_bucket_unlock((uintptr_t)NULL, &index, type, 0);
1871
1872 turnstile_cleanup();
1873
1874 primitive_lock();
1875
1876 return ret;
1877}
1878
1879kern_return_t
1880change_sleep_inheritor_and_turnstile_type(event_t event,
1881 thread_t inheritor,
1882 turnstile_type_t type)
1883{
1884 uint32_t index;
1885 struct turnstile *ts = NULL;
1886 kern_return_t ret = KERN_SUCCESS;
1887 /*
1888 * the hash bucket spinlock is used as turnstile interlock
1889 */
1890 turnstile_hash_bucket_lock((uintptr_t)event, &index, type);
1891
1892 ts = turnstile_prepare((uintptr_t)event, NULL, TURNSTILE_NULL, type);
1893
1894 if (!turnstile_has_waiters(ts)) {
1895 ret = KERN_NOT_WAITING;
1896 }
1897
1898 /*
1899 * We will not call an assert_wait later so use TURNSTILE_IMMEDIATE_UPDATE
1900 */
1901 turnstile_update_inheritor(ts, inheritor, (TURNSTILE_IMMEDIATE_UPDATE | TURNSTILE_INHERITOR_THREAD));
1902
1903 turnstile_hash_bucket_unlock((uintptr_t)NULL, &index, type, 0);
1904
1905 /*
1906 * update the chains outside the interlock
1907 */
1908 turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_NOT_HELD);
1909
1910 turnstile_hash_bucket_lock((uintptr_t)NULL, &index, type);
1911
1912 turnstile_complete((uintptr_t)event, NULL, NULL, type);
1913
1914 turnstile_hash_bucket_unlock((uintptr_t)NULL, &index, type, 0);
1915
1916 turnstile_cleanup();
1917
1918 return ret;
1919}
1920
1921typedef void (^void_block_void)(void);
1922
1923/*
1924 * sleep_with_inheritor functions with lck_mtx_t as locking primitive.
1925 */
1926
1927wait_result_t
1928lck_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)
1929{
1930 LCK_MTX_ASSERT(lock, LCK_MTX_ASSERT_OWNED);
1931
1932 if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
1933 return sleep_with_inheritor_and_turnstile_type(event,
1934 inheritor,
1935 interruptible,
1936 deadline,
1937 type,
1938 ^{;},
1939 ^{lck_mtx_unlock(lock);});
1940 } else if (lck_sleep_action & LCK_SLEEP_SPIN) {
1941 return sleep_with_inheritor_and_turnstile_type(event,
1942 inheritor,
1943 interruptible,
1944 deadline,
1945 type,
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,
1950 inheritor,
1951 interruptible,
1952 deadline,
1953 type,
1954 ^{lck_mtx_lock_spin_always(lock);},
1955 ^{lck_mtx_unlock(lock);});
1956 } else {
1957 return sleep_with_inheritor_and_turnstile_type(event,
1958 inheritor,
1959 interruptible,
1960 deadline,
1961 type,
1962 ^{lck_mtx_lock(lock);},
1963 ^{lck_mtx_unlock(lock);});
1964 }
1965}
1966
1967/*
1968 * Name: lck_spin_sleep_with_inheritor
1969 *
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.
1974 *
1975 * Args:
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.
1982 *
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.
1987 *
1988 * Returns: result of the wait.
1989 */
1990wait_result_t
1991lck_spin_sleep_with_inheritor(
1992 lck_spin_t *lock,
1993 lck_sleep_action_t lck_sleep_action,
1994 event_t event,
1995 thread_t inheritor,
1996 wait_interrupt_t interruptible,
1997 uint64_t deadline)
1998{
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); });
2003 } else {
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); });
2007 }
2008}
2009
2010/*
2011 * Name: lck_mtx_sleep_with_inheritor
2012 *
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.
2017 *
2018 * Args:
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.
2025 *
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.
2030 *
2031 * Returns: result of the wait.
2032 */
2033wait_result_t
2034lck_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)
2035{
2036 return lck_mtx_sleep_with_inheritor_and_turnstile_type(lock, lck_sleep_action, event, inheritor, interruptible, deadline, TURNSTILE_SLEEP_INHERITOR);
2037}
2038
2039/*
2040 * sleep_with_inheritor functions with lck_rw_t as locking primitive.
2041 */
2042
2043wait_result_t
2044lck_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)
2045{
2046 __block lck_rw_type_t lck_rw_type = LCK_RW_TYPE_EXCLUSIVE;
2047
2048 LCK_RW_ASSERT(lock, LCK_RW_ASSERT_HELD);
2049
2050 if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
2051 return sleep_with_inheritor_and_turnstile_type(event,
2052 inheritor,
2053 interruptible,
2054 deadline,
2055 type,
2056 ^{;},
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,
2060 inheritor,
2061 interruptible,
2062 deadline,
2063 type,
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,
2068 inheritor,
2069 interruptible,
2070 deadline,
2071 type,
2072 ^{lck_rw_lock_exclusive(lock);},
2073 ^{lck_rw_type = lck_rw_done(lock);});
2074 } else {
2075 return sleep_with_inheritor_and_turnstile_type(event,
2076 inheritor,
2077 interruptible,
2078 deadline,
2079 type,
2080 ^{lck_rw_lock_shared(lock);},
2081 ^{lck_rw_type = lck_rw_done(lock);});
2082 }
2083}
2084
2085/*
2086 * Name: lck_rw_sleep_with_inheritor
2087 *
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.
2092 *
2093 * Args:
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.
2100 *
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.
2105 *
2106 * Returns: result of the wait.
2107 */
2108wait_result_t
2109lck_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)
2110{
2111 return lck_rw_sleep_with_inheritor_and_turnstile_type(lock, lck_sleep_action, event, inheritor, interruptible, deadline, TURNSTILE_SLEEP_INHERITOR);
2112}
2113
2114/*
2115 * wakeup_with_inheritor functions are independent from the locking primitive.
2116 */
2117
2118/*
2119 * Name: wakeup_one_with_inheritor
2120 *
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.
2124 *
2125 * Args:
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.
2130 *
2131 * Returns: KERN_NOT_WAITING if no threads were waiting, KERN_SUCCESS otherwise.
2132 *
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.
2137 */
2138kern_return_t
2139wakeup_one_with_inheritor(event_t event, wait_result_t result, lck_wake_action_t action, thread_t *thread_wokenup)
2140{
2141 return wakeup_with_inheritor_and_turnstile_type(event,
2142 TURNSTILE_SLEEP_INHERITOR,
2143 result,
2144 TRUE,
2145 action,
2146 thread_wokenup);
2147}
2148
2149/*
2150 * Name: wakeup_all_with_inheritor
2151 *
2152 * Description: wake up all waiters waiting for event. The old inheritor will lose the push.
2153 *
2154 * Args:
2155 * Arg1: event to wake from.
2156 * Arg2: wait result to pass to the woken up threads.
2157 *
2158 * Returns: KERN_NOT_WAITING if no threads were waiting, KERN_SUCCESS otherwise.
2159 *
2160 * Conditions: NOTE: this cannot be called from interrupt context.
2161 */
2162kern_return_t
2163wakeup_all_with_inheritor(event_t event, wait_result_t result)
2164{
2165 return wakeup_with_inheritor_and_turnstile_type(event,
2166 TURNSTILE_SLEEP_INHERITOR,
2167 result,
2168 FALSE,
2169 0,
2170 NULL);
2171}
2172
2173/*
2174 * change_sleep_inheritor is independent from the locking primitive.
2175 */
2176
2177/*
2178 * Name: change_sleep_inheritor
2179 *
2180 * Description: Redirect the push of the waiting threads of event to the new inheritor specified.
2181 *
2182 * Args:
2183 * Arg1: event to redirect the push.
2184 * Arg2: new inheritor for event.
2185 *
2186 * Returns: KERN_NOT_WAITING if no threads were waiting, KERN_SUCCESS otherwise.
2187 *
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.
2191 */
2192kern_return_t
2193change_sleep_inheritor(event_t event, thread_t inheritor)
2194{
2195 return change_sleep_inheritor_and_turnstile_type(event,
2196 inheritor,
2197 TURNSTILE_SLEEP_INHERITOR);
2198}
2199
2200void
2201kdp_sleep_with_inheritor_find_owner(struct waitq * waitq, __unused event64_t event, thread_waitinfo_t * waitinfo)
2202{
2203 assert(waitinfo->wait_type == kThreadWaitSleepWithInheritor);
2204 assert(waitq_is_turnstile_queue(waitq));
2205 waitinfo->owner = 0;
2206 waitinfo->context = 0;
2207
2208 if (waitq_held(waitq)) {
2209 return;
2210 }
2211
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);
2215}
2216
2217typedef void (*void_func_void)(void);
2218
2219static kern_return_t
2220gate_try_close(gate_t *gate)
2221{
2222 uintptr_t state;
2223 thread_t holder;
2224 kern_return_t ret;
2225 __assert_only bool waiters;
2226 thread_t thread = current_thread();
2227
2228 if (os_atomic_cmpxchg(&gate->gate_data, 0, GATE_THREAD_TO_STATE(thread), acquire)) {
2229 return KERN_SUCCESS;
2230 }
2231
2232 gate_ilock(gate);
2233 state = ordered_load_gate(gate);
2234 holder = GATE_STATE_TO_THREAD(state);
2235
2236 if (holder == NULL) {
2237 waiters = gate_has_waiters(state);
2238 assert(waiters == FALSE);
2239
2240 state = GATE_THREAD_TO_STATE(current_thread());
2241 state |= GATE_ILOCK;
2242 ordered_store_gate(gate, state);
2243 ret = KERN_SUCCESS;
2244 } else {
2245 if (holder == current_thread()) {
2246 panic("Trying to close a gate already owned by current thread %p", current_thread());
2247 }
2248 ret = KERN_FAILURE;
2249 }
2250
2251 gate_iunlock(gate);
2252 return ret;
2253}
2254
2255static void
2256gate_close(gate_t* gate)
2257{
2258 uintptr_t state;
2259 thread_t holder;
2260 __assert_only bool waiters;
2261 thread_t thread = current_thread();
2262
2263 if (os_atomic_cmpxchg(&gate->gate_data, 0, GATE_THREAD_TO_STATE(thread), acquire)) {
2264 return;
2265 }
2266
2267 gate_ilock(gate);
2268 state = ordered_load_gate(gate);
2269 holder = GATE_STATE_TO_THREAD(state);
2270
2271 if (holder != NULL) {
2272 panic("Closing a gate already owned by %p from current thread %p", holder, current_thread());
2273 }
2274
2275 waiters = gate_has_waiters(state);
2276 assert(waiters == FALSE);
2277
2278 state = GATE_THREAD_TO_STATE(thread);
2279 state |= GATE_ILOCK;
2280 ordered_store_gate(gate, state);
2281
2282 gate_iunlock(gate);
2283}
2284
2285static void
2286gate_open_turnstile(gate_t *gate)
2287{
2288 struct turnstile *ts = NULL;
2289
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);
2295 /*
2296 * We can do the cleanup while holding the interlock.
2297 * It is ok because:
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.
2301 */
2302 turnstile_cleanup();
2303}
2304
2305static void
2306gate_open(gate_t *gate)
2307{
2308 uintptr_t state;
2309 thread_t holder;
2310 bool waiters;
2311 thread_t thread = current_thread();
2312
2313 if (os_atomic_cmpxchg(&gate->gate_data, GATE_THREAD_TO_STATE(thread), 0, release)) {
2314 return;
2315 }
2316
2317 gate_ilock(gate);
2318 state = ordered_load_gate(gate);
2319 holder = GATE_STATE_TO_THREAD(state);
2320 waiters = gate_has_waiters(state);
2321
2322 if (holder != thread) {
2323 panic("Opening gate owned by %p from current thread %p", holder, thread);
2324 }
2325
2326 if (waiters) {
2327 gate_open_turnstile(gate);
2328 }
2329
2330 state = GATE_ILOCK;
2331 ordered_store_gate(gate, state);
2332
2333 gate_iunlock(gate);
2334}
2335
2336static kern_return_t
2337gate_handoff_turnstile(gate_t *gate,
2338 int flags,
2339 thread_t *thread_woken_up,
2340 bool *waiters)
2341{
2342 struct turnstile *ts = NULL;
2343 kern_return_t ret = KERN_FAILURE;
2344 thread_t hp_thread;
2345
2346 ts = turnstile_prepare((uintptr_t)gate, &gate->turnstile, TURNSTILE_NULL, TURNSTILE_KERNEL_MUTEX);
2347 /*
2348 * Wake up the higest priority thread waiting on the gate
2349 */
2350 hp_thread = waitq_wakeup64_identify(&ts->ts_waitq, CAST_EVENT64_T(GATE_EVENT(gate)), THREAD_AWAKENED, WAITQ_PROMOTE_ON_WAKE);
2351
2352 if (hp_thread != NULL) {
2353 /*
2354 * In this case waitq_wakeup64_identify has called turnstile_update_inheritor for us
2355 */
2356 turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_HELD);
2357 *thread_woken_up = hp_thread;
2358 *waiters = turnstile_has_waiters(ts);
2359 /*
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.
2367 */
2368 ret = KERN_SUCCESS;
2369 } else {
2370 /*
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.
2375 */
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);
2379 }
2380 // there are no waiters.
2381 ret = KERN_NOT_WAITING;
2382 }
2383
2384 turnstile_complete((uintptr_t)gate, &gate->turnstile, NULL, TURNSTILE_KERNEL_MUTEX);
2385
2386 /*
2387 * We can do the cleanup while holding the interlock.
2388 * It is ok because:
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.
2393 */
2394 turnstile_cleanup();
2395
2396 return ret;
2397}
2398
2399static kern_return_t
2400gate_handoff(gate_t *gate,
2401 int flags)
2402{
2403 kern_return_t ret;
2404 thread_t new_holder = NULL;
2405 uintptr_t state;
2406 thread_t holder;
2407 bool waiters;
2408 thread_t thread = current_thread();
2409
2410 assert(flags == GATE_HANDOFF_OPEN_IF_NO_WAITERS || flags == GATE_HANDOFF_DEFAULT);
2411
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;
2416 }
2417 }
2418
2419 gate_ilock(gate);
2420 state = ordered_load_gate(gate);
2421 holder = GATE_STATE_TO_THREAD(state);
2422 waiters = gate_has_waiters(state);
2423
2424 if (holder != current_thread()) {
2425 panic("Handing off gate owned by %p from current thread %p", holder, current_thread());
2426 }
2427
2428 if (waiters) {
2429 ret = gate_handoff_turnstile(gate, flags, &new_holder, &waiters);
2430 if (ret == KERN_SUCCESS) {
2431 state = GATE_THREAD_TO_STATE(new_holder);
2432 if (waiters) {
2433 state |= GATE_WAITERS;
2434 }
2435 } else {
2436 if (flags == GATE_HANDOFF_OPEN_IF_NO_WAITERS) {
2437 state = 0;
2438 }
2439 }
2440 } else {
2441 if (flags == GATE_HANDOFF_OPEN_IF_NO_WAITERS) {
2442 state = 0;
2443 }
2444 ret = KERN_NOT_WAITING;
2445 }
2446 state |= GATE_ILOCK;
2447 ordered_store_gate(gate, state);
2448
2449 gate_iunlock(gate);
2450
2451 if (new_holder) {
2452 thread_deallocate(new_holder);
2453 }
2454 return ret;
2455}
2456
2457static void_func_void
2458gate_steal_turnstile(gate_t *gate,
2459 thread_t new_inheritor)
2460{
2461 struct turnstile *ts = NULL;
2462
2463 ts = turnstile_prepare((uintptr_t)gate, &gate->turnstile, TURNSTILE_NULL, TURNSTILE_KERNEL_MUTEX);
2464
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);
2468
2469 /*
2470 * turnstile_cleanup might need to update the chain of the old holder.
2471 * This operation should happen without the turnstile interlock held.
2472 */
2473 return turnstile_cleanup;
2474}
2475
2476static void
2477gate_steal(gate_t *gate)
2478{
2479 uintptr_t state;
2480 thread_t holder;
2481 thread_t thread = current_thread();
2482 bool waiters;
2483
2484 void_func_void func_after_interlock_unlock;
2485
2486 gate_ilock(gate);
2487 state = ordered_load_gate(gate);
2488 holder = GATE_STATE_TO_THREAD(state);
2489 waiters = gate_has_waiters(state);
2490
2491 assert(holder != NULL);
2492 state = GATE_THREAD_TO_STATE(thread) | GATE_ILOCK;
2493 if (waiters) {
2494 state |= GATE_WAITERS;
2495 ordered_store_gate(gate, state);
2496 func_after_interlock_unlock = gate_steal_turnstile(gate, thread);
2497 gate_iunlock(gate);
2498
2499 func_after_interlock_unlock();
2500 } else {
2501 ordered_store_gate(gate, state);
2502 gate_iunlock(gate);
2503 }
2504}
2505
2506static void_func_void
2507gate_wait_turnstile(gate_t *gate,
2508 wait_interrupt_t interruptible,
2509 uint64_t deadline,
2510 thread_t holder,
2511 wait_result_t* wait,
2512 bool* waiters)
2513{
2514 struct turnstile *ts;
2515 uintptr_t state;
2516
2517 ts = turnstile_prepare((uintptr_t)gate, &gate->turnstile, TURNSTILE_NULL, TURNSTILE_KERNEL_MUTEX);
2518
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);
2521
2522 gate_iunlock(gate);
2523
2524 turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_NOT_HELD);
2525
2526 *wait = thread_block(THREAD_CONTINUE_NULL);
2527
2528 gate_ilock(gate);
2529
2530 *waiters = turnstile_has_waiters(ts);
2531
2532 if (!*waiters) {
2533 /*
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.
2537 *
2538 * NOTE: if it was an open operation that woke this thread up, the inheritor has
2539 * already been set to NULL.
2540 */
2541 state = ordered_load_gate(gate);
2542 holder = GATE_STATE_TO_THREAD(state);
2543 if (holder &&
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);
2548 }
2549 }
2550
2551 turnstile_complete((uintptr_t)gate, &gate->turnstile, NULL, TURNSTILE_KERNEL_MUTEX);
2552
2553 /*
2554 * turnstile_cleanup might need to update the chain of the old holder.
2555 * This operation should happen without the turnstile primitive interlock held.
2556 */
2557 return turnstile_cleanup;
2558}
2559
2560static gate_wait_result_t
2561gate_wait(gate_t* gate,
2562 wait_interrupt_t interruptible,
2563 uint64_t deadline,
2564 void (^primitive_unlock)(void),
2565 void (^primitive_lock)(void))
2566{
2567 gate_wait_result_t ret;
2568 void_func_void func_after_interlock_unlock;
2569 wait_result_t wait_result;
2570 uintptr_t state;
2571 thread_t holder;
2572 bool waiters;
2573
2574
2575 gate_ilock(gate);
2576 state = ordered_load_gate(gate);
2577 holder = GATE_STATE_TO_THREAD(state);
2578
2579 if (holder == NULL) {
2580 panic("Trying to wait on open gate thread %p gate %p", current_thread(), gate);
2581 }
2582
2583 state |= GATE_WAITERS;
2584 ordered_store_gate(gate, state);
2585
2586 /*
2587 * Release the primitive lock before any
2588 * turnstile operation. Turnstile
2589 * does not support a blocking primitive as
2590 * interlock.
2591 *
2592 * In this way, concurrent threads will be
2593 * able to acquire the primitive lock
2594 * but still will wait for me through the
2595 * gate interlock.
2596 */
2597 primitive_unlock();
2598
2599 func_after_interlock_unlock = gate_wait_turnstile( gate,
2600 interruptible,
2601 deadline,
2602 holder,
2603 &wait_result,
2604 &waiters);
2605
2606 state = ordered_load_gate(gate);
2607 holder = GATE_STATE_TO_THREAD(state);
2608
2609 switch (wait_result) {
2610 case THREAD_INTERRUPTED:
2611 case THREAD_TIMED_OUT:
2612 assert(holder != current_thread());
2613
2614 if (waiters) {
2615 state |= GATE_WAITERS;
2616 } else {
2617 state &= ~GATE_WAITERS;
2618 }
2619 ordered_store_gate(gate, state);
2620
2621 if (wait_result == THREAD_INTERRUPTED) {
2622 ret = GATE_INTERRUPTED;
2623 } else {
2624 ret = GATE_TIMED_OUT;
2625 }
2626 break;
2627 default:
2628 /*
2629 * Note it is possible that even if the gate was handed off to
2630 * me, someone called gate_steal() before I woke up.
2631 *
2632 * As well as it is possible that the gate was opened, but someone
2633 * closed it while I was waking up.
2634 *
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
2637 * the gate is open.
2638 */
2639 if (holder == current_thread()) {
2640 ret = GATE_HANDOFF;
2641 } else {
2642 ret = GATE_OPENED;
2643 }
2644 break;
2645 }
2646
2647 gate_iunlock(gate);
2648
2649 /*
2650 * turnstile func that needs to be executed without
2651 * holding the primitive interlock
2652 */
2653 func_after_interlock_unlock();
2654
2655 primitive_lock();
2656
2657 return ret;
2658}
2659static void
2660gate_assert(gate_t *gate, int flags)
2661{
2662 uintptr_t state;
2663 thread_t holder;
2664
2665 gate_ilock(gate);
2666 state = ordered_load_gate(gate);
2667 holder = GATE_STATE_TO_THREAD(state);
2668
2669 switch (flags) {
2670 case GATE_ASSERT_CLOSED:
2671 assert(holder != NULL);
2672 break;
2673 case GATE_ASSERT_OPEN:
2674 assert(holder == NULL);
2675 break;
2676 case GATE_ASSERT_HELD:
2677 assert(holder == current_thread());
2678 break;
2679 default:
2680 panic("invalid %s flag %d", __func__, flags);
2681 }
2682
2683 gate_iunlock(gate);
2684}
2685
2686static void
2687gate_init(gate_t *gate)
2688{
2689 gate->gate_data = 0;
2690 gate->turnstile = NULL;
2691}
2692
2693static void
2694gate_destroy(__assert_only gate_t *gate)
2695{
2696 assert(gate->gate_data == 0);
2697 assert(gate->turnstile == NULL);
2698}
2699
2700/*
2701 * Name: lck_rw_gate_init
2702 *
2703 * Description: initializes a variable declared with decl_lck_rw_gate_data.
2704 *
2705 * Args:
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.
2708 */
2709void
2710lck_rw_gate_init(lck_rw_t *lock, gate_t *gate)
2711{
2712 (void) lock;
2713 gate_init(gate);
2714}
2715
2716/*
2717 * Name: lck_rw_gate_destroy
2718 *
2719 * Description: destroys a variable previously initialized.
2720 *
2721 * Args:
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.
2724 */
2725void
2726lck_rw_gate_destroy(lck_rw_t *lock, gate_t *gate)
2727{
2728 (void) lock;
2729 gate_destroy(gate);
2730}
2731
2732/*
2733 * Name: lck_rw_gate_try_close
2734 *
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.
2738 *
2739 * Args:
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.
2742 *
2743 * Conditions: Lock must be held. Returns with the lock held.
2744 *
2745 * Returns:
2746 * KERN_SUCCESS in case the gate was successfully closed. The current thread is the new holder
2747 * of the gate.
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().
2752 *
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.
2757 */
2758int
2759lck_rw_gate_try_close(__assert_only lck_rw_t *lock, gate_t *gate)
2760{
2761 LCK_RW_ASSERT(lock, LCK_RW_ASSERT_HELD);
2762
2763 return gate_try_close(gate);
2764}
2765
2766/*
2767 * Name: lck_rw_gate_close
2768 *
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.
2773 *
2774 * Args:
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.
2777 *
2778 * Conditions: Lock must be held. Returns with the lock held.
2779 * The gate must be open.
2780 *
2781 */
2782void
2783lck_rw_gate_close(__assert_only lck_rw_t *lock, gate_t *gate)
2784{
2785 LCK_RW_ASSERT(lock, LCK_RW_ASSERT_HELD);
2786
2787 return gate_close(gate);
2788}
2789
2790/*
2791 * Name: lck_rw_gate_open
2792 *
2793 * Description: Opens the gate and wakes up possible waiters.
2794 *
2795 * Args:
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.
2798 *
2799 * Conditions: Lock must be held. Returns with the lock held.
2800 * The current thread must be the holder of the gate.
2801 *
2802 */
2803void
2804lck_rw_gate_open(__assert_only lck_rw_t *lock, gate_t *gate)
2805{
2806 LCK_RW_ASSERT(lock, LCK_RW_ASSERT_HELD);
2807
2808 gate_open(gate);
2809}
2810
2811/*
2812 * Name: lck_rw_gate_handoff
2813 *
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
2818 * will be returned.
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.
2821 *
2822 *
2823 * Args:
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
2827 *
2828 * Conditions: Lock must be held. Returns with the lock held.
2829 * The current thread must be the holder of the gate.
2830 *
2831 * Returns:
2832 * KERN_SUCCESS in case one of the waiters became the new holder.
2833 * KERN_NOT_WAITING in case there were no waiters.
2834 *
2835 */
2836kern_return_t
2837lck_rw_gate_handoff(__assert_only lck_rw_t *lock, gate_t *gate, int flags)
2838{
2839 LCK_RW_ASSERT(lock, LCK_RW_ASSERT_HELD);
2840
2841 return gate_handoff(gate, flags);
2842}
2843
2844/*
2845 * Name: lck_rw_gate_steal
2846 *
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()
2852 * anymore.
2853 *
2854 *
2855 * Args:
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.
2858 *
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.
2861 *
2862 */
2863void
2864lck_rw_gate_steal(__assert_only lck_rw_t *lock, gate_t *gate)
2865{
2866 LCK_RW_ASSERT(lock, LCK_RW_ASSERT_HELD);
2867
2868 gate_steal(gate);
2869}
2870
2871/*
2872 * Name: lck_rw_gate_wait
2873 *
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.
2877 *
2878 * Args:
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.
2883 * Arg4: deadline
2884 *
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.
2888 *
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.
2896 *
2897 */
2898gate_wait_result_t
2899lck_rw_gate_wait(lck_rw_t *lock, gate_t *gate, lck_sleep_action_t lck_sleep_action, wait_interrupt_t interruptible, uint64_t deadline)
2900{
2901 __block lck_rw_type_t lck_rw_type = LCK_RW_TYPE_EXCLUSIVE;
2902
2903 LCK_RW_ASSERT(lock, LCK_RW_ASSERT_HELD);
2904
2905 if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
2906 return gate_wait(gate,
2907 interruptible,
2908 deadline,
2909 ^{lck_rw_type = lck_rw_done(lock);},
2910 ^{;});
2911 } else if (!(lck_sleep_action & (LCK_SLEEP_SHARED | LCK_SLEEP_EXCLUSIVE))) {
2912 return gate_wait(gate,
2913 interruptible,
2914 deadline,
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,
2919 interruptible,
2920 deadline,
2921 ^{lck_rw_type = lck_rw_done(lock);},
2922 ^{lck_rw_lock_exclusive(lock);});
2923 } else {
2924 return gate_wait(gate,
2925 interruptible,
2926 deadline,
2927 ^{lck_rw_type = lck_rw_done(lock);},
2928 ^{lck_rw_lock_shared(lock);});
2929 }
2930}
2931
2932/*
2933 * Name: lck_rw_gate_assert
2934 *
2935 * Description: asserts that the gate is in the specified state.
2936 *
2937 * Args:
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
2944 */
2945void
2946lck_rw_gate_assert(__assert_only lck_rw_t *lock, gate_t *gate, int flags)
2947{
2948 LCK_RW_ASSERT(lock, LCK_RW_ASSERT_HELD);
2949
2950 gate_assert(gate, flags);
2951 return;
2952}
2953
2954/*
2955 * Name: lck_mtx_gate_init
2956 *
2957 * Description: initializes a variable declared with decl_lck_mtx_gate_data.
2958 *
2959 * Args:
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.
2962 */
2963void
2964lck_mtx_gate_init(lck_mtx_t *lock, gate_t *gate)
2965{
2966 (void) lock;
2967 gate_init(gate);
2968}
2969
2970/*
2971 * Name: lck_mtx_gate_destroy
2972 *
2973 * Description: destroys a variable previously initialized
2974 *
2975 * Args:
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.
2978 */
2979void
2980lck_mtx_gate_destroy(lck_mtx_t *lock, gate_t *gate)
2981{
2982 (void) lock;
2983 gate_destroy(gate);
2984}
2985
2986/*
2987 * Name: lck_mtx_gate_try_close
2988 *
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.
2992 *
2993 * Args:
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.
2996 *
2997 * Conditions: Lock must be held. Returns with the lock held.
2998 *
2999 * Returns:
3000 * KERN_SUCCESS in case the gate was successfully closed. The current thread is the new holder
3001 * of the gate.
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().
3006 *
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.
3011 */
3012int
3013lck_mtx_gate_try_close(__assert_only lck_mtx_t *lock, gate_t *gate)
3014{
3015 LCK_MTX_ASSERT(lock, LCK_MTX_ASSERT_OWNED);
3016
3017 return gate_try_close(gate);
3018}
3019
3020/*
3021 * Name: lck_mtx_gate_close
3022 *
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.
3027 *
3028 * Args:
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.
3031 *
3032 * Conditions: Lock must be held. Returns with the lock held.
3033 * The gate must be open.
3034 *
3035 */
39037602 3036void
cb323159 3037lck_mtx_gate_close(__assert_only lck_mtx_t *lock, gate_t *gate)
39037602 3038{
cb323159
A
3039 LCK_MTX_ASSERT(lock, LCK_MTX_ASSERT_OWNED);
3040
3041 return gate_close(gate);
3042}
3043
3044/*
3045 * Name: lck_mtx_gate_open
3046 *
3047 * Description: Opens of the gate and wakes up possible waiters.
3048 *
3049 * Args:
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.
3052 *
3053 * Conditions: Lock must be held. Returns with the lock held.
3054 * The current thread must be the holder of the gate.
3055 *
3056 */
3057void
3058lck_mtx_gate_open(__assert_only lck_mtx_t *lock, gate_t *gate)
3059{
3060 LCK_MTX_ASSERT(lock, LCK_MTX_ASSERT_OWNED);
3061
3062 gate_open(gate);
39037602
A
3063}
3064
cb323159
A
3065/*
3066 * Name: lck_mtx_gate_handoff
3067 *
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
3072 * will be returned.
3073 * OPEN_ON_FAILURE flag can be used to specify if the gate should be opened in
3074 * case no waiters were found.
3075 *
3076 *
3077 * Args:
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
3081 *
3082 * Conditions: Lock must be held. Returns with the lock held.
3083 * The current thread must be the holder of the gate.
3084 *
3085 * Returns:
3086 * KERN_SUCCESS in case one of the waiters became the new holder.
3087 * KERN_NOT_WAITING in case there were no waiters.
3088 *
3089 */
3090kern_return_t
3091lck_mtx_gate_handoff(__assert_only lck_mtx_t *lock, gate_t *gate, int flags)
39037602 3092{
cb323159
A
3093 LCK_MTX_ASSERT(lock, LCK_MTX_ASSERT_OWNED);
3094
3095 return gate_handoff(gate, flags);
39037602
A
3096}
3097
cb323159
A
3098/*
3099 * Name: lck_mtx_gate_steal
3100 *
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()
3106 * anymore.
3107 *
3108 *
3109 * Args:
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.
3112 *
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.
3115 *
3116 */
39037602 3117void
cb323159
A
3118lck_mtx_gate_steal(__assert_only lck_mtx_t *lock, gate_t *gate)
3119{
3120 LCK_MTX_ASSERT(lock, LCK_MTX_ASSERT_OWNED);
3121
3122 gate_steal(gate);
3123}
3124
3125/*
3126 * Name: lck_mtx_gate_wait
3127 *
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.
3131 *
3132 * Args:
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.
3137 * Arg4: deadline
3138 *
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.
3142 *
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.
3150 *
3151 */
3152gate_wait_result_t
3153lck_mtx_gate_wait(lck_mtx_t *lock, gate_t *gate, lck_sleep_action_t lck_sleep_action, wait_interrupt_t interruptible, uint64_t deadline)
39037602 3154{
cb323159
A
3155 LCK_MTX_ASSERT(lock, LCK_MTX_ASSERT_OWNED);
3156
3157 if (lck_sleep_action & LCK_SLEEP_UNLOCK) {
3158 return gate_wait(gate,
3159 interruptible,
3160 deadline,
3161 ^{lck_mtx_unlock(lock);},
3162 ^{;});
3163 } else if (lck_sleep_action & LCK_SLEEP_SPIN) {
3164 return gate_wait(gate,
3165 interruptible,
3166 deadline,
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,
3171 interruptible,
3172 deadline,
3173 ^{lck_mtx_unlock(lock);},
3174 ^{lck_mtx_lock_spin_always(lock);});
3175 } else {
3176 return gate_wait(gate,
3177 interruptible,
3178 deadline,
3179 ^{lck_mtx_unlock(lock);},
3180 ^{lck_mtx_lock(lock);});
3181 }
39037602
A
3182}
3183
cb323159
A
3184/*
3185 * Name: lck_mtx_gate_assert
3186 *
3187 * Description: asserts that the gate is in the specified state.
3188 *
3189 * Args:
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
3196 */
3197void
3198lck_mtx_gate_assert(__assert_only lck_mtx_t *lock, gate_t *gate, int flags)
39037602 3199{
cb323159
A
3200 LCK_MTX_ASSERT(lock, LCK_MTX_ASSERT_OWNED);
3201
3202 gate_assert(gate, flags);
39037602 3203}
f427ee49
A
3204
3205#pragma mark - LCK_*_DECLARE support
3206
3207__startup_func
3208void
3209lck_grp_attr_startup_init(struct lck_grp_attr_startup_spec *sp)
3210{
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;
3215}
3216
3217__startup_func
3218void
3219lck_grp_startup_init(struct lck_grp_startup_spec *sp)
3220{
3221 lck_grp_init(sp->grp, sp->grp_name, sp->grp_attr);
3222}
3223
3224__startup_func
3225void
3226lck_attr_startup_init(struct lck_attr_startup_spec *sp)
3227{
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;
3232}
3233
3234__startup_func
3235void
3236lck_spin_startup_init(struct lck_spin_startup_spec *sp)
3237{
3238 lck_spin_init(sp->lck, sp->lck_grp, sp->lck_attr);
3239}
3240
3241__startup_func
3242void
3243lck_mtx_startup_init(struct lck_mtx_startup_spec *sp)
3244{
3245 if (sp->lck_ext) {
3246 lck_mtx_init_ext(sp->lck, sp->lck_ext, sp->lck_grp, sp->lck_attr);
3247 } else {
3248 lck_mtx_init(sp->lck, sp->lck_grp, sp->lck_attr);
3249 }
3250}
3251
3252__startup_func
3253void
3254lck_rw_startup_init(struct lck_rw_startup_spec *sp)
3255{
3256 lck_rw_init(sp->lck, sp->lck_grp, sp->lck_attr);
3257}
3258
3259__startup_func
3260void
3261usimple_lock_startup_init(struct usimple_lock_startup_spec *sp)
3262{
3263 simple_lock_init(sp->lck, sp->lck_init_arg);
3264}