2 * Copyright (c) 2015-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * @OSF_FREE_COPYRIGHT@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
58 * un-comment the following lines to debug the link/prepost tables
59 * NOTE: this expands each element by ~40 bytes
61 //#define KEEP_WAITQ_LINK_STATS
62 //#define KEEP_WAITQ_PREPOST_STATS
65 #include <kern/backtrace.h>
66 #include <kern/kern_types.h>
67 #include <kern/ltable.h>
68 #include <kern/mach_param.h>
69 #include <kern/percpu.h>
70 #include <kern/queue.h>
71 #include <kern/sched_prim.h>
72 #include <kern/simple_lock.h>
74 #include <kern/waitq.h>
75 #include <kern/zalloc.h>
76 #include <kern/policy_internal.h>
77 #include <kern/turnstile.h>
80 #include <libkern/OSAtomic.h>
81 #include <mach/sync_policy.h>
82 #include <vm/vm_kern.h>
84 #include <sys/kdebug.h>
86 #if defined(KEEP_WAITQ_LINK_STATS) || defined(KEEP_WAITQ_PREPOST_STATS)
87 # if !CONFIG_LTABLE_STATS
88 # error "You must configure LTABLE_STATS to use WAITQ_[LINK|PREPOST]_STATS"
90 # if !CONFIG_WAITQ_STATS
91 # error "You must configure WAITQ_STATS to use WAITQ_[LINK|PREPOST]_STATS"
95 #if CONFIG_WAITQ_DEBUG
96 #define wqdbg(fmt, ...) \
97 printf("WQ[%s]: " fmt "\n", __func__, ## __VA_ARGS__)
99 #define wqdbg(fmt, ...) do { } while (0)
102 #ifdef WAITQ_VERBOSE_DEBUG
103 #define wqdbg_v(fmt, ...) \
104 printf("WQ[v:%s]: " fmt "\n", __func__, ## __VA_ARGS__)
106 #define wqdbg_v(fmt, ...) do { } while (0)
109 #define wqinfo(fmt, ...) \
110 printf("WQ[%s]: " fmt "\n", __func__, ## __VA_ARGS__)
112 #define wqerr(fmt, ...) \
113 printf("WQ[%s] ERROR: " fmt "\n", __func__, ## __VA_ARGS__)
116 * file-static functions / data
118 static thread_t
waitq_select_one_locked(struct waitq
*waitq
, event64_t event
,
119 uint64_t *reserved_preposts
,
120 int priority
, spl_t
*spl
);
122 static kern_return_t
waitq_select_thread_locked(struct waitq
*waitq
,
124 thread_t thread
, spl_t
*spl
);
126 ZONE_DECLARE(waitq_set_zone
, "waitq sets",
127 sizeof(struct waitq_set
), ZC_NOENCRYPT
);
129 /* waitq prepost cache */
130 #define WQP_CACHE_MAX 50
135 static struct wqp_cache
PERCPU_DATA(wqp_cache
);
137 #define P2ROUNDUP(x, align) (-(-((uint32_t)(x)) & -(align)))
138 #define ROUNDDOWN(x, y) (((x)/(y))*(y))
141 #if CONFIG_LTABLE_STATS || CONFIG_WAITQ_STATS
142 static __inline__
void waitq_grab_backtrace(uintptr_t bt
[NWAITQ_BTFRAMES
], int skip
);
145 LCK_GRP_DECLARE(waitq_lck_grp
, "waitq");
149 #define waitq_lock_to(wq, to) \
150 (hw_lock_bit_to(&(wq)->waitq_interlock, LCK_ILOCK, to, &waitq_lck_grp))
152 #define waitq_lock_unlock(wq) \
153 (hw_unlock_bit(&(wq)->waitq_interlock, LCK_ILOCK))
155 #define waitq_lock_init(wq) \
156 (wq->waitq_interlock = 0)
160 #define waitq_lock_to(wq, to) \
161 (hw_lock_to(&(wq)->waitq_interlock, to, &waitq_lck_grp))
163 #define waitq_lock_unlock(wq) \
164 (hw_lock_unlock(&(wq)->waitq_interlock))
166 #define waitq_lock_init(wq) \
167 (hw_lock_init(&(wq)->waitq_interlock))
169 #endif /* __arm64__ */
172 * Prepost callback function for specially marked waitq sets
173 * (prepost alternative)
175 extern void waitq_set__CALLING_PREPOST_HOOK__(waitq_set_prepost_hook_t
*ctx
);
177 #define DEFAULT_MIN_FREE_TABLE_ELEM 100
178 static uint32_t g_min_free_table_elem
;
179 static uint32_t g_min_free_cache
;
182 /* ----------------------------------------------------------------------
184 * SetID Link Table Implementation
186 * ---------------------------------------------------------------------- */
187 static struct link_table g_wqlinktable
;
200 /* wqt_type == WQL_WQS (LT_ELEM) */
202 struct waitq_set
*wql_set
;
203 /* uint64_t sl_prepost_id; */
206 /* wqt_type == WQL_LINK (LT_LINK) */
209 uint64_t right_setid
;
212 #ifdef KEEP_WAITQ_LINK_STATS
213 thread_t sl_alloc_th
;
214 task_t sl_alloc_task
;
215 uintptr_t sl_alloc_bt
[NWAITQ_BTFRAMES
];
216 uint64_t sl_alloc_ts
;
217 uintptr_t sl_invalidate_bt
[NWAITQ_BTFRAMES
];
218 uint64_t sl_invalidate_ts
;
219 uintptr_t sl_mkvalid_bt
[NWAITQ_BTFRAMES
];
220 uint64_t sl_mkvalid_ts
;
224 #if !defined(KEEP_WAITQ_LINK_STATS)
225 static_assert((sizeof(struct waitq_link
) & (sizeof(struct waitq_link
) - 1)) == 0,
226 "waitq_link struct must be a power of two!");
229 #define wql_refcnt(link) \
230 (lt_bits_refcnt((link)->wqte.lt_bits))
232 #define wql_type(link) \
233 (lt_bits_type((link)->wqte.lt_bits))
235 #define wql_mkvalid(link) \
237 lt_elem_mkvalid(&(link)->wqte); \
238 wql_do_mkvalid_stats(&(link)->wqte); \
241 #define wql_is_valid(link) \
242 lt_bits_valid((link)->wqte.lt_bits)
244 #define wql_setid wqte.lt_id
246 #define WQL_WQS_POISON ((void *)(0xf00df00d))
247 #define WQL_LINK_POISON (0x0bad0badffffffffull)
250 wql_poison(struct link_table
*table
, struct lt_elem
*elem
)
252 struct waitq_link
*link
= (struct waitq_link
*)elem
;
255 switch (wql_type(link
)) {
257 link
->wql_wqs
.wql_set
= WQL_WQS_POISON
;
260 link
->wql_link
.left_setid
= WQL_LINK_POISON
;
261 link
->wql_link
.right_setid
= WQL_LINK_POISON
;
266 #ifdef KEEP_WAITQ_LINK_STATS
267 memset(link
->sl_alloc_bt
, 0, sizeof(link
->sl_alloc_bt
));
268 link
->sl_alloc_ts
= 0;
269 memset(link
->sl_mkvalid_bt
, 0, sizeof(link
->sl_mkvalid_bt
));
270 link
->sl_mkvalid_ts
= 0;
272 link
->sl_alloc_th
= THREAD_NULL
;
273 /* leave the sl_alloc_task in place for debugging */
275 link
->sl_free_ts
= mach_absolute_time();
279 #ifdef KEEP_WAITQ_LINK_STATS
280 static __inline__
void
281 wql_do_alloc_stats(struct lt_elem
*elem
)
284 struct waitq_link
*link
= (struct waitq_link
*)elem
;
285 memset(link
->sl_alloc_bt
, 0, sizeof(link
->sl_alloc_bt
));
286 waitq_grab_backtrace(link
->sl_alloc_bt
, 0);
287 link
->sl_alloc_th
= current_thread();
288 link
->sl_alloc_task
= current_task();
290 assert(link
->sl_alloc_ts
== 0);
291 link
->sl_alloc_ts
= mach_absolute_time();
293 memset(link
->sl_invalidate_bt
, 0, sizeof(link
->sl_invalidate_bt
));
294 link
->sl_invalidate_ts
= 0;
298 static __inline__
void
299 wql_do_invalidate_stats(struct lt_elem
*elem
)
301 struct waitq_link
*link
= (struct waitq_link
*)elem
;
307 assert(link
->sl_mkvalid_ts
> 0);
309 memset(link
->sl_invalidate_bt
, 0, sizeof(link
->sl_invalidate_bt
));
310 link
->sl_invalidate_ts
= mach_absolute_time();
311 waitq_grab_backtrace(link
->sl_invalidate_bt
, 0);
314 static __inline__
void
315 wql_do_mkvalid_stats(struct lt_elem
*elem
)
317 struct waitq_link
*link
= (struct waitq_link
*)elem
;
323 memset(link
->sl_mkvalid_bt
, 0, sizeof(link
->sl_mkvalid_bt
));
324 link
->sl_mkvalid_ts
= mach_absolute_time();
325 waitq_grab_backtrace(link
->sl_mkvalid_bt
, 0);
328 #define wql_do_alloc_stats(e)
329 #define wql_do_invalidate_stats(e)
330 #define wql_do_mkvalid_stats(e)
331 #endif /* KEEP_WAITQ_LINK_STATS */
336 uint32_t tablesz
= 0, max_links
= 0;
338 if (PE_parse_boot_argn("wql_tsize", &tablesz
, sizeof(tablesz
)) != TRUE
) {
339 tablesz
= (uint32_t)g_lt_max_tbl_size
;
342 tablesz
= P2ROUNDUP(tablesz
, PAGE_SIZE
);
343 max_links
= tablesz
/ sizeof(struct waitq_link
);
344 assert(max_links
> 0 && tablesz
> 0);
346 /* we have a restricted index range */
347 if (max_links
> (LT_IDX_MAX
+ 1)) {
348 max_links
= LT_IDX_MAX
+ 1;
351 wqinfo("init linktable with max:%d elements (%d bytes)",
353 ltable_init(&g_wqlinktable
, "wqslab.wql", max_links
,
354 sizeof(struct waitq_link
), wql_poison
);
358 wql_ensure_free_space(void)
360 if (g_wqlinktable
.nelem
- g_wqlinktable
.used_elem
< g_min_free_table_elem
) {
362 * we don't hold locks on these values, so check for underflow
364 if (g_wqlinktable
.used_elem
<= g_wqlinktable
.nelem
) {
365 wqdbg_v("Forcing table growth: nelem=%d, used=%d, min_free=%d",
366 g_wqlinktable
.nelem
, g_wqlinktable
.used_elem
,
367 g_min_free_table_elem
);
368 ltable_grow(&g_wqlinktable
, g_min_free_table_elem
);
373 static struct waitq_link
*
374 wql_alloc_link(int type
)
376 struct lt_elem
*elem
;
378 elem
= ltable_alloc_elem(&g_wqlinktable
, type
, 1, 0);
379 wql_do_alloc_stats(elem
);
380 return (struct waitq_link
*)elem
;
384 wql_realloc_link(struct waitq_link
*link
, int type
)
386 ltable_realloc_elem(&g_wqlinktable
, &link
->wqte
, type
);
387 #ifdef KEEP_WAITQ_LINK_STATS
388 memset(link
->sl_alloc_bt
, 0, sizeof(link
->sl_alloc_bt
));
389 link
->sl_alloc_ts
= 0;
390 wql_do_alloc_stats(&link
->wqte
);
392 memset(link
->sl_invalidate_bt
, 0, sizeof(link
->sl_invalidate_bt
));
393 link
->sl_invalidate_ts
= 0;
398 wql_invalidate(struct waitq_link
*link
)
400 lt_elem_invalidate(&link
->wqte
);
401 wql_do_invalidate_stats(&link
->wqte
);
404 static struct waitq_link
*
405 wql_get_link(uint64_t setid
)
407 struct lt_elem
*elem
;
409 elem
= ltable_get_elem(&g_wqlinktable
, setid
);
410 return (struct waitq_link
*)elem
;
414 wql_put_link(struct waitq_link
*link
)
419 ltable_put_elem(&g_wqlinktable
, (struct lt_elem
*)link
);
422 static struct waitq_link
*
423 wql_get_reserved(uint64_t setid
, int type
)
425 struct lt_elem
*elem
;
427 elem
= lt_elem_list_first(&g_wqlinktable
, setid
);
431 ltable_realloc_elem(&g_wqlinktable
, elem
, type
);
432 return (struct waitq_link
*)elem
;
436 static inline int waitq_maybe_remove_link(struct waitq
*waitq
,
438 struct waitq_link
*parent
,
439 struct waitq_link
*left
,
440 struct waitq_link
*right
);
443 LINK_WALK_ONE_LEVEL
= 0,
444 LINK_WALK_FULL_DAG
= 1,
445 LINK_WALK_FULL_DAG_UNLOCKED
= 2,
448 typedef int (*wql_callback_func
)(struct waitq
*waitq
, void *ctx
,
449 struct waitq_link
*link
);
452 * walk_waitq_links: walk all table elements (of type 'link_type') pointed to by 'setid'
455 * waitq is locked (or NULL)
456 * 'setid' is managed by 'waitq'
457 * this could be direct (waitq->waitq_set_id == setid)
458 * OR indirect (setid is the left/right ID in a LINK chain,
459 * whose root is waitq->waitq_set_id)
462 * This function uses recursion to walk the set of table elements
463 * pointed to by 'setid'. For each element encountered, 'cb' will be
464 * called. If non-zero, the return value of this callback function can
465 * early-out of the table walk.
467 * For each link element encountered, the function takes a reference to
468 * it. The reference is dropped only after the callback and any recursion
471 * The assumed table/link/tree structure:
480 * /\ /\ ... ... ... ...
483 * WQS(wqset_q.waitq_setid == Sx)
484 * [waitq set is a membet of setid, 'Sx')
493 * The basic algorithm is as follows:
494 * *) take a reference to the table object pointed to by 'setid'
495 * *) if appropriate, call 'cb' (potentially early-out on non-zero return)
496 * *) if the link object points to a waitq set, and the walk type
497 * is 'FULL_DAG' (full directed-acyclic-graph), then try to lock
498 * the associated waitq set object and recursively walk all sets to
499 * which that set belongs. This is a DFS of the tree structure.
500 * *) recurse down the left side of the tree (following the
501 * 'left_setid' pointer in the link object
502 * *) recurse down the right side of the tree (following the
503 * 'right_setid' pointer in the link object
505 static __attribute__((noinline
))
507 walk_waitq_links(int walk_type
, struct waitq
*waitq
,
508 uint64_t setid
, int link_type
,
509 void *ctx
, wql_callback_func cb
)
511 struct waitq_link
*link
;
515 link
= wql_get_link(setid
);
519 return WQ_ITERATE_CONTINUE
;
523 wqltype
= wql_type(link
);
524 if (wqltype
== WQL_LINK
) {
525 setid
= link
->wql_link
.left_setid
;
526 nextid
= link
->wql_link
.right_setid
;
530 * Make the callback only on specified link_type (or all links)
531 * Note that after the callback, the link object may be
532 * invalid. The only valid thing we can do is put our
533 * reference to it (which may put it back on the free list)
535 if (link_type
== WQL_ALL
|| link_type
== wqltype
) {
536 /* allow the callback to early-out */
537 int ret
= cb(waitq
, ctx
, link
);
538 if (ret
!= WQ_ITERATE_CONTINUE
) {
544 if (wqltype
== WQL_WQS
&&
545 (walk_type
== LINK_WALK_FULL_DAG
||
546 walk_type
== LINK_WALK_FULL_DAG_UNLOCKED
)) {
548 * Recurse down any sets to which this wait queue set was
549 * added. We do this just before we put our reference to
550 * the link object (which may free it).
552 struct waitq_set
*wqset
= link
->wql_wqs
.wql_set
;
553 int ret
= WQ_ITERATE_CONTINUE
;
554 int should_unlock
= 0;
555 uint64_t wqset_setid
= 0;
557 if (waitq_set_is_valid(wqset
) && walk_type
== LINK_WALK_FULL_DAG
) {
558 assert(!waitq_irq_safe(&wqset
->wqset_q
));
559 waitq_set_lock(wqset
);
564 * verify the linked waitq set as it could have been
565 * invalidated before we grabbed the lock!
567 if (wqset
->wqset_id
!= link
->wql_setid
.id
) {
568 /* This is the bottom of the tree: just get out */
570 waitq_set_unlock(wqset
);
573 return WQ_ITERATE_CONTINUE
;
576 wqset_setid
= wqset
->wqset_q
.waitq_set_id
;
578 if (wqset_setid
> 0) {
579 ret
= walk_waitq_links(walk_type
, &wqset
->wqset_q
,
580 wqset_setid
, link_type
, ctx
, cb
);
583 waitq_set_unlock(wqset
);
585 if (ret
!= WQ_ITERATE_CONTINUE
) {
593 /* recurse down left side of the tree */
595 int ret
= walk_waitq_links(walk_type
, waitq
, setid
, link_type
, ctx
, cb
);
596 if (ret
!= WQ_ITERATE_CONTINUE
) {
601 /* recurse down right side of the tree */
603 return walk_waitq_links(walk_type
, waitq
, nextid
, link_type
, ctx
, cb
);
606 return WQ_ITERATE_CONTINUE
;
609 /* ----------------------------------------------------------------------
611 * Prepost Link Table Implementation
613 * ---------------------------------------------------------------------- */
614 static struct link_table g_prepost_table
;
616 enum wq_prepost_type
{
626 /* wqt_type == WQP_WQ (LT_ELEM) */
628 struct waitq
*wqp_wq_ptr
;
630 /* wqt_type == WQP_POST (LT_LINK) */
632 uint64_t wqp_next_id
;
636 #ifdef KEEP_WAITQ_PREPOST_STATS
637 thread_t wqp_alloc_th
;
638 task_t wqp_alloc_task
;
639 uintptr_t wqp_alloc_bt
[NWAITQ_BTFRAMES
];
642 #if !defined(KEEP_WAITQ_PREPOST_STATS)
643 static_assert((sizeof(struct wq_prepost
) & (sizeof(struct wq_prepost
) - 1)) == 0,
644 "wq_prepost struct must be a power of two!");
647 #define wqp_refcnt(wqp) \
648 (lt_bits_refcnt((wqp)->wqte.lt_bits))
650 #define wqp_type(wqp) \
651 (lt_bits_type((wqp)->wqte.lt_bits))
653 #define wqp_set_valid(wqp) \
654 lt_elem_mkvalid(&(wqp)->wqte)
656 #define wqp_is_valid(wqp) \
657 lt_bits_valid((wqp)->wqte.lt_bits)
659 #define wqp_prepostid wqte.lt_id
661 #define WQP_WQ_POISON (0x0bad0badffffffffull)
662 #define WQP_POST_POISON (0xf00df00df00df00d)
665 wqp_poison(struct link_table
*table
, struct lt_elem
*elem
)
667 struct wq_prepost
*wqp
= (struct wq_prepost
*)elem
;
670 switch (wqp_type(wqp
)) {
674 wqp
->wqp_post
.wqp_next_id
= WQP_POST_POISON
;
675 wqp
->wqp_post
.wqp_wq_id
= WQP_POST_POISON
;
682 #ifdef KEEP_WAITQ_PREPOST_STATS
683 static __inline__
void
684 wqp_do_alloc_stats(struct lt_elem
*elem
)
690 struct wq_prepost
*wqp
= (struct wq_prepost
*)elem
;
691 uintptr_t alloc_bt
[sizeof(wqp
->wqp_alloc_bt
)];
693 waitq_grab_backtrace(alloc_bt
, NWAITQ_BTFRAMES
);
695 /* be sure the take stats for _all_ allocated objects */
697 memcpy(wqp
->wqp_alloc_bt
, alloc_bt
, sizeof(alloc_bt
));
698 wqp
->wqp_alloc_th
= current_thread();
699 wqp
->wqp_alloc_task
= current_task();
700 wqp
= (struct wq_prepost
*)lt_elem_list_next(&g_prepost_table
, &wqp
->wqte
);
707 #define wqp_do_alloc_stats(e)
708 #endif /* KEEP_WAITQ_LINK_STATS */
713 uint32_t tablesz
= 0, max_wqp
= 0;
715 if (PE_parse_boot_argn("wqp_tsize", &tablesz
, sizeof(tablesz
)) != TRUE
) {
716 tablesz
= (uint32_t)g_lt_max_tbl_size
;
719 tablesz
= P2ROUNDUP(tablesz
, PAGE_SIZE
);
720 max_wqp
= tablesz
/ sizeof(struct wq_prepost
);
721 assert(max_wqp
> 0 && tablesz
> 0);
723 /* we have a restricted index range */
724 if (max_wqp
> (LT_IDX_MAX
+ 1)) {
725 max_wqp
= LT_IDX_MAX
+ 1;
728 wqinfo("init prepost table with max:%d elements (%d bytes)",
730 ltable_init(&g_prepost_table
, "wqslab.prepost", max_wqp
,
731 sizeof(struct wq_prepost
), wqp_poison
);
735 * Refill the per-CPU cache.
738 wq_prepost_refill_cpu_cache(uint32_t nalloc
)
740 struct lt_elem
*new_head
, *old_head
;
741 struct wqp_cache
*cache
;
743 /* require preemption enabled to allocate elements */
744 if (get_preemption_level() != 0) {
748 new_head
= ltable_alloc_elem(&g_prepost_table
,
749 LT_RESERVED
, nalloc
, 1);
750 if (new_head
== NULL
) {
754 disable_preemption();
755 cache
= PERCPU_GET(wqp_cache
);
757 /* check once more before putting these elements on the list */
758 if (cache
->avail
>= WQP_CACHE_MAX
) {
759 lt_elem_list_release(&g_prepost_table
, new_head
, LT_RESERVED
);
764 cache
->avail
+= nalloc
;
765 if (cache
->head
== 0 || cache
->head
== LT_IDX_MAX
) {
766 cache
->head
= new_head
->lt_id
.id
;
770 old_head
= lt_elem_list_first(&g_prepost_table
, cache
->head
);
771 (void)lt_elem_list_link(&g_prepost_table
, new_head
, old_head
);
772 cache
->head
= new_head
->lt_id
.id
;
780 wq_prepost_ensure_free_space(void)
784 struct wqp_cache
*cache
;
786 if (g_min_free_cache
== 0) {
787 g_min_free_cache
= (WQP_CACHE_MAX
* ml_wait_max_cpus());
791 * Ensure that we always have a pool of per-CPU prepost elements
793 disable_preemption();
794 cache
= PERCPU_GET(wqp_cache
);
795 free_elem
= cache
->avail
;
798 if (free_elem
< (WQP_CACHE_MAX
/ 3)) {
799 wq_prepost_refill_cpu_cache(WQP_CACHE_MAX
- free_elem
);
803 * Now ensure that we have a sufficient amount of free table space
805 free_elem
= g_prepost_table
.nelem
- g_prepost_table
.used_elem
;
806 min_free
= g_min_free_table_elem
+ g_min_free_cache
;
807 if (free_elem
< min_free
) {
809 * we don't hold locks on these values, so check for underflow
811 if (g_prepost_table
.used_elem
<= g_prepost_table
.nelem
) {
812 wqdbg_v("Forcing table growth: nelem=%d, used=%d, min_free=%d+%d",
813 g_prepost_table
.nelem
, g_prepost_table
.used_elem
,
814 g_min_free_table_elem
, g_min_free_cache
);
815 ltable_grow(&g_prepost_table
, min_free
);
820 static struct wq_prepost
*
821 wq_prepost_alloc(int type
, int nelem
)
823 struct lt_elem
*elem
;
824 struct wq_prepost
*wqp
;
825 struct wqp_cache
*cache
;
827 if (type
!= LT_RESERVED
) {
835 * First try to grab the elements from the per-CPU cache if we are
836 * allocating RESERVED elements
838 disable_preemption();
839 cache
= PERCPU_GET(wqp_cache
);
840 if (nelem
<= (int)cache
->avail
) {
841 struct lt_elem
*first
, *next
= NULL
;
844 cache
->avail
-= nelem
;
846 /* grab the first element */
847 first
= lt_elem_list_first(&g_prepost_table
, cache
->head
);
849 /* find the last element and re-adjust the cache head */
850 for (elem
= first
; elem
!= NULL
&& nalloc
> 0; elem
= next
) {
851 next
= lt_elem_list_next(&g_prepost_table
, elem
);
853 /* terminate the allocated list */
854 elem
->lt_next_idx
= LT_IDX_MAX
;
860 cache
->head
= LT_IDX_MAX
;
862 cache
->head
= next
->lt_id
.id
;
864 /* assert that we don't have mis-matched book keeping */
865 assert(!(cache
->head
== LT_IDX_MAX
&& cache
->avail
> 0));
873 /* fall-back to standard table allocation */
874 elem
= ltable_alloc_elem(&g_prepost_table
, type
, nelem
, 0);
880 wqp
= (struct wq_prepost
*)elem
;
881 wqp_do_alloc_stats(elem
);
886 wq_prepost_invalidate(struct wq_prepost
*wqp
)
888 lt_elem_invalidate(&wqp
->wqte
);
891 static struct wq_prepost
*
892 wq_prepost_get(uint64_t wqp_id
)
894 struct lt_elem
*elem
;
896 elem
= ltable_get_elem(&g_prepost_table
, wqp_id
);
897 return (struct wq_prepost
*)elem
;
901 wq_prepost_put(struct wq_prepost
*wqp
)
903 ltable_put_elem(&g_prepost_table
, (struct lt_elem
*)wqp
);
907 wq_prepost_rlink(struct wq_prepost
*parent
, struct wq_prepost
*child
)
909 return lt_elem_list_link(&g_prepost_table
, &parent
->wqte
, &child
->wqte
);
912 static struct wq_prepost
*
913 wq_prepost_get_rnext(struct wq_prepost
*head
)
915 struct lt_elem
*elem
;
916 struct wq_prepost
*wqp
;
919 elem
= lt_elem_list_next(&g_prepost_table
, &head
->wqte
);
924 elem
= ltable_get_elem(&g_prepost_table
, id
);
929 wqp
= (struct wq_prepost
*)elem
;
930 if (elem
->lt_id
.id
!= id
||
931 wqp_type(wqp
) != WQP_POST
||
932 wqp
->wqp_post
.wqp_next_id
!= head
->wqp_prepostid
.id
) {
933 ltable_put_elem(&g_prepost_table
, elem
);
941 wq_prepost_reset_rnext(struct wq_prepost
*wqp
)
943 (void)lt_elem_list_break(&g_prepost_table
, &wqp
->wqte
);
948 * remove 'wqp' from the prepost list on 'wqset'
952 * caller holds a reference on wqp (and is responsible to release it)
955 * wqp is invalidated, wqset is potentially updated with a new
956 * prepost ID, and the next element of the prepost list may be
957 * consumed as well (if the list contained only 2 objects)
960 wq_prepost_remove(struct waitq_set
*wqset
,
961 struct wq_prepost
*wqp
)
964 uint64_t next_id
= wqp
->wqp_post
.wqp_next_id
;
965 uint64_t wqp_id
= wqp
->wqp_prepostid
.id
;
966 struct wq_prepost
*prev_wqp
, *next_wqp
;
968 assert(wqp_type(wqp
) == WQP_POST
);
969 assert(wqset
->wqset_q
.waitq_prepost
== 1);
971 if (next_id
== wqp_id
) {
972 /* the list is singular and becoming empty */
973 wqset
->wqset_prepost_id
= 0;
978 prev_wqp
= wq_prepost_get_rnext(wqp
);
979 assert(prev_wqp
!= NULL
);
980 assert(prev_wqp
->wqp_post
.wqp_next_id
== wqp_id
);
981 assert(prev_wqp
->wqp_prepostid
.id
!= wqp_id
);
982 assert(wqp_type(prev_wqp
) == WQP_POST
);
984 if (prev_wqp
->wqp_prepostid
.id
== next_id
) {
986 * There are two items in the list, and we're removing one. We
987 * only need to keep the WQP_WQ pointer from 'prev_wqp'
989 wqset
->wqset_prepost_id
= prev_wqp
->wqp_post
.wqp_wq_id
;
990 wq_prepost_invalidate(prev_wqp
);
991 wq_prepost_put(prev_wqp
);
996 /* prev->next = next */
997 prev_wqp
->wqp_post
.wqp_next_id
= next_id
;
999 /* next->prev = prev */
1000 next_wqp
= wq_prepost_get(next_id
);
1001 assert(next_wqp
!= NULL
);
1002 assert(next_wqp
!= wqp
);
1003 assert(next_wqp
!= prev_wqp
);
1004 assert(wqp_type(next_wqp
) == WQP_POST
);
1006 wq_prepost_reset_rnext(next_wqp
);
1007 wq_prepost_rlink(next_wqp
, prev_wqp
);
1009 /* If we remove the head of the list, update the wqset */
1010 if (wqp_id
== wqset
->wqset_prepost_id
) {
1011 wqset
->wqset_prepost_id
= next_id
;
1014 wq_prepost_put(prev_wqp
);
1015 wq_prepost_put(next_wqp
);
1018 wq_prepost_reset_rnext(wqp
);
1019 wq_prepost_invalidate(wqp
);
1023 static struct wq_prepost
*
1024 wq_prepost_rfirst(uint64_t id
)
1026 struct lt_elem
*elem
;
1027 elem
= lt_elem_list_first(&g_prepost_table
, id
);
1028 wqp_do_alloc_stats(elem
);
1029 return (struct wq_prepost
*)(void *)elem
;
1032 static struct wq_prepost
*
1033 wq_prepost_rpop(uint64_t *id
, int type
)
1035 struct lt_elem
*elem
;
1036 elem
= lt_elem_list_pop(&g_prepost_table
, id
, type
);
1037 wqp_do_alloc_stats(elem
);
1038 return (struct wq_prepost
*)(void *)elem
;
1042 wq_prepost_release_rlist(struct wq_prepost
*wqp
)
1045 struct wqp_cache
*cache
;
1046 struct lt_elem
*elem
;
1055 * These are reserved elements: release them back to the per-cpu pool
1056 * if our cache is running low.
1058 disable_preemption();
1059 cache
= PERCPU_GET(wqp_cache
);
1060 if (cache
->avail
< WQP_CACHE_MAX
) {
1061 struct lt_elem
*tmp
= NULL
;
1062 if (cache
->head
!= LT_IDX_MAX
) {
1063 tmp
= lt_elem_list_first(&g_prepost_table
, cache
->head
);
1065 nelem
= lt_elem_list_link(&g_prepost_table
, elem
, tmp
);
1066 cache
->head
= elem
->lt_id
.id
;
1067 cache
->avail
+= nelem
;
1068 enable_preemption();
1071 enable_preemption();
1073 /* release these elements back to the main table */
1074 nelem
= lt_elem_list_release(&g_prepost_table
, elem
, LT_RESERVED
);
1076 #if CONFIG_WAITQ_STATS
1077 g_prepost_table
.nreserved_releases
+= 1;
1078 OSDecrementAtomic64(&g_prepost_table
.nreservations
);
1082 typedef int (*wqp_callback_func
)(struct waitq_set
*wqset
,
1084 struct wq_prepost
*wqp
,
1085 struct waitq
*waitq
);
1088 * iterate over a chain of preposts associated with a waitq set.
1094 * This loop performs automatic prepost chain management / culling, and
1095 * may reset or adjust the waitq set's prepost ID pointer. If you don't
1096 * want this extra processing, you can use wq_prepost_iterate().
1099 wq_prepost_foreach_locked(struct waitq_set
*wqset
,
1100 void *ctx
, wqp_callback_func cb
)
1102 int ret
= WQ_ITERATE_SUCCESS
;
1103 struct wq_prepost
*wqp
, *tmp_wqp
;
1107 if (!wqset
|| !waitq_set_maybe_preposted(wqset
)) {
1108 return WQ_ITERATE_SUCCESS
;
1112 wqp
= wq_prepost_get(wqset
->wqset_prepost_id
);
1115 * The prepost object is no longer valid, reset the waitq
1118 wqset
->wqset_prepost_id
= 0;
1119 return WQ_ITERATE_SUCCESS
;
1122 if (wqp_type(wqp
) == WQP_WQ
) {
1123 uint64_t __assert_only wqp_id
= wqp
->wqp_prepostid
.id
;
1125 ret
= cb(wqset
, ctx
, wqp
, wqp
->wqp_wq
.wqp_wq_ptr
);
1128 case WQ_ITERATE_INVALIDATE_CONTINUE
:
1129 /* the caller wants to remove the only prepost here */
1130 assert(wqp_id
== wqset
->wqset_prepost_id
);
1131 wqset
->wqset_prepost_id
= 0;
1133 case WQ_ITERATE_CONTINUE
:
1134 wq_prepost_put(wqp
);
1135 ret
= WQ_ITERATE_SUCCESS
;
1137 case WQ_ITERATE_RESTART
:
1138 wq_prepost_put(wqp
);
1140 case WQ_ITERATE_DROPPED
:
1143 wq_prepost_put(wqp
);
1149 assert(wqp
->wqp_prepostid
.id
== wqset
->wqset_prepost_id
);
1150 assert(wqp_type(wqp
) == WQP_POST
);
1153 * At this point we know we have a list of POST objects.
1154 * Grab a handle to the last element in the list and start
1157 tmp_wqp
= wq_prepost_get_rnext(wqp
);
1158 assert(tmp_wqp
!= NULL
&& wqp_type(tmp_wqp
) == WQP_POST
);
1160 uint64_t last_id
= tmp_wqp
->wqp_prepostid
.id
;
1161 wq_prepost_put(tmp_wqp
);
1163 ret
= WQ_ITERATE_SUCCESS
;
1165 uint64_t wqp_id
, first_id
, next_id
;
1167 wqp_id
= wqp
->wqp_prepostid
.id
;
1168 first_id
= wqset
->wqset_prepost_id
;
1169 next_id
= wqp
->wqp_post
.wqp_next_id
;
1171 /* grab the WQP_WQ object this _POST points to */
1172 tmp_wqp
= wq_prepost_get(wqp
->wqp_post
.wqp_wq_id
);
1175 * This WQP_POST object points to an invalid
1176 * WQP_WQ object - remove the POST object from
1179 if (wq_prepost_remove(wqset
, wqp
) == 0) {
1180 wq_prepost_put(wqp
);
1185 assert(wqp_type(tmp_wqp
) == WQP_WQ
);
1187 * make the callback: note that this could remove 'wqp' or
1188 * drop the lock on our waitq set. We need to re-validate
1189 * our state when this function returns.
1191 ret
= cb(wqset
, ctx
, wqp
, tmp_wqp
->wqp_wq
.wqp_wq_ptr
);
1192 wq_prepost_put(tmp_wqp
);
1195 case WQ_ITERATE_CONTINUE
:
1196 /* continue iteration */
1198 case WQ_ITERATE_INVALIDATE_CONTINUE
:
1199 assert(next_id
== wqp
->wqp_post
.wqp_next_id
);
1200 if (wq_prepost_remove(wqset
, wqp
) == 0) {
1201 wq_prepost_put(wqp
);
1205 case WQ_ITERATE_RESTART
:
1206 wq_prepost_put(wqp
);
1208 case WQ_ITERATE_DROPPED
:
1209 /* the callback dropped the ref to wqp: just restart */
1212 /* break out of the iteration for some other reason */
1213 goto finish_prepost_foreach
;
1217 * the set lock may have been dropped during callback,
1218 * if something looks different, restart the prepost iteration
1220 if (!wqp_is_valid(wqp
) ||
1221 (wqp
->wqp_post
.wqp_next_id
!= next_id
) ||
1222 wqset
->wqset_prepost_id
!= first_id
) {
1223 wq_prepost_put(wqp
);
1228 /* this was the last object in the list */
1229 if (wqp_id
== last_id
) {
1233 /* get the next object */
1234 tmp_wqp
= wq_prepost_get(next_id
);
1237 * At this point we've already checked our state
1238 * after the callback (which may have dropped the set
1239 * lock). If we find an invalid member of the list
1240 * then something is wrong.
1242 panic("Invalid WQP_POST member 0x%llx in waitq set "
1243 "0x%llx prepost list (first:%llx, "
1245 next_id
, wqset
->wqset_id
, first_id
, wqp
);
1247 wq_prepost_put(wqp
);
1250 assert(wqp_type(wqp
) == WQP_POST
);
1253 finish_prepost_foreach
:
1254 wq_prepost_put(wqp
);
1255 if (ret
== WQ_ITERATE_CONTINUE
) {
1256 ret
= WQ_ITERATE_SUCCESS
;
1263 * Perform a simple loop over a chain of prepost objects
1266 * If 'prepost_id' is associated with a waitq (set) then that object must
1267 * be locked before calling this function.
1268 * Callback function, 'cb', must be able to handle a NULL wqset pointer
1269 * and a NULL waitq pointer!
1272 * This prepost chain iteration will _not_ automatically adjust any chain
1273 * element or linkage. This is the responsibility of the caller! If you
1274 * want automatic prepost chain management (at a cost of extra CPU time),
1275 * you can use: wq_prepost_foreach_locked().
1278 wq_prepost_iterate(uint64_t prepost_id
,
1279 void *ctx
, wqp_callback_func cb
)
1282 struct wq_prepost
*wqp
;
1285 return WQ_ITERATE_SUCCESS
;
1288 wqp
= wq_prepost_get(prepost_id
);
1290 return WQ_ITERATE_SUCCESS
;
1293 if (wqp_type(wqp
) == WQP_WQ
) {
1294 ret
= WQ_ITERATE_SUCCESS
;
1296 ret
= cb(NULL
, ctx
, wqp
, wqp
->wqp_wq
.wqp_wq_ptr
);
1299 if (ret
!= WQ_ITERATE_DROPPED
) {
1300 wq_prepost_put(wqp
);
1305 assert(wqp
->wqp_prepostid
.id
== prepost_id
);
1306 assert(wqp_type(wqp
) == WQP_POST
);
1308 /* at this point we know we have a list of POST objects */
1311 ret
= WQ_ITERATE_CONTINUE
;
1313 struct wq_prepost
*tmp_wqp
;
1314 struct waitq
*wq
= NULL
;
1316 next_id
= wqp
->wqp_post
.wqp_next_id
;
1318 /* grab the WQP_WQ object this _POST points to */
1319 tmp_wqp
= wq_prepost_get(wqp
->wqp_post
.wqp_wq_id
);
1321 assert(wqp_type(tmp_wqp
) == WQP_WQ
);
1322 wq
= tmp_wqp
->wqp_wq
.wqp_wq_ptr
;
1326 ret
= cb(NULL
, ctx
, wqp
, wq
);
1329 wq_prepost_put(tmp_wqp
);
1332 if (ret
!= WQ_ITERATE_CONTINUE
) {
1336 tmp_wqp
= wq_prepost_get(next_id
);
1339 * the chain is broken: nothing we can do here besides
1340 * bail from the iteration.
1342 ret
= WQ_ITERATE_ABORTED
;
1346 wq_prepost_put(wqp
);
1349 assert(wqp_type(wqp
) == WQP_POST
);
1350 } while (next_id
!= prepost_id
);
1352 if (ret
!= WQ_ITERATE_DROPPED
) {
1353 wq_prepost_put(wqp
);
1356 if (ret
== WQ_ITERATE_CONTINUE
) {
1357 ret
= WQ_ITERATE_SUCCESS
;
1363 struct _is_posted_ctx
{
1364 struct waitq
*posting_wq
;
1369 wq_is_preposted_on_set_cb(struct waitq_set
*wqset
, void *ctx
,
1370 struct wq_prepost
*wqp
, struct waitq
*waitq
)
1372 struct _is_posted_ctx
*pctx
= (struct _is_posted_ctx
*)ctx
;
1378 * Don't early-out, run through the _entire_ list:
1379 * This ensures that we retain a minimum number of invalid elements.
1381 if (pctx
->posting_wq
== waitq
) {
1382 pctx
->did_prepost
= 1;
1385 return WQ_ITERATE_CONTINUE
;
1390 * checks if 'waitq' has already preposted on 'wqset'
1393 * waitq The waitq that's preposting
1394 * wqset The set onto which waitq may be preposted
1397 * both waitq and wqset are locked
1399 * Returns non-zero if 'waitq' has already preposted to 'wqset'
1402 wq_is_preposted_on_set(struct waitq
*waitq
, struct waitq_set
*wqset
)
1405 struct _is_posted_ctx pctx
;
1408 * If the set's only prepost matches the waitq's prepost ID,
1409 * then it obviously already preposted to the set.
1411 if (waitq
->waitq_prepost_id
!= 0 &&
1412 wqset
->wqset_prepost_id
== waitq
->waitq_prepost_id
) {
1416 /* use full prepost iteration: always trim the list */
1417 pctx
.posting_wq
= waitq
;
1418 pctx
.did_prepost
= 0;
1419 ret
= wq_prepost_foreach_locked(wqset
, (void *)&pctx
,
1420 wq_is_preposted_on_set_cb
);
1421 return pctx
.did_prepost
;
1424 static struct wq_prepost
*
1425 wq_get_prepost_obj(uint64_t *reserved
, int type
)
1427 struct wq_prepost
*wqp
= NULL
;
1429 * don't fail just because the caller doesn't have enough
1430 * reservations, we've kept a low-water mark on the prepost table,
1431 * so there should be some available for us.
1433 if (reserved
&& *reserved
) {
1434 wqp
= wq_prepost_rpop(reserved
, type
);
1435 assert(wqp
->wqte
.lt_id
.idx
< g_prepost_table
.nelem
);
1438 * TODO: if in interrupt context, grab from a special
1439 * region / reserved list!
1441 wqp
= wq_prepost_alloc(type
, 1);
1445 panic("Couldn't allocate prepost object!");
1452 * prepost a waitq onto a waitq set
1455 * wqset The set onto which waitq will be preposted
1456 * waitq The waitq that's preposting
1457 * reserved List (lt_elem_list_ style) of pre-allocated prepost elements
1461 * both wqset and waitq are locked
1464 * If reserved is NULL, this may block on prepost table growth.
1467 wq_prepost_do_post_locked(struct waitq_set
*wqset
,
1468 struct waitq
*waitq
,
1471 struct wq_prepost
*wqp_post
, *wqp_head
, *wqp_tail
;
1473 assert(waitq_held(waitq
) && waitq_held(&wqset
->wqset_q
));
1476 * nothing to do if it's already preposted:
1477 * note that this also culls any invalid prepost objects
1479 if (wq_is_preposted_on_set(waitq
, wqset
)) {
1483 assert(waitqs_is_linked(wqset
));
1486 * This function is called because an event is being posted to 'waitq'.
1487 * We need a prepost object associated with this queue. Allocate one
1488 * now if the waitq isn't already associated with one.
1490 if (waitq
->waitq_prepost_id
== 0) {
1491 struct wq_prepost
*wqp
;
1492 wqp
= wq_get_prepost_obj(reserved
, WQP_WQ
);
1493 wqp
->wqp_wq
.wqp_wq_ptr
= waitq
;
1495 waitq
->waitq_prepost_id
= wqp
->wqp_prepostid
.id
;
1496 wq_prepost_put(wqp
);
1499 #if CONFIG_LTABLE_STATS
1500 g_prepost_table
.npreposts
+= 1;
1503 wqdbg_v("preposting waitq %p (0x%llx) to set 0x%llx",
1504 (void *)VM_KERNEL_UNSLIDE_OR_PERM(waitq
),
1505 waitq
->waitq_prepost_id
, wqset
->wqset_id
);
1507 if (wqset
->wqset_prepost_id
== 0) {
1508 /* the set has no previous preposts */
1509 wqset
->wqset_prepost_id
= waitq
->waitq_prepost_id
;
1513 wqp_head
= wq_prepost_get(wqset
->wqset_prepost_id
);
1515 /* the previous prepost has become invalid */
1516 wqset
->wqset_prepost_id
= waitq
->waitq_prepost_id
;
1520 assert(wqp_head
->wqp_prepostid
.id
== wqset
->wqset_prepost_id
);
1523 * If we get here, we're going to need at least one new wq_prepost
1524 * object. If the previous wqset_prepost_id points to a WQP_WQ, we
1525 * actually need to allocate 2 wq_prepost objects because the WQP_WQ
1526 * is tied to the waitq and shared across all sets.
1528 wqp_post
= wq_get_prepost_obj(reserved
, WQP_POST
);
1530 wqp_post
->wqp_post
.wqp_wq_id
= waitq
->waitq_prepost_id
;
1531 wqdbg_v("POST 0x%llx :: WQ 0x%llx", wqp_post
->wqp_prepostid
.id
,
1532 waitq
->waitq_prepost_id
);
1534 if (wqp_type(wqp_head
) == WQP_WQ
) {
1536 * We must replace the wqset_prepost_id with a pointer
1537 * to two new WQP_POST objects
1539 uint64_t wqp_id
= wqp_head
->wqp_prepostid
.id
;
1540 wqdbg_v("set 0x%llx previous had 1 WQ prepost (0x%llx): "
1541 "replacing with two POST preposts",
1542 wqset
->wqset_id
, wqp_id
);
1544 /* drop the old reference */
1545 wq_prepost_put(wqp_head
);
1547 /* grab another new object (the 2nd of two) */
1548 wqp_head
= wq_get_prepost_obj(reserved
, WQP_POST
);
1550 /* point this one to the original WQP_WQ object */
1551 wqp_head
->wqp_post
.wqp_wq_id
= wqp_id
;
1552 wqdbg_v("POST 0x%llx :: WQ 0x%llx",
1553 wqp_head
->wqp_prepostid
.id
, wqp_id
);
1555 /* link it to the new wqp_post object allocated earlier */
1556 wqp_head
->wqp_post
.wqp_next_id
= wqp_post
->wqp_prepostid
.id
;
1557 /* make the list a double-linked and circular */
1558 wq_prepost_rlink(wqp_head
, wqp_post
);
1561 * Finish setting up the new prepost: point it back to the
1562 * POST object we allocated to replace the original wqset
1565 wqp_post
->wqp_post
.wqp_next_id
= wqp_head
->wqp_prepostid
.id
;
1566 wq_prepost_rlink(wqp_post
, wqp_head
);
1568 /* mark objects valid, and reset the wqset prepost list head */
1569 wqp_set_valid(wqp_head
);
1570 wqp_set_valid(wqp_post
);
1571 wqset
->wqset_prepost_id
= wqp_head
->wqp_prepostid
.id
;
1573 /* release both references */
1574 wq_prepost_put(wqp_head
);
1575 wq_prepost_put(wqp_post
);
1577 wqdbg_v("set 0x%llx: 0x%llx/0x%llx -> 0x%llx/0x%llx -> 0x%llx",
1578 wqset
->wqset_id
, wqset
->wqset_prepost_id
,
1579 wqp_head
->wqp_prepostid
.id
, wqp_head
->wqp_post
.wqp_next_id
,
1580 wqp_post
->wqp_prepostid
.id
,
1581 wqp_post
->wqp_post
.wqp_next_id
);
1585 assert(wqp_type(wqp_head
) == WQP_POST
);
1588 * Add the new prepost to the end of the prepost list
1590 wqp_tail
= wq_prepost_get_rnext(wqp_head
);
1591 assert(wqp_tail
!= NULL
);
1592 assert(wqp_tail
->wqp_post
.wqp_next_id
== wqset
->wqset_prepost_id
);
1595 * link the head to the new tail
1596 * NOTE: this needs to happen first in case wqp_tail == wqp_head
1598 wq_prepost_reset_rnext(wqp_head
);
1599 wq_prepost_rlink(wqp_head
, wqp_post
);
1601 /* point the new object to the list head, and list tail */
1602 wqp_post
->wqp_post
.wqp_next_id
= wqp_head
->wqp_prepostid
.id
;
1603 wq_prepost_rlink(wqp_post
, wqp_tail
);
1605 /* point the last item in the waitq set's list to the new object */
1606 wqp_tail
->wqp_post
.wqp_next_id
= wqp_post
->wqp_prepostid
.id
;
1608 wqp_set_valid(wqp_post
);
1610 wq_prepost_put(wqp_head
);
1611 wq_prepost_put(wqp_tail
);
1612 wq_prepost_put(wqp_post
);
1614 wqdbg_v("set 0x%llx (wqp:0x%llx) last_prepost:0x%llx, "
1615 "new_prepost:0x%llx->0x%llx", wqset
->wqset_id
,
1616 wqset
->wqset_prepost_id
, wqp_head
->wqp_prepostid
.id
,
1617 wqp_post
->wqp_prepostid
.id
, wqp_post
->wqp_post
.wqp_next_id
);
1623 /* ----------------------------------------------------------------------
1625 * Stats collection / reporting
1627 * ---------------------------------------------------------------------- */
1628 #if CONFIG_LTABLE_STATS && CONFIG_WAITQ_STATS
1630 wq_table_stats(struct link_table
*table
, struct wq_table_stats
*stats
)
1632 stats
->version
= WAITQ_STATS_VERSION
;
1633 stats
->table_elements
= table
->nelem
;
1634 stats
->table_used_elems
= table
->used_elem
;
1635 stats
->table_elem_sz
= table
->elem_sz
;
1636 stats
->table_slabs
= table
->nslabs
;
1637 stats
->table_slab_sz
= table
->slab_sz
;
1639 stats
->table_num_allocs
= table
->nallocs
;
1640 stats
->table_num_preposts
= table
->npreposts
;
1641 stats
->table_num_reservations
= table
->nreservations
;
1643 stats
->table_max_used
= table
->max_used
;
1644 stats
->table_avg_used
= table
->avg_used
;
1645 stats
->table_max_reservations
= table
->max_reservations
;
1646 stats
->table_avg_reservations
= table
->avg_reservations
;
1650 waitq_link_stats(struct wq_table_stats
*stats
)
1655 wq_table_stats(&g_wqlinktable
, stats
);
1659 waitq_prepost_stats(struct wq_table_stats
*stats
)
1661 wq_table_stats(&g_prepost_table
, stats
);
1666 /* ----------------------------------------------------------------------
1668 * Global Wait Queues
1670 * ---------------------------------------------------------------------- */
1672 static struct waitq g_boot_waitq
;
1673 static struct waitq
*global_waitqs
= &g_boot_waitq
;
1674 static uint32_t g_num_waitqs
= 1;
1677 * Zero out the used MSBs of the event.
1679 #define _CAST_TO_EVENT_MASK(event) ((uintptr_t)(event) & ((1ul << _EVENT_MASK_BITS) - 1ul))
1681 static __inline__
uint32_t
1682 waitq_hash(char *key
, size_t length
)
1684 uint32_t hash
= os_hash_jenkins(key
, length
);
1686 hash
&= (g_num_waitqs
- 1);
1690 /* return a global waitq pointer corresponding to the given event */
1692 _global_eventq(char *event
, size_t event_length
)
1694 return &global_waitqs
[waitq_hash(event
, event_length
)];
1697 /* return an indexed global waitq pointer */
1699 global_waitq(int index
)
1701 return &global_waitqs
[index
% g_num_waitqs
];
1705 #if CONFIG_LTABLE_STATS || CONFIG_WAITQ_STATS
1706 /* this global is for lldb */
1707 const uint32_t g_nwaitq_btframes
= NWAITQ_BTFRAMES
;
1709 static __inline__
void
1710 waitq_grab_backtrace(uintptr_t bt
[NWAITQ_BTFRAMES
], int skip
)
1712 uintptr_t buf
[NWAITQ_BTFRAMES
+ skip
];
1716 memset(buf
, 0, (NWAITQ_BTFRAMES
+ skip
) * sizeof(uintptr_t));
1717 backtrace(buf
, g_nwaitq_btframes
+ skip
, NULL
);
1718 memcpy(&bt
[0], &buf
[skip
], NWAITQ_BTFRAMES
* sizeof(uintptr_t));
1720 #else /* no stats */
1721 #define waitq_grab_backtrace(...)
1724 #if CONFIG_WAITQ_STATS
1726 struct wq_stats g_boot_stats
;
1727 struct wq_stats
*g_waitq_stats
= &g_boot_stats
;
1729 static __inline__
struct wq_stats
*
1730 waitq_global_stats(struct waitq
*waitq
)
1732 struct wq_stats
*wqs
;
1735 if (!waitq_is_global(waitq
)) {
1739 idx
= (uint32_t)(((uintptr_t)waitq
- (uintptr_t)global_waitqs
) / sizeof(*waitq
));
1740 assert(idx
< g_num_waitqs
);
1741 wqs
= &g_waitq_stats
[idx
];
1745 static __inline__
void
1746 waitq_stats_count_wait(struct waitq
*waitq
)
1748 struct wq_stats
*wqs
= waitq_global_stats(waitq
);
1751 waitq_grab_backtrace(wqs
->last_wait
, 2);
1755 static __inline__
void
1756 waitq_stats_count_wakeup(struct waitq
*waitq
)
1758 struct wq_stats
*wqs
= waitq_global_stats(waitq
);
1761 waitq_grab_backtrace(wqs
->last_wakeup
, 2);
1765 static __inline__
void
1766 waitq_stats_count_clear_wakeup(struct waitq
*waitq
)
1768 struct wq_stats
*wqs
= waitq_global_stats(waitq
);
1772 waitq_grab_backtrace(wqs
->last_wakeup
, 2);
1776 static __inline__
void
1777 waitq_stats_count_fail(struct waitq
*waitq
)
1779 struct wq_stats
*wqs
= waitq_global_stats(waitq
);
1781 wqs
->failed_wakeups
++;
1782 waitq_grab_backtrace(wqs
->last_failed_wakeup
, 2);
1785 #else /* !CONFIG_WAITQ_STATS */
1786 #define waitq_stats_count_wait(q) do { } while (0)
1787 #define waitq_stats_count_wakeup(q) do { } while (0)
1788 #define waitq_stats_count_clear_wakeup(q) do { } while (0)
1789 #define waitq_stats_count_fail(q) do { } while (0)
1793 waitq_is_valid(struct waitq
*waitq
)
1795 return (waitq
!= NULL
) && waitq
->waitq_isvalid
;
1799 waitq_set_is_valid(struct waitq_set
*wqset
)
1801 return (wqset
!= NULL
) && wqset
->wqset_q
.waitq_isvalid
&& waitqs_is_set(wqset
);
1805 waitq_is_global(struct waitq
*waitq
)
1807 if (waitq
>= global_waitqs
&& waitq
< global_waitqs
+ g_num_waitqs
) {
1814 waitq_irq_safe(struct waitq
*waitq
)
1816 /* global wait queues have this bit set on initialization */
1817 return waitq
->waitq_irq
;
1821 waitq_empty(struct waitq
*wq
)
1823 if (waitq_is_turnstile_queue(wq
)) {
1824 return priority_queue_empty(&wq
->waitq_prio_queue
);
1825 } else if (waitq_is_turnstile_proxy(wq
)) {
1826 struct turnstile
*ts
= wq
->waitq_ts
;
1827 return ts
== TURNSTILE_NULL
||
1828 priority_queue_empty(&ts
->ts_waitq
.waitq_prio_queue
);
1830 return queue_empty(&wq
->waitq_queue
);
1834 static struct waitq
*
1835 waitq_get_safeq(struct waitq
*waitq
)
1837 /* Check if it's a port waitq */
1838 if (waitq_is_turnstile_proxy(waitq
)) {
1839 struct turnstile
*ts
= waitq
->waitq_ts
;
1840 return ts
? &ts
->ts_waitq
: NULL
;
1842 return global_eventq(waitq
);
1846 waitq_hash_size(void)
1848 uint32_t hsize
, queues
;
1850 if (PE_parse_boot_argn("wqsize", &hsize
, sizeof(hsize
))) {
1854 queues
= thread_max
/ 5;
1855 hsize
= P2ROUNDUP(queues
* sizeof(struct waitq
), PAGE_SIZE
);
1861 * Since the priority ordered waitq uses basepri as the
1862 * ordering key assert that this value fits in a uint8_t.
1864 static_assert(MAXPRI
<= UINT8_MAX
);
1867 waitq_thread_insert(struct waitq
*wq
,
1868 thread_t thread
, boolean_t fifo
)
1870 if (waitq_is_turnstile_queue(wq
)) {
1871 turnstile_stats_update(0, TSU_TURNSTILE_BLOCK_COUNT
, NULL
);
1872 turnstile_waitq_add_thread_priority_queue(wq
, thread
);
1874 turnstile_stats_update(0, TSU_REGULAR_WAITQ_BLOCK_COUNT
, NULL
);
1876 enqueue_tail(&wq
->waitq_queue
, &thread
->wait_links
);
1878 enqueue_head(&wq
->waitq_queue
, &thread
->wait_links
);
1884 waitq_thread_remove(struct waitq
*wq
,
1887 if (waitq_is_turnstile_queue(wq
)) {
1888 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
1889 (TURNSTILE_CODE(TURNSTILE_HEAP_OPERATIONS
, (THREAD_REMOVED_FROM_TURNSTILE_WAITQ
))) | DBG_FUNC_NONE
,
1890 VM_KERNEL_UNSLIDE_OR_PERM(waitq_to_turnstile(wq
)),
1893 priority_queue_remove(&wq
->waitq_prio_queue
, &thread
->wait_prioq_links
);
1895 remqueue(&(thread
->wait_links
));
1900 waitq_bootstrap(void)
1903 uint32_t whsize
, qsz
, tmp32
;
1905 g_min_free_table_elem
= DEFAULT_MIN_FREE_TABLE_ELEM
;
1906 if (PE_parse_boot_argn("wqt_min_free", &tmp32
, sizeof(tmp32
)) == TRUE
) {
1907 g_min_free_table_elem
= tmp32
;
1909 wqdbg("Minimum free table elements: %d", tmp32
);
1912 * Determine the amount of memory we're willing to reserve for
1913 * the waitqueue hash table
1915 whsize
= waitq_hash_size();
1917 /* Determine the number of waitqueues we can fit. */
1918 qsz
= sizeof(struct waitq
);
1919 whsize
= ROUNDDOWN(whsize
, qsz
);
1920 g_num_waitqs
= whsize
/ qsz
;
1923 * The hash algorithm requires that this be a power of 2, so we
1924 * just mask off all the low-order bits.
1926 for (uint32_t i
= 0; i
< 31; i
++) {
1927 uint32_t bit
= (1 << i
);
1928 if ((g_num_waitqs
& bit
) == g_num_waitqs
) {
1931 g_num_waitqs
&= ~bit
;
1933 assert(g_num_waitqs
> 0);
1935 /* Now determine how much memory we really need. */
1936 whsize
= P2ROUNDUP(g_num_waitqs
* qsz
, PAGE_SIZE
);
1938 wqdbg("allocating %d global queues (%d bytes)", g_num_waitqs
, whsize
);
1939 kret
= kernel_memory_allocate(kernel_map
, (vm_offset_t
*)&global_waitqs
,
1940 whsize
, 0, KMA_KOBJECT
| KMA_NOPAGEWAIT
, VM_KERN_MEMORY_WAITQ
);
1941 if (kret
!= KERN_SUCCESS
|| global_waitqs
== NULL
) {
1942 panic("kernel_memory_allocate() failed to alloc global_waitqs"
1943 ", error: %d, whsize: 0x%x", kret
, whsize
);
1946 #if CONFIG_WAITQ_STATS
1947 whsize
= P2ROUNDUP(g_num_waitqs
* sizeof(struct wq_stats
), PAGE_SIZE
);
1948 kret
= kernel_memory_allocate(kernel_map
, (vm_offset_t
*)&g_waitq_stats
,
1949 whsize
, 0, KMA_KOBJECT
| KMA_NOPAGEWAIT
, VM_KERN_MEMORY_WAITQ
);
1950 if (kret
!= KERN_SUCCESS
|| global_waitqs
== NULL
) {
1951 panic("kernel_memory_allocate() failed to alloc g_waitq_stats"
1952 ", error: %d, whsize: 0x%x", kret
, whsize
);
1954 memset(g_waitq_stats
, 0, whsize
);
1957 for (uint32_t i
= 0; i
< g_num_waitqs
; i
++) {
1958 waitq_init(&global_waitqs
[i
], SYNC_POLICY_FIFO
| SYNC_POLICY_DISABLE_IRQ
);
1961 /* initialize the global waitq link table */
1964 /* initialize the global waitq prepost table */
1969 /* ----------------------------------------------------------------------
1971 * Wait Queue Implementation
1973 * ---------------------------------------------------------------------- */
1976 * Double the standard lock timeout, because wait queues tend
1977 * to iterate over a number of threads - locking each. If there is
1978 * a problem with a thread lock, it normally times out at the wait
1979 * queue level first, hiding the real problem.
1981 /* For x86, the hardware timeout is in TSC units. */
1982 #if defined(__i386__) || defined(__x86_64__)
1983 #define hwLockTimeOut LockTimeOutTSC
1985 #define hwLockTimeOut LockTimeOut
1989 waitq_lock(struct waitq
*wq
)
1991 if (__improbable(waitq_lock_to(wq
,
1992 hwLockTimeOut
* 2) == 0)) {
1993 boolean_t wql_acquired
= FALSE
;
1995 while (machine_timeout_suspended()) {
1996 mp_enable_preemption();
1997 wql_acquired
= waitq_lock_to(wq
,
2003 if (wql_acquired
== FALSE
) {
2004 panic("waitq deadlock - waitq=%p, cpu=%d\n",
2008 #if defined(__x86_64__)
2011 assert(waitq_held(wq
));
2015 waitq_unlock(struct waitq
*wq
)
2017 assert(waitq_held(wq
));
2018 #if defined(__x86_64__)
2021 waitq_lock_unlock(wq
);
2026 * clear the thread-related waitq state
2029 * 'thread' is locked
2032 thread_clear_waitq_state(thread_t thread
)
2034 thread
->waitq
= NULL
;
2035 thread
->wait_event
= NO_EVENT64
;
2036 thread
->at_safe_point
= FALSE
;
2040 typedef thread_t (*waitq_select_cb
)(void *ctx
, struct waitq
*waitq
,
2041 int is_global
, thread_t thread
);
2043 struct waitq_select_args
{
2044 /* input parameters */
2045 struct waitq
*posted_waitq
;
2046 struct waitq
*waitq
;
2048 waitq_select_cb select_cb
;
2052 uint64_t *reserved_preposts
;
2054 /* output parameters */
2061 static void do_waitq_select_n_locked(struct waitq_select_args
*args
);
2064 * callback invoked once for every waitq set to which a waitq belongs
2067 * ctx->posted_waitq is locked
2068 * 'link' points to a valid waitq set
2071 * Takes the waitq set lock on the set pointed to by 'link'
2072 * Calls do_waitq_select_n_locked() which could recurse back into
2073 * this function if the waitq set is a member of other sets.
2074 * If no threads were selected, it preposts the input waitq
2075 * onto the waitq set pointed to by 'link'.
2078 waitq_select_walk_cb(struct waitq
*waitq
, void *ctx
,
2079 struct waitq_link
*link
)
2081 int ret
= WQ_ITERATE_CONTINUE
;
2082 struct waitq_select_args args
= *((struct waitq_select_args
*)ctx
);
2083 struct waitq_set
*wqset
;
2086 assert(wql_type(link
) == WQL_WQS
);
2088 wqset
= link
->wql_wqs
.wql_set
;
2089 args
.waitq
= &wqset
->wqset_q
;
2091 assert(!waitq_irq_safe(waitq
));
2092 assert(!waitq_irq_safe(&wqset
->wqset_q
));
2094 waitq_set_lock(wqset
);
2096 * verify that the link wasn't invalidated just before
2097 * we were able to take the lock.
2099 if (wqset
->wqset_id
!= link
->wql_setid
.id
) {
2103 assert(waitqs_is_linked(wqset
));
2106 * Find any threads waiting on this wait queue set,
2107 * and recurse into any waitq set to which this set belongs.
2109 do_waitq_select_n_locked(&args
);
2111 if (*args
.nthreads
> 0 || (args
.threadq
&& !queue_empty(args
.threadq
))) {
2112 /* at least 1 thread was selected and returned: don't prepost */
2113 if (args
.max_threads
> 0 && *args
.nthreads
>= args
.max_threads
) {
2114 /* break out of the setid walk */
2115 ret
= WQ_ITERATE_FOUND
;
2117 } else if (args
.event
== NO_EVENT64
) {
2119 * No thread selected: prepost 'waitq' to 'wqset'
2120 * if wqset can handle preposts and the event is set to 0.
2121 * We also make sure to not post waitq sets to other sets.
2123 * If the set doesn't support preposts, but does support
2124 * prepost callout/hook interaction, invoke the predefined
2125 * callout function and pass the set's 'prepost_hook.' This
2126 * could potentially release another thread to handle events.
2128 if (waitq_set_can_prepost(wqset
)) {
2129 wq_prepost_do_post_locked(
2130 wqset
, waitq
, args
.reserved_preposts
);
2131 } else if (waitq_set_has_prepost_hook(wqset
)) {
2132 waitq_set_prepost_hook_t
*hook
= wqset
->wqset_prepost_hook
;
2135 * When calling out to the prepost hook,
2136 * we drop the waitq lock, to allow for the kevent
2137 * subsytem to call into the waitq subsystem again,
2138 * without risking a deadlock.
2140 * However, we need to guard against wqset going away,
2141 * so we increment the prepost hook use count
2142 * while the lock is dropped.
2144 * This lets waitq_set_deinit() know to wait for the
2145 * prepost hook call to be done before it can proceed.
2147 * Note: we need to keep preemption disabled the whole
2148 * time as waitq_set_deinit will spin on this.
2151 disable_preemption();
2152 os_atomic_add(hook
, (uint16_t)1, relaxed
);
2153 waitq_set_unlock(wqset
);
2155 waitq_set__CALLING_PREPOST_HOOK__(hook
);
2157 /* Note: after this decrement, the wqset may be deallocated */
2158 os_atomic_add(hook
, (uint16_t)-1, relaxed
);
2159 enable_preemption();
2165 waitq_set_unlock(wqset
);
2170 * Routine to iterate over the waitq for non-priority ordered waitqs
2173 * args->waitq (and args->posted_waitq) is locked
2176 * Uses the optional select callback function to refine the selection
2177 * of one or more threads from a waitq. The select callback is invoked
2178 * once for every thread that is found to be waiting on the input args->waitq.
2180 * If one or more threads are selected, this may disable interrupts.
2181 * The previous interrupt state is returned in args->spl and should
2182 * be used in a call to splx() if threads are returned to the caller.
2185 waitq_queue_iterate_locked(struct waitq
*safeq
, struct waitq
*waitq
,
2186 spl_t spl
, struct waitq_select_args
*args
,
2187 uint32_t *remaining_eventmask
)
2189 int max_threads
= args
->max_threads
;
2190 int *nthreads
= args
->nthreads
;
2191 thread_t thread
= THREAD_NULL
;
2192 thread_t first_thread
= THREAD_NULL
;
2194 qe_foreach_element_safe(thread
, &safeq
->waitq_queue
, wait_links
) {
2195 thread_t t
= THREAD_NULL
;
2196 assert_thread_magic(thread
);
2199 * For non-priority ordered waitqs, we allow multiple events to be
2200 * mux'ed into the same waitq. Also safeqs may contain threads from
2201 * multiple waitqs. Only pick threads that match the
2202 * requested wait event.
2204 if (thread
->waitq
== waitq
&& thread
->wait_event
== args
->event
) {
2206 if (first_thread
== THREAD_NULL
) {
2207 first_thread
= thread
;
2210 /* allow the caller to futher refine the selection */
2211 if (args
->select_cb
) {
2212 t
= args
->select_cb(args
->select_ctx
, waitq
,
2213 waitq_is_global(waitq
), thread
);
2215 if (t
!= THREAD_NULL
) {
2217 if (args
->threadq
) {
2218 /* if output queue, add locked thread to it */
2219 if (*nthreads
== 1) {
2220 *(args
->spl
) = (safeq
!= waitq
) ? spl
: splsched();
2223 thread_clear_waitq_state(t
);
2224 re_queue_tail(args
->threadq
, &t
->wait_links
);
2226 /* only enqueue up to 'max' threads */
2227 if (*nthreads
>= max_threads
&& max_threads
> 0) {
2232 /* thread wasn't selected so track it's event */
2233 if (t
== THREAD_NULL
) {
2234 *remaining_eventmask
|= (thread
->waitq
!= safeq
) ?
2235 _CAST_TO_EVENT_MASK(thread
->waitq
) : _CAST_TO_EVENT_MASK(thread
->wait_event
);
2239 return first_thread
;
2243 * Routine to iterate and remove threads from priority ordered waitqs
2246 * args->waitq (and args->posted_waitq) is locked
2249 * The priority ordered waitqs only support maximum priority element removal.
2251 * Also, the implementation makes sure that all threads in a priority ordered
2252 * waitq are waiting on the same wait event. This is not necessarily true for
2253 * non-priority ordered waitqs. If one or more threads are selected, this may
2254 * disable interrupts. The previous interrupt state is returned in args->spl
2255 * and should be used in a call to splx() if threads are returned to the caller.
2257 * In the future, we could support priority ordered waitqs with multiple wait
2258 * events in the same queue. The way to implement that would be to keep removing
2259 * elements from the waitq and if the event does not match the requested one,
2260 * add it to a local list. This local list of elements needs to be re-inserted
2261 * into the priority queue at the end and the select_cb return value &
2262 * remaining_eventmask would need to be handled appropriately. The implementation
2263 * is not very efficient but would work functionally.
2266 waitq_prioq_iterate_locked(struct waitq
*safeq
, struct waitq
*waitq
,
2267 spl_t spl
, struct waitq_select_args
*args
,
2268 uint32_t *remaining_eventmask
)
2270 int max_threads
= args
->max_threads
;
2271 int *nthreads
= args
->nthreads
;
2272 thread_t first_thread
= THREAD_NULL
;
2273 thread_t thread
= THREAD_NULL
;
2276 * The waitq select routines need to handle two cases:
2277 * Case 1: Peek at maximum priority thread in the waitq (remove_op = 0)
2278 * Get the maximum priority thread from the waitq without removing it.
2279 * In that case args->threadq == NULL and max_threads == 1.
2280 * Case 2: Remove 'n' highest priority threads from waitq (remove_op = 1)
2281 * Get max_threads (if available) while removing them from the waitq.
2282 * In that case args->threadq != NULL and max_threads is one of {-1, 1}.
2284 * The only possible values for remaining_eventmask for the priority queue
2285 * waitq are either 0 (for the remove all threads case) or the original
2286 * safeq->waitq_eventmask (for the lookup/remove one thread cases).
2288 *remaining_eventmask
= safeq
->waitq_eventmask
;
2289 boolean_t remove_op
= !!(args
->threadq
);
2291 while ((max_threads
<= 0) || (*nthreads
< max_threads
)) {
2292 if (priority_queue_empty(&(safeq
->waitq_prio_queue
))) {
2293 *remaining_eventmask
= 0;
2298 thread
= priority_queue_remove_max(&safeq
->waitq_prio_queue
,
2299 struct thread
, wait_prioq_links
);
2301 /* For the peek operation, the only valid value for max_threads is 1 */
2302 assert(max_threads
== 1);
2303 thread
= priority_queue_max(&safeq
->waitq_prio_queue
,
2304 struct thread
, wait_prioq_links
);
2307 * Ensure the wait event matches since priority ordered waitqs do not
2308 * support multiple events in the same waitq.
2310 assert((thread
->waitq
== waitq
) && (thread
->wait_event
== args
->event
));
2312 if (args
->select_cb
) {
2314 * Call the select_cb passed into the waitq_select args. The callback
2315 * updates the select_ctx with information about the highest priority
2316 * thread which is eventually used by the caller.
2318 thread_t __assert_only ret_thread
= args
->select_cb(args
->select_ctx
, waitq
,
2319 waitq_is_global(waitq
), thread
);
2321 /* For the peek operation, the thread should not be selected for addition */
2322 assert(ret_thread
== THREAD_NULL
);
2325 * For the remove operation, the select routine should always return a valid
2326 * thread for priority waitqs. Since all threads in a prioq are equally
2327 * eligible, it should match the thread removed from the prioq. If this
2328 * invariant changes, the implementation would need to handle the
2329 * remaining_eventmask here correctly.
2331 assert(ret_thread
== thread
);
2335 if (first_thread
== THREAD_NULL
) {
2336 first_thread
= thread
;
2338 * turnstile_kernel_update_inheritor_on_wake_locked will lock
2339 * first_thread, so call it before locking it.
2341 if (args
->priority
== WAITQ_PROMOTE_ON_WAKE
&& first_thread
!= THREAD_NULL
&& waitq_is_turnstile_queue(safeq
)) {
2342 turnstile_kernel_update_inheritor_on_wake_locked(waitq_to_turnstile(safeq
), (turnstile_inheritor_t
)first_thread
, TURNSTILE_INHERITOR_THREAD
);
2346 /* For the peek operation, break out early */
2351 /* Add the thread to the result thread list */
2353 if (*nthreads
== 1) {
2354 *(args
->spl
) = (safeq
!= waitq
) ? spl
: splsched();
2356 thread_lock(thread
);
2357 thread_clear_waitq_state(thread
);
2358 enqueue_tail(args
->threadq
, &(thread
->wait_links
));
2361 return first_thread
;
2365 * generic thread selection from a waitq (and sets to which the waitq belongs)
2368 * args->waitq (and args->posted_waitq) is locked
2371 * Uses the optional select callback function to refine the selection
2372 * of one or more threads from a waitq and any set to which the waitq
2373 * belongs. The select callback is invoked once for every thread that
2374 * is found to be waiting on the input args->waitq.
2376 * If one or more threads are selected, this may disable interrupts.
2377 * The previous interrupt state is returned in args->spl and should
2378 * be used in a call to splx() if threads are returned to the caller.
2381 do_waitq_select_n_locked(struct waitq_select_args
*args
)
2383 struct waitq
*waitq
= args
->waitq
;
2384 int max_threads
= args
->max_threads
;
2385 thread_t first_thread
= THREAD_NULL
;
2386 struct waitq
*safeq
;
2387 uint32_t remaining_eventmask
= 0;
2389 int *nthreads
= args
->nthreads
;
2392 assert(max_threads
!= 0);
2394 if (!waitq_irq_safe(waitq
)) {
2395 /* JMM - add flag to waitq to avoid global lookup if no waiters */
2396 eventmask
= _CAST_TO_EVENT_MASK(waitq
);
2397 safeq
= waitq_get_safeq(waitq
);
2398 if (safeq
== NULL
) {
2400 * in the WQT_TSPROXY case, if there's no turnstile,
2401 * there's no queue and no waiters, so we can move straight
2402 * to the waitq set recursion
2404 goto handle_waitq_set
;
2407 if (*nthreads
== 0) {
2412 eventmask
= _CAST_TO_EVENT_MASK(args
->event
);
2417 * If the safeq doesn't have an eventmask (not global) or the event
2418 * we're looking for IS set in its eventmask, then scan the threads
2419 * in that queue for ones that match the original <waitq,event> pair.
2421 if (!waitq_is_global(safeq
) ||
2422 (safeq
->waitq_eventmask
& eventmask
) == eventmask
) {
2423 if (waitq_is_turnstile_queue(safeq
)) {
2424 first_thread
= waitq_prioq_iterate_locked(safeq
, waitq
,
2426 &remaining_eventmask
);
2428 first_thread
= waitq_queue_iterate_locked(safeq
, waitq
,
2430 &remaining_eventmask
);
2434 * Update the eventmask of global queues we just scanned:
2435 * - If we selected all the threads in the queue, we can clear its
2438 * - If we didn't find enough threads to fill our needs, then we can
2439 * assume we looked at every thread in the queue and the mask we
2440 * computed is complete - so reset it.
2442 if (waitq_is_global(safeq
)) {
2443 if (waitq_empty(safeq
)) {
2444 safeq
->waitq_eventmask
= 0;
2445 } else if (max_threads
< 0 || *nthreads
< max_threads
) {
2446 safeq
->waitq_eventmask
= remaining_eventmask
;
2452 * Grab the first thread in the queue if no other thread was selected.
2453 * We can guarantee that no one has manipulated this thread because
2454 * it's waiting on the given waitq, and we have that waitq locked.
2456 if (*nthreads
== 0 && first_thread
!= THREAD_NULL
&& args
->threadq
) {
2457 /* we know this is the first (and only) thread */
2459 *(args
->spl
) = (safeq
!= waitq
) ? spl
: splsched();
2461 thread_lock(first_thread
);
2462 thread_clear_waitq_state(first_thread
);
2463 waitq_thread_remove(safeq
, first_thread
);
2464 enqueue_tail(args
->threadq
, &(first_thread
->wait_links
));
2466 /* update the eventmask on [now] empty global queues */
2467 if (waitq_is_global(safeq
) && waitq_empty(safeq
)) {
2468 safeq
->waitq_eventmask
= 0;
2472 /* unlock the safe queue if we locked one above */
2473 if (safeq
!= waitq
) {
2474 waitq_unlock(safeq
);
2475 if (*nthreads
== 0) {
2480 if (max_threads
> 0 && *nthreads
>= max_threads
) {
2486 * wait queues that are not in any sets
2487 * are the bottom of the recursion
2489 if (!waitq
->waitq_set_id
) {
2493 /* check to see if the set ID for this wait queue is valid */
2494 struct waitq_link
*link
= wql_get_link(waitq
->waitq_set_id
);
2496 /* the waitq set to which this waitq belonged, has been invalidated */
2497 waitq
->waitq_set_id
= 0;
2504 * If this waitq is a member of any wait queue sets, we need to look
2505 * for waiting thread(s) in any of those sets, and prepost all sets that
2506 * don't have active waiters.
2508 * Note that we do a local walk of this waitq's links - we manually
2509 * recurse down wait queue set's with non-zero wqset_q.waitq_set_id
2511 (void)walk_waitq_links(LINK_WALK_ONE_LEVEL
, waitq
, waitq
->waitq_set_id
,
2512 WQL_WQS
, (void *)args
, waitq_select_walk_cb
);
2516 * main entry point for thread selection from a waitq
2522 * The number of threads waiting on 'waitq' for 'event' which have
2523 * been placed onto the input 'threadq'
2526 * The 'select_cb' function is invoked for every thread found waiting on
2527 * 'waitq' for 'event'. The thread is _not_ locked upon callback
2528 * invocation. This parameter may be NULL.
2530 * If one or more threads are returned in 'threadq' then the caller is
2531 * responsible to call splx() using the returned 'spl' value. Each
2532 * returned thread is locked.
2534 static __inline__
int
2535 waitq_select_n_locked(struct waitq
*waitq
,
2537 waitq_select_cb select_cb
,
2539 uint64_t *reserved_preposts
,
2541 int max_threads
, spl_t
*spl
,
2546 struct waitq_select_args args
= {
2547 .posted_waitq
= waitq
,
2550 .select_cb
= select_cb
,
2551 .select_ctx
= select_ctx
,
2552 .priority
= priority
,
2553 .reserved_preposts
= reserved_preposts
,
2555 .max_threads
= max_threads
,
2556 .nthreads
= &nthreads
,
2560 do_waitq_select_n_locked(&args
);
2565 * select from a waitq a single thread waiting for a given event
2571 * A locked thread that's been removed from the waitq, but has not
2572 * yet been put on a run queue. Caller is responsible to call splx
2573 * with the '*spl' value.
2576 waitq_select_one_locked(struct waitq
*waitq
, event64_t event
,
2577 uint64_t *reserved_preposts
,
2578 int priority
, spl_t
*spl
)
2581 queue_head_t threadq
;
2583 queue_init(&threadq
);
2585 nthreads
= waitq_select_n_locked(waitq
, event
, NULL
, NULL
,
2586 reserved_preposts
, &threadq
, 1, spl
, priority
);
2588 /* if we selected a thread, return it (still locked) */
2589 if (!queue_empty(&threadq
)) {
2591 queue_entry_t qe
= dequeue_head(&threadq
);
2592 t
= qe_element(qe
, struct thread
, wait_links
);
2593 assert(queue_empty(&threadq
)); /* there should be 1 entry */
2594 /* t has been locked and removed from all queues */
2601 struct select_thread_ctx
{
2608 * link walk callback invoked once for each set to which a waitq belongs
2611 * initial waitq is locked
2612 * ctx->thread is unlocked
2615 * This may disable interrupts and early-out of the full DAG link walk by
2616 * returning KERN_ALREADY_IN_SET. In this case, the returned thread has
2617 * been removed from the waitq, it's waitq state has been reset, and the
2618 * caller is responsible to call splx() with the returned interrupt state
2622 waitq_select_thread_cb(struct waitq
*waitq
, void *ctx
,
2623 struct waitq_link
*link
)
2625 struct select_thread_ctx
*stctx
= (struct select_thread_ctx
*)ctx
;
2626 struct waitq_set
*wqset
;
2627 struct waitq
*wqsetq
;
2628 struct waitq
*safeq
;
2633 thread_t thread
= stctx
->thread
;
2634 event64_t event
= stctx
->event
;
2636 if (wql_type(link
) != WQL_WQS
) {
2637 return WQ_ITERATE_CONTINUE
;
2640 wqset
= link
->wql_wqs
.wql_set
;
2641 wqsetq
= &wqset
->wqset_q
;
2643 assert(!waitq_irq_safe(waitq
));
2644 assert(!waitq_irq_safe(wqsetq
));
2646 waitq_set_lock(wqset
);
2650 /* find and lock the interrupt-safe waitq the thread is thought to be on */
2651 safeq
= waitq_get_safeq(wqsetq
);
2654 thread_lock(thread
);
2656 if ((thread
->waitq
== wqsetq
) && (thread
->wait_event
== event
)) {
2657 waitq_thread_remove(wqsetq
, thread
);
2658 if (waitq_empty(safeq
)) {
2659 safeq
->waitq_eventmask
= 0;
2661 thread_clear_waitq_state(thread
);
2662 waitq_unlock(safeq
);
2663 waitq_set_unlock(wqset
);
2665 * thread still locked,
2666 * return non-zero to break out of WQS walk
2669 return WQ_ITERATE_FOUND
;
2672 thread_unlock(thread
);
2673 waitq_set_unlock(wqset
);
2674 waitq_unlock(safeq
);
2677 return WQ_ITERATE_CONTINUE
;
2681 * returns KERN_SUCCESS and locks 'thread' if-and-only-if 'thread' is waiting
2682 * on 'waitq' (or any set to which waitq belongs) for 'event'
2686 * 'thread' is unlocked
2688 static kern_return_t
2689 waitq_select_thread_locked(struct waitq
*waitq
,
2691 thread_t thread
, spl_t
*spl
)
2693 struct waitq
*safeq
;
2694 struct waitq_link
*link
;
2695 struct select_thread_ctx ctx
;
2699 /* Find and lock the interrupts disabled queue the thread is actually on */
2700 if (!waitq_irq_safe(waitq
)) {
2701 safeq
= waitq_get_safeq(waitq
);
2702 if (safeq
== NULL
) {
2704 * in the WQT_TSPROXY case, if there's no turnstile,
2705 * there's no queue and no waiters, so we can move straight
2706 * to the waitq set recursion
2708 goto handle_waitq_set
;
2718 thread_lock(thread
);
2720 if ((thread
->waitq
== waitq
) && (thread
->wait_event
== event
)) {
2721 waitq_thread_remove(safeq
, thread
);
2722 if (waitq_empty(safeq
)) {
2723 safeq
->waitq_eventmask
= 0;
2725 thread_clear_waitq_state(thread
);
2727 /* thread still locked */
2728 return KERN_SUCCESS
;
2731 thread_unlock(thread
);
2733 if (safeq
!= waitq
) {
2734 waitq_unlock(safeq
);
2740 if (!waitq
->waitq_set_id
) {
2741 return KERN_NOT_WAITING
;
2744 /* check to see if the set ID for this wait queue is valid */
2745 link
= wql_get_link(waitq
->waitq_set_id
);
2747 /* the waitq to which this set belonged, has been invalidated */
2748 waitq
->waitq_set_id
= 0;
2749 return KERN_NOT_WAITING
;
2753 * The thread may be waiting on a wait queue set to which
2754 * the input 'waitq' belongs. Go look for the thread in
2755 * all wait queue sets. If it's there, we'll remove it
2756 * because it's equivalent to waiting directly on the input waitq.
2758 ctx
.thread
= thread
;
2761 kr
= walk_waitq_links(LINK_WALK_FULL_DAG
, waitq
, waitq
->waitq_set_id
,
2762 WQL_WQS
, (void *)&ctx
, waitq_select_thread_cb
);
2766 /* we found a thread, return success */
2767 if (kr
== WQ_ITERATE_FOUND
) {
2768 return KERN_SUCCESS
;
2771 return KERN_NOT_WAITING
;
2775 prepost_exists_cb(struct waitq_set __unused
*wqset
,
2777 struct wq_prepost __unused
*wqp
,
2778 struct waitq __unused
*waitq
)
2780 /* if we get here, then we know that there is a valid prepost object! */
2781 return WQ_ITERATE_FOUND
;
2785 * declare a thread's intent to wait on 'waitq' for 'wait_event'
2791 waitq_assert_wait64_locked(struct waitq
*waitq
,
2792 event64_t wait_event
,
2793 wait_interrupt_t interruptible
,
2794 wait_timeout_urgency_t urgency
,
2799 wait_result_t wait_result
;
2801 struct waitq
*safeq
;
2802 uintptr_t eventmask
;
2807 * Warning: Do _not_ place debugging print statements here.
2808 * The waitq is locked!
2810 assert(!thread
->started
|| thread
== current_thread());
2812 if (thread
->waitq
!= NULL
) {
2813 panic("thread already waiting on %p", thread
->waitq
);
2816 if (waitq_is_set(waitq
)) {
2817 struct waitq_set
*wqset
= (struct waitq_set
*)waitq
;
2819 * early-out if the thread is waiting on a wait queue set
2820 * that has already been pre-posted.
2822 if (wait_event
== NO_EVENT64
&& waitq_set_maybe_preposted(wqset
)) {
2825 * Run through the list of potential preposts. Because
2826 * this is a hot path, we short-circuit the iteration
2827 * if we find just one prepost object.
2829 ret
= wq_prepost_foreach_locked(wqset
, NULL
,
2831 if (ret
== WQ_ITERATE_FOUND
) {
2833 thread_lock(thread
);
2834 thread
->wait_result
= THREAD_AWAKENED
;
2835 thread_unlock(thread
);
2837 return THREAD_AWAKENED
;
2845 * If already dealing with an irq safe wait queue, we are all set.
2846 * Otherwise, determine a global queue to use and lock it.
2848 if (!waitq_irq_safe(waitq
)) {
2849 safeq
= waitq_get_safeq(waitq
);
2850 if (__improbable(safeq
== NULL
)) {
2851 panic("Trying to assert_wait on a turnstile proxy "
2852 "that hasn't been donated one (waitq: %p)", waitq
);
2854 eventmask
= _CAST_TO_EVENT_MASK(waitq
);
2858 eventmask
= _CAST_TO_EVENT_MASK(wait_event
);
2861 /* lock the thread now that we have the irq-safe waitq locked */
2862 thread_lock(thread
);
2865 * Realtime threads get priority for wait queue placements.
2866 * This allows wait_queue_wakeup_one to prefer a waiting
2867 * realtime thread, similar in principle to performing
2868 * a wait_queue_wakeup_all and allowing scheduler prioritization
2869 * to run the realtime thread, but without causing the
2870 * lock contention of that scenario.
2872 if (thread
->sched_pri
>= BASEPRI_REALTIME
) {
2877 * This is the extent to which we currently take scheduling attributes
2878 * into account. If the thread is vm priviledged, we stick it at
2879 * the front of the queue. Later, these queues will honor the policy
2880 * value set at waitq_init time.
2882 wait_result
= thread_mark_wait_locked(thread
, interruptible
);
2883 /* thread->wait_result has been set */
2884 if (wait_result
== THREAD_WAITING
) {
2885 if (!safeq
->waitq_fifo
2886 || (thread
->options
& TH_OPT_VMPRIV
) || realtime
) {
2887 waitq_thread_insert(safeq
, thread
, false);
2889 waitq_thread_insert(safeq
, thread
, true);
2892 /* mark the event and real waitq, even if enqueued on a global safeq */
2893 thread
->wait_event
= wait_event
;
2894 thread
->waitq
= waitq
;
2896 if (deadline
!= 0) {
2899 act
= timer_call_enter_with_leeway(&thread
->wait_timer
,
2904 thread
->wait_timer_active
++;
2906 thread
->wait_timer_is_set
= TRUE
;
2909 if (waitq_is_global(safeq
)) {
2910 safeq
->waitq_eventmask
|= eventmask
;
2913 waitq_stats_count_wait(waitq
);
2916 /* unlock the thread */
2917 thread_unlock(thread
);
2919 /* update the inheritor's thread priority if the waitq is embedded in turnstile */
2920 if (waitq_is_turnstile_queue(safeq
) && wait_result
== THREAD_WAITING
) {
2921 turnstile_recompute_priority_locked(waitq_to_turnstile(safeq
));
2922 turnstile_update_inheritor_locked(waitq_to_turnstile(safeq
));
2925 /* unlock the safeq if we locked it here */
2926 if (safeq
!= waitq
) {
2927 waitq_unlock(safeq
);
2936 * remove 'thread' from its current blocking state on 'waitq'
2939 * 'thread' is locked
2942 * This function is primarily used by clear_wait_internal in
2943 * sched_prim.c from the thread timer wakeup path
2944 * (i.e. the thread was waiting on 'waitq' with a timeout that expired)
2947 waitq_pull_thread_locked(struct waitq
*waitq
, thread_t thread
)
2949 struct waitq
*safeq
;
2951 assert_thread_magic(thread
);
2952 assert(thread
->waitq
== waitq
);
2954 /* Find the interrupts disabled queue thread is waiting on */
2955 if (!waitq_irq_safe(waitq
)) {
2956 safeq
= waitq_get_safeq(waitq
);
2957 if (__improbable(safeq
== NULL
)) {
2958 panic("Trying to clear_wait on a turnstile proxy "
2959 "that hasn't been donated one (waitq: %p)", waitq
);
2965 /* thread is already locked so have to try for the waitq lock */
2966 if (!waitq_lock_try(safeq
)) {
2970 waitq_thread_remove(safeq
, thread
);
2971 thread_clear_waitq_state(thread
);
2972 waitq_stats_count_clear_wakeup(waitq
);
2974 /* clear the global event mask if this was the last thread there! */
2975 if (waitq_is_global(safeq
) && waitq_empty(safeq
)) {
2976 safeq
->waitq_eventmask
= 0;
2977 /* JMM - also mark no-waiters on waitq (if not the same as the safeq) */
2980 waitq_unlock(safeq
);
2988 maybe_adjust_thread_pri(thread_t thread
,
2990 __kdebug_only
struct waitq
*waitq
)
2993 * If the caller is requesting the waitq subsystem to promote the
2994 * priority of the awoken thread, then boost the thread's priority to
2995 * the default WAITQ_BOOST_PRIORITY (if it's not already equal or
2996 * higher priority). This boost must be removed via a call to
2997 * waitq_clear_promotion_locked before the thread waits again.
2999 * WAITQ_PROMOTE_PRIORITY is -2.
3000 * Anything above 0 represents a mutex promotion.
3001 * The default 'no action' value is -1.
3002 * TODO: define this in a header
3004 if (priority
== WAITQ_PROMOTE_PRIORITY
) {
3005 uintptr_t trace_waitq
= 0;
3006 if (__improbable(kdebug_enable
)) {
3007 trace_waitq
= VM_KERNEL_UNSLIDE_OR_PERM(waitq
);
3010 sched_thread_promote_reason(thread
, TH_SFLAG_WAITQ_PROMOTED
, trace_waitq
);
3015 * Clear a potential thread priority promotion from a waitq wakeup
3016 * with WAITQ_PROMOTE_PRIORITY.
3018 * This must be called on the thread which was woken up with TH_SFLAG_WAITQ_PROMOTED.
3021 waitq_clear_promotion_locked(struct waitq
*waitq
, thread_t thread
)
3025 assert(waitq_held(waitq
));
3026 assert(thread
!= THREAD_NULL
);
3027 assert(thread
== current_thread());
3029 /* This flag is only cleared by the thread itself, so safe to check outside lock */
3030 if ((thread
->sched_flags
& TH_SFLAG_WAITQ_PROMOTED
) != TH_SFLAG_WAITQ_PROMOTED
) {
3034 if (!waitq_irq_safe(waitq
)) {
3037 thread_lock(thread
);
3039 sched_thread_unpromote_reason(thread
, TH_SFLAG_WAITQ_PROMOTED
, 0);
3041 thread_unlock(thread
);
3042 if (!waitq_irq_safe(waitq
)) {
3048 * wakeup all threads waiting on 'waitq' for 'wake_event'
3054 * May temporarily disable and re-enable interrupts
3055 * and re-adjust thread priority of each awoken thread.
3057 * If the input 'lock_state' == WAITQ_UNLOCK then the waitq will have
3058 * been unlocked before calling thread_go() on any returned threads, and
3059 * is guaranteed to be unlocked upon function return.
3062 waitq_wakeup64_all_locked(struct waitq
*waitq
,
3063 event64_t wake_event
,
3064 wait_result_t result
,
3065 uint64_t *reserved_preposts
,
3067 waitq_lock_state_t lock_state
)
3073 queue_head_t wakeup_queue
;
3075 assert(waitq_held(waitq
));
3076 queue_init(&wakeup_queue
);
3078 nthreads
= waitq_select_n_locked(waitq
, wake_event
, NULL
, NULL
,
3080 &wakeup_queue
, -1, &th_spl
, priority
);
3082 /* set each thread running */
3083 ret
= KERN_NOT_WAITING
;
3085 #if CONFIG_WAITQ_STATS
3086 qe_foreach_element(thread
, &wakeup_queue
, wait_links
)
3087 waitq_stats_count_wakeup(waitq
);
3089 if (lock_state
== WAITQ_UNLOCK
) {
3090 waitq_unlock(waitq
);
3093 qe_foreach_element_safe(thread
, &wakeup_queue
, wait_links
) {
3094 assert_thread_magic(thread
);
3095 remqueue(&thread
->wait_links
);
3096 maybe_adjust_thread_pri(thread
, priority
, waitq
);
3097 ret
= thread_go(thread
, result
, WQ_OPTION_NONE
);
3098 assert(ret
== KERN_SUCCESS
);
3099 thread_unlock(thread
);
3104 waitq_stats_count_fail(waitq
);
3111 * wakeup one thread waiting on 'waitq' for 'wake_event'
3117 * May temporarily disable and re-enable interrupts.
3120 waitq_wakeup64_one_locked(struct waitq
*waitq
,
3121 event64_t wake_event
,
3122 wait_result_t result
,
3123 uint64_t *reserved_preposts
,
3125 waitq_lock_state_t lock_state
,
3126 waitq_options_t option
)
3131 assert(waitq_held(waitq
));
3133 thread
= waitq_select_one_locked(waitq
, wake_event
,
3137 if (thread
!= THREAD_NULL
) {
3138 waitq_stats_count_wakeup(waitq
);
3140 waitq_stats_count_fail(waitq
);
3143 if (lock_state
== WAITQ_UNLOCK
) {
3144 waitq_unlock(waitq
);
3147 if (thread
!= THREAD_NULL
) {
3148 maybe_adjust_thread_pri(thread
, priority
, waitq
);
3149 kern_return_t ret
= thread_go(thread
, result
, option
);
3150 assert(ret
== KERN_SUCCESS
);
3151 thread_unlock(thread
);
3156 return KERN_NOT_WAITING
;
3160 * wakeup one thread waiting on 'waitq' for 'wake_event'
3166 * A locked, runnable thread.
3167 * If return value is non-NULL, interrupts have also
3168 * been disabled, and the caller is responsible to call
3169 * splx() with the returned '*spl' value.
3172 waitq_wakeup64_identify_locked(struct waitq
*waitq
,
3173 event64_t wake_event
,
3174 wait_result_t result
,
3176 uint64_t *reserved_preposts
,
3178 waitq_lock_state_t lock_state
)
3182 assert(waitq_held(waitq
));
3184 thread
= waitq_select_one_locked(waitq
, wake_event
,
3188 if (thread
!= THREAD_NULL
) {
3189 waitq_stats_count_wakeup(waitq
);
3191 waitq_stats_count_fail(waitq
);
3194 if (lock_state
== WAITQ_UNLOCK
) {
3195 waitq_unlock(waitq
);
3198 if (thread
!= THREAD_NULL
) {
3199 kern_return_t __assert_only ret
;
3200 ret
= thread_go(thread
, result
, WQ_OPTION_NONE
);
3201 assert(ret
== KERN_SUCCESS
);
3204 return thread
; /* locked if not NULL (caller responsible for spl) */
3208 * wakeup a specific thread iff it's waiting on 'waitq' for 'wake_event'
3212 * 'thread' is unlocked
3215 * May temporarily disable and re-enable interrupts
3217 * If the input lock_state == WAITQ_UNLOCK then the waitq will have been
3218 * unlocked before calling thread_go() if 'thread' is to be awoken, and
3219 * is guaranteed to be unlocked upon function return.
3222 waitq_wakeup64_thread_locked(struct waitq
*waitq
,
3223 event64_t wake_event
,
3225 wait_result_t result
,
3226 waitq_lock_state_t lock_state
)
3231 assert(waitq_held(waitq
));
3232 assert_thread_magic(thread
);
3235 * See if the thread was still waiting there. If so, it got
3236 * dequeued and returned locked.
3238 ret
= waitq_select_thread_locked(waitq
, wake_event
, thread
, &th_spl
);
3240 if (ret
== KERN_SUCCESS
) {
3241 waitq_stats_count_wakeup(waitq
);
3243 waitq_stats_count_fail(waitq
);
3246 if (lock_state
== WAITQ_UNLOCK
) {
3247 waitq_unlock(waitq
);
3250 if (ret
!= KERN_SUCCESS
) {
3251 return KERN_NOT_WAITING
;
3254 ret
= thread_go(thread
, result
, WQ_OPTION_NONE
);
3255 assert(ret
== KERN_SUCCESS
);
3256 thread_unlock(thread
);
3264 /* ----------------------------------------------------------------------
3268 * ---------------------------------------------------------------------- */
3271 * initialize a waitq object
3274 waitq_init(struct waitq
*waitq
, int policy
)
3276 assert(waitq
!= NULL
);
3278 /* only FIFO and LIFO for now */
3279 if ((policy
& SYNC_POLICY_FIXED_PRIORITY
) != 0) {
3280 return KERN_INVALID_ARGUMENT
;
3283 waitq
->waitq_fifo
= ((policy
& SYNC_POLICY_REVERSED
) == 0);
3284 waitq
->waitq_irq
= !!(policy
& SYNC_POLICY_DISABLE_IRQ
);
3285 waitq
->waitq_prepost
= 0;
3286 if (policy
& SYNC_POLICY_TURNSTILE_PROXY
) {
3287 waitq
->waitq_type
= WQT_TSPROXY
;
3289 waitq
->waitq_type
= WQT_QUEUE
;
3291 waitq
->waitq_turnstile
= !!(policy
& SYNC_POLICY_TURNSTILE
);
3292 waitq
->waitq_eventmask
= 0;
3294 waitq
->waitq_set_id
= 0;
3295 waitq
->waitq_prepost_id
= 0;
3297 waitq_lock_init(waitq
);
3298 if (waitq_is_turnstile_queue(waitq
)) {
3299 /* For turnstile, initialize it as a priority queue */
3300 priority_queue_init(&waitq
->waitq_prio_queue
);
3301 assert(waitq
->waitq_fifo
== 0);
3302 } else if (policy
& SYNC_POLICY_TURNSTILE_PROXY
) {
3303 waitq
->waitq_ts
= TURNSTILE_NULL
;
3304 waitq
->waitq_tspriv
= NULL
;
3306 queue_init(&waitq
->waitq_queue
);
3309 waitq
->waitq_isvalid
= 1;
3310 return KERN_SUCCESS
;
3313 struct wq_unlink_ctx
{
3314 struct waitq
*unlink_wq
;
3315 struct waitq_set
*unlink_wqset
;
3318 static int waitq_unlink_prepost_cb(struct waitq_set __unused
*wqset
, void *ctx
,
3319 struct wq_prepost
*wqp
, struct waitq
*waitq
);
3322 * walk_waitq_links callback to invalidate 'link' parameter
3325 * Called from walk_waitq_links.
3326 * Note that unlink other callbacks, this one make no assumptions about
3327 * the 'waitq' parameter, specifically it does not have to be locked or
3331 waitq_unlink_all_cb(struct waitq
*waitq
, void *ctx
,
3332 struct waitq_link
*link
)
3336 if (wql_type(link
) == WQL_LINK
&& wql_is_valid(link
)) {
3337 wql_invalidate(link
);
3340 if (wql_type(link
) == WQL_WQS
) {
3341 struct waitq_set
*wqset
;
3342 struct wq_unlink_ctx ulctx
;
3345 * When destroying the waitq, take the time to clear out any
3346 * preposts it may have made. This could potentially save time
3347 * on the IPC send path which would otherwise have to iterate
3348 * over lots of dead port preposts.
3350 if (waitq
->waitq_prepost_id
== 0) {
3354 wqset
= link
->wql_wqs
.wql_set
;
3355 assert(wqset
!= NULL
);
3356 assert(!waitq_irq_safe(&wqset
->wqset_q
));
3358 waitq_set_lock(wqset
);
3360 if (!waitq_set_is_valid(wqset
)) {
3361 /* someone raced us to teardown */
3364 if (!waitq_set_maybe_preposted(wqset
)) {
3368 ulctx
.unlink_wq
= waitq
;
3369 ulctx
.unlink_wqset
= wqset
;
3370 (void)wq_prepost_iterate(wqset
->wqset_prepost_id
, &ulctx
,
3371 waitq_unlink_prepost_cb
);
3373 waitq_set_unlock(wqset
);
3377 return WQ_ITERATE_CONTINUE
;
3382 * cleanup any link/prepost table resources associated with a waitq
3385 waitq_deinit(struct waitq
*waitq
)
3390 if (!waitq_is_valid(waitq
)) {
3394 if (!waitq_is_queue(waitq
) && !waitq_is_turnstile_proxy(waitq
)) {
3398 if (waitq_irq_safe(waitq
)) {
3403 if (waitq_valid(waitq
)) {
3404 waitq
->waitq_isvalid
= 0;
3405 if (!waitq_irq_safe(waitq
)) {
3406 waitq_unlink_all_unlock(waitq
);
3407 /* waitq unlocked and set links deallocated */
3412 waitq_unlock(waitq
);
3413 if (waitq_irq_safe(waitq
)) {
3419 if (waitq_is_turnstile_queue(waitq
)) {
3420 assert(priority_queue_empty(&waitq
->waitq_prio_queue
));
3421 } else if (waitq_is_turnstile_proxy(waitq
)) {
3422 assert(waitq
->waitq_ts
== TURNSTILE_NULL
);
3424 assert(queue_empty(&waitq
->waitq_queue
));
3428 #endif // MACH_ASSERT
3432 waitq_invalidate_locked(struct waitq
*waitq
)
3434 assert(waitq_held(waitq
));
3435 assert(waitq_is_valid(waitq
));
3436 waitq
->waitq_isvalid
= 0;
3440 * invalidate the given wq_prepost object
3443 * Called from wq_prepost_iterate (_not_ from wq_prepost_foreach_locked!)
3446 wqset_clear_prepost_chain_cb(struct waitq_set __unused
*wqset
,
3448 struct wq_prepost
*wqp
,
3449 struct waitq __unused
*waitq
)
3451 if (wqp_type(wqp
) == WQP_POST
) {
3452 wq_prepost_invalidate(wqp
);
3454 return WQ_ITERATE_CONTINUE
;
3459 * allocate and initialize a waitq set object
3465 * allocated / initialized waitq_set object.
3466 * the waits_set object returned does not have
3467 * a waitq_link associated.
3472 waitq_set_alloc(int policy
, waitq_set_prepost_hook_t
*prepost_hook
)
3474 struct waitq_set
*wqset
;
3476 wqset
= (struct waitq_set
*)zalloc(waitq_set_zone
);
3478 panic("Can't allocate a new waitq set from zone %p", waitq_set_zone
);
3482 ret
= waitq_set_init(wqset
, policy
, NULL
, prepost_hook
);
3483 if (ret
!= KERN_SUCCESS
) {
3484 zfree(waitq_set_zone
, wqset
);
3492 * initialize a waitq set object
3494 * if no 'reserved_link' object is passed
3495 * the waitq_link will be lazily allocated
3496 * on demand through waitq_set_lazy_init_link.
3499 waitq_set_init(struct waitq_set
*wqset
,
3500 int policy
, uint64_t *reserved_link
,
3501 waitq_set_prepost_hook_t
*prepost_hook
)
3503 struct waitq_link
*link
;
3506 memset(wqset
, 0, sizeof(*wqset
));
3508 ret
= waitq_init(&wqset
->wqset_q
, policy
);
3509 if (ret
!= KERN_SUCCESS
) {
3513 wqset
->wqset_q
.waitq_type
= WQT_SET
;
3514 if (policy
& SYNC_POLICY_PREPOST
) {
3515 wqset
->wqset_q
.waitq_prepost
= 1;
3516 wqset
->wqset_prepost_id
= 0;
3517 assert(prepost_hook
== NULL
);
3519 wqset
->wqset_q
.waitq_prepost
= 0;
3520 wqset
->wqset_prepost_hook
= prepost_hook
;
3523 if (reserved_link
&& *reserved_link
!= 0) {
3524 link
= wql_get_reserved(*reserved_link
, WQL_WQS
);
3527 panic("Can't allocate link object for waitq set: %p", wqset
);
3530 /* always consume the caller's reference */
3533 link
->wql_wqs
.wql_set
= wqset
;
3536 wqset
->wqset_id
= link
->wql_setid
.id
;
3540 * Lazy allocate the link only when an actual id is needed.
3542 wqset
->wqset_id
= WQSET_NOT_LINKED
;
3545 return KERN_SUCCESS
;
3548 #if DEVELOPMENT || DEBUG
3551 sysctl_helper_waitq_set_nelem(void)
3553 return ltable_nelem(&g_wqlinktable
);
3559 * initialize a waitq set link.
3563 * locks and unlocks the waiq set lock
3567 waitq_set_lazy_init_link(struct waitq_set
*wqset
)
3569 struct waitq_link
*link
;
3571 assert(get_preemption_level() == 0 && waitq_wait_possible(current_thread()));
3573 waitq_set_lock(wqset
);
3574 if (!waitq_set_should_lazy_init_link(wqset
)) {
3575 waitq_set_unlock(wqset
);
3579 assert(wqset
->wqset_id
== WQSET_NOT_LINKED
);
3580 waitq_set_unlock(wqset
);
3582 link
= wql_alloc_link(WQL_WQS
);
3584 panic("Can't allocate link object for waitq set: %p", wqset
);
3587 link
->wql_wqs
.wql_set
= wqset
;
3589 waitq_set_lock(wqset
);
3590 if (waitq_set_should_lazy_init_link(wqset
)) {
3592 wqset
->wqset_id
= link
->wql_setid
.id
;
3595 assert(wqset
->wqset_id
!= 0);
3596 assert(wqset
->wqset_id
!= WQSET_NOT_LINKED
);
3598 waitq_set_unlock(wqset
);
3606 * checks if a waitq set needs to be linked.
3610 waitq_set_should_lazy_init_link(struct waitq_set
*wqset
)
3612 if (waitqs_is_linked(wqset
) || wqset
->wqset_id
== 0) {
3619 * clear out / release any resources associated with a waitq set
3624 * This will render the waitq set invalid, and it must
3625 * be re-initialized with waitq_set_init before it can be used again
3628 waitq_set_deinit(struct waitq_set
*wqset
)
3630 struct waitq_link
*link
= NULL
;
3631 uint64_t set_id
, prepost_id
;
3633 if (!waitqs_is_set(wqset
)) {
3634 panic("trying to de-initialize an invalid wqset @%p", wqset
);
3637 assert(!waitq_irq_safe(&wqset
->wqset_q
));
3639 waitq_set_lock(wqset
);
3641 if (waitq_set_has_prepost_hook(wqset
)) {
3642 waitq_set_prepost_hook_t
*hook
= wqset
->wqset_prepost_hook
;
3644 * If the wqset_prepost_hook value is non 0,
3645 * then another core is currently posting to this waitq set
3646 * and we need for it to finish what it's doing.
3648 while (os_atomic_load(hook
, relaxed
) != 0) {
3649 waitq_set_unlock(wqset
);
3651 waitq_set_lock(wqset
);
3655 set_id
= wqset
->wqset_id
;
3657 if (waitqs_is_linked(wqset
) || set_id
== 0) {
3658 /* grab the set's link object */
3659 link
= wql_get_link(set_id
);
3661 wql_invalidate(link
);
3663 /* someone raced us to deinit */
3664 if (!link
|| wqset
->wqset_id
!= set_id
|| set_id
!= link
->wql_setid
.id
) {
3668 waitq_set_unlock(wqset
);
3672 /* the link should be a valid link object at this point */
3673 assert(link
!= NULL
&& wql_type(link
) == WQL_WQS
);
3675 wqset
->wqset_id
= 0;
3679 * This set may have a lot of preposts, or may have been a member of
3680 * many other sets. To minimize spinlock hold times, we clear out the
3681 * waitq set data structure under the lock-hold, but don't clear any
3682 * table objects. We keep handles to the prepost and set linkage
3683 * objects and free those outside the critical section.
3686 if (wqset
->wqset_q
.waitq_prepost
&& wqset
->wqset_prepost_id
) {
3687 assert(link
!= NULL
);
3688 prepost_id
= wqset
->wqset_prepost_id
;
3690 /* else { TODO: notify kqueue subsystem? } */
3691 wqset
->wqset_prepost_id
= 0;
3693 wqset
->wqset_q
.waitq_fifo
= 0;
3694 wqset
->wqset_q
.waitq_prepost
= 0;
3695 wqset
->wqset_q
.waitq_isvalid
= 0;
3697 /* don't clear the 'waitq_irq' bit: it's used in locking! */
3698 wqset
->wqset_q
.waitq_eventmask
= 0;
3700 waitq_unlink_all_unlock(&wqset
->wqset_q
);
3701 /* wqset->wqset_q unlocked and set links deallocated */
3706 * walk_waitq_links may race with us for access to the waitq set.
3707 * If walk_waitq_links has a reference to the set, then we should wait
3708 * until the link's refcount goes to 1 (our reference) before we exit
3709 * this function. That way we ensure that the waitq set memory will
3710 * remain valid even though it's been cleared out.
3712 while (wql_refcnt(link
) > 1) {
3718 /* drop / unlink all the prepost table objects */
3719 /* JMM - can this happen before the delay? */
3721 (void)wq_prepost_iterate(prepost_id
, NULL
,
3722 wqset_clear_prepost_chain_cb
);
3727 * de-initialize and free an allocated waitq set object
3733 waitq_set_free(struct waitq_set
*wqset
)
3735 waitq_set_deinit(wqset
);
3737 memset(wqset
, 0, sizeof(*wqset
));
3738 zfree(waitq_set_zone
, wqset
);
3740 return KERN_SUCCESS
;
3743 #if DEVELOPMENT || DEBUG
3744 #if CONFIG_WAITQ_DEBUG
3746 * return the set ID of 'wqset'
3749 wqset_id(struct waitq_set
*wqset
)
3755 assert(waitqs_is_set(wqset
));
3757 if (!waitqs_is_linked(wqset
)) {
3758 waitq_set_lazy_init_link(wqset
);
3761 return wqset
->wqset_id
;
3765 * returns a pointer to the waitq object embedded in 'wqset'
3768 wqset_waitq(struct waitq_set
*wqset
)
3774 assert(waitqs_is_set(wqset
));
3776 return &wqset
->wqset_q
;
3778 #endif /* CONFIG_WAITQ_DEBUG */
3779 #endif /* DEVELOPMENT || DEBUG */
3783 * clear all preposts originating from 'waitq'
3787 * may (rarely) spin waiting for another on-core thread to
3788 * release the last reference to the waitq's prepost link object
3791 * If this function needs to spin, it will drop the waitq lock!
3792 * The return value of the function indicates whether or not this
3793 * happened: 1 == lock was dropped, 0 == lock held
3796 waitq_clear_prepost_locked(struct waitq
*waitq
)
3798 struct wq_prepost
*wqp
;
3799 int dropped_lock
= 0;
3801 assert(!waitq_irq_safe(waitq
));
3803 if (waitq
->waitq_prepost_id
== 0) {
3807 wqp
= wq_prepost_get(waitq
->waitq_prepost_id
);
3808 waitq
->waitq_prepost_id
= 0;
3810 uint64_t wqp_id
= wqp
->wqp_prepostid
.id
;
3811 wqdbg_v("invalidate prepost 0x%llx (refcnt:%d)",
3812 wqp
->wqp_prepostid
.id
, wqp_refcnt(wqp
));
3813 wq_prepost_invalidate(wqp
);
3814 while (wqp_refcnt(wqp
) > 1) {
3816 * Some other thread must have raced us to grab a link
3817 * object reference before we invalidated it. This
3818 * means that they are probably trying to access the
3819 * waitq to which the prepost object points. We need
3820 * to wait here until the other thread drops their
3821 * reference. We know that no one else can get a
3822 * reference (the object has been invalidated), and
3823 * that prepost references are short-lived (dropped on
3824 * a call to wq_prepost_put). We also know that no one
3825 * blocks while holding a reference therefore the
3826 * other reference holder must be on-core. We'll just
3827 * sit and wait for the other reference to be dropped.
3829 disable_preemption();
3831 waitq_unlock(waitq
);
3834 * don't yield here, just spin and assume the other
3835 * consumer is already on core...
3841 enable_preemption();
3843 if (wqp_refcnt(wqp
) > 0 && wqp
->wqp_prepostid
.id
== wqp_id
) {
3844 wq_prepost_put(wqp
);
3848 return dropped_lock
;
3852 * clear all preposts originating from 'waitq'
3855 * 'waitq' is not locked
3856 * may disable and re-enable interrupts
3859 waitq_clear_prepost(struct waitq
*waitq
)
3861 assert(waitq_valid(waitq
));
3862 assert(!waitq_irq_safe(waitq
));
3865 /* it doesn't matter to us if the lock is dropped here */
3866 (void)waitq_clear_prepost_locked(waitq
);
3867 waitq_unlock(waitq
);
3871 * return a the waitq's prepost object ID (allocate if necessary)
3874 * 'waitq' is unlocked
3877 waitq_get_prepost_id(struct waitq
*waitq
)
3879 struct wq_prepost
*wqp
;
3880 uint64_t wqp_id
= 0;
3882 if (!waitq_valid(waitq
)) {
3886 assert(!waitq_irq_safe(waitq
));
3890 if (!waitq_valid(waitq
)) {
3894 if (waitq
->waitq_prepost_id
) {
3895 wqp_id
= waitq
->waitq_prepost_id
;
3899 /* don't hold a spinlock while allocating a prepost object */
3900 waitq_unlock(waitq
);
3902 wqp
= wq_prepost_alloc(WQP_WQ
, 1);
3907 /* re-acquire the waitq lock */
3910 if (!waitq_valid(waitq
)) {
3911 wq_prepost_put(wqp
);
3916 if (waitq
->waitq_prepost_id
) {
3917 /* we were beat by someone else */
3918 wq_prepost_put(wqp
);
3919 wqp_id
= waitq
->waitq_prepost_id
;
3923 wqp
->wqp_wq
.wqp_wq_ptr
= waitq
;
3926 wqp_id
= wqp
->wqp_prepostid
.id
;
3927 waitq
->waitq_prepost_id
= wqp_id
;
3929 wq_prepost_put(wqp
);
3932 waitq_unlock(waitq
);
3939 waitq_inset_cb(struct waitq
*waitq
, void *ctx
, struct waitq_link
*link
)
3941 uint64_t setid
= *(uint64_t *)ctx
;
3942 int wqltype
= wql_type(link
);
3944 if (wqltype
== WQL_WQS
&& link
->wql_setid
.id
== setid
) {
3945 wqdbg_v(" waitq already in set 0x%llx", setid
);
3946 return WQ_ITERATE_FOUND
;
3947 } else if (wqltype
== WQL_LINK
) {
3949 * break out early if we see a link that points to the setid
3950 * in question. This saves us a step in the
3951 * iteration/recursion
3953 wqdbg_v(" waitq already in set 0x%llx (WQL_LINK)", setid
);
3954 if (link
->wql_link
.left_setid
== setid
||
3955 link
->wql_link
.right_setid
== setid
) {
3956 return WQ_ITERATE_FOUND
;
3960 return WQ_ITERATE_CONTINUE
;
3964 * determine if 'waitq' is a member of 'wqset'
3967 * neither 'waitq' nor 'wqset' is not locked
3968 * may disable and re-enable interrupts while locking 'waitq'
3971 waitq_member(struct waitq
*waitq
, struct waitq_set
*wqset
)
3973 kern_return_t kr
= WQ_ITERATE_SUCCESS
;
3976 if (!waitq_valid(waitq
)) {
3977 panic("Invalid waitq: %p", waitq
);
3979 assert(!waitq_irq_safe(waitq
));
3981 if (!waitqs_is_set(wqset
)) {
3987 if (!waitqs_is_linked(wqset
)) {
3991 setid
= wqset
->wqset_id
;
3993 /* fast path: most waitqs are members of only 1 set */
3994 if (waitq
->waitq_set_id
== setid
) {
3995 waitq_unlock(waitq
);
3999 /* walk the link table and look for the Set ID of wqset */
4000 kr
= walk_waitq_links(LINK_WALK_ONE_LEVEL
, waitq
, waitq
->waitq_set_id
,
4001 WQL_ALL
, (void *)&setid
, waitq_inset_cb
);
4004 waitq_unlock(waitq
);
4005 return kr
== WQ_ITERATE_FOUND
;
4009 * Returns true is the given waitq is a member of at least 1 set
4012 waitq_in_set(struct waitq
*waitq
)
4014 struct waitq_link
*link
;
4015 boolean_t inset
= FALSE
;
4017 if (waitq_irq_safe(waitq
)) {
4023 if (!waitq
->waitq_set_id
) {
4027 link
= wql_get_link(waitq
->waitq_set_id
);
4029 /* if we get here, the waitq is in _at_least_one_ set */
4033 /* we can just optimize this for next time */
4034 waitq
->waitq_set_id
= 0;
4038 waitq_unlock(waitq
);
4044 * pre-allocate a waitq link structure from the link table
4047 * 'waitq' is not locked
4048 * may (rarely) block if link table needs to grow
4051 waitq_link_reserve(struct waitq
*waitq
)
4053 struct waitq_link
*link
;
4054 uint64_t reserved_id
= 0;
4056 assert(get_preemption_level() == 0 && waitq_wait_possible(current_thread()));
4059 * We've asserted that the caller can block, so we enforce a
4060 * minimum-free table element policy here.
4062 wql_ensure_free_space();
4065 link
= wql_alloc_link(LT_RESERVED
);
4070 reserved_id
= link
->wql_setid
.id
;
4076 * release a pre-allocated waitq link structure
4079 waitq_link_release(uint64_t id
)
4081 struct waitq_link
*link
;
4087 link
= wql_get_reserved(id
, WQL_LINK
);
4093 * if we successfully got a link object, then we know
4094 * it's not been marked valid, and can be released with
4095 * a standard wql_put_link() which should free the element.
4098 #if CONFIG_LTABLE_STATS
4099 g_wqlinktable
.nreserved_releases
+= 1;
4104 * link 'waitq' to the set identified by 'setid' using the 'link' structure
4108 * caller should have a reference to the 'link' object
4110 static kern_return_t
4111 waitq_link_internal(struct waitq
*waitq
,
4112 uint64_t setid
, struct waitq_link
*link
)
4114 struct waitq_link
*qlink
;
4117 assert(waitq_held(waitq
));
4119 assert(setid
!= WQSET_NOT_LINKED
);
4122 * If the waitq_set_id field is empty, then this waitq is not
4123 * a member of any other set. All we have to do is update the
4126 if (!waitq
->waitq_set_id
) {
4127 waitq
->waitq_set_id
= setid
;
4128 return KERN_SUCCESS
;
4131 qlink
= wql_get_link(waitq
->waitq_set_id
);
4134 * The set to which this wait queue belonged has been
4135 * destroyed / invalidated. We can re-use the waitq field.
4137 waitq
->waitq_set_id
= setid
;
4138 return KERN_SUCCESS
;
4140 wql_put_link(qlink
);
4143 * Check to see if it's already a member of the set.
4145 * TODO: check for cycles!
4147 kr
= walk_waitq_links(LINK_WALK_ONE_LEVEL
, waitq
, waitq
->waitq_set_id
,
4148 WQL_ALL
, (void *)&setid
, waitq_inset_cb
);
4149 if (kr
== WQ_ITERATE_FOUND
) {
4150 return KERN_ALREADY_IN_SET
;
4154 * This wait queue is a member of at least one set already,
4155 * and _not_ a member of the given set. Use our previously
4156 * allocated link object, and hook it up to the wait queue.
4157 * Note that it's possible that one or more of the wait queue sets to
4158 * which the wait queue belongs was invalidated before we allocated
4159 * this link object. That's OK because the next time we use that
4160 * object we'll just ignore it.
4162 link
->wql_link
.left_setid
= setid
;
4163 link
->wql_link
.right_setid
= waitq
->waitq_set_id
;
4166 waitq
->waitq_set_id
= link
->wql_setid
.id
;
4168 return KERN_SUCCESS
;
4172 * link 'waitq' to 'wqset'
4175 * if 'lock_state' contains WAITQ_SHOULD_LOCK, 'waitq' must be unlocked.
4176 * Otherwise, 'waitq' must be locked.
4178 * may (rarely) block on link table allocation if the table has to grow,
4179 * and no 'reserved_link' object is passed.
4181 * may block and acquire wqset lock if the wqset passed has no link.
4184 * The caller can guarantee that this function will never block by
4185 * - pre-allocating a link table object and passing its ID in 'reserved_link'
4186 * - and pre-allocating the waitq set link calling waitq_set_lazy_init_link.
4187 * It is not possible to provide a reserved_link without having also linked
4191 waitq_link(struct waitq
*waitq
, struct waitq_set
*wqset
,
4192 waitq_lock_state_t lock_state
, uint64_t *reserved_link
)
4195 struct waitq_link
*link
;
4196 int should_lock
= (lock_state
== WAITQ_SHOULD_LOCK
);
4198 if (!waitq_valid(waitq
) || waitq_irq_safe(waitq
)) {
4199 panic("Invalid waitq: %p", waitq
);
4202 if (!waitqs_is_set(wqset
)) {
4203 return KERN_INVALID_ARGUMENT
;
4206 if (!reserved_link
|| *reserved_link
== 0) {
4207 if (!waitqs_is_linked(wqset
)) {
4208 waitq_set_lazy_init_link(wqset
);
4212 wqdbg_v("Link waitq %p to wqset 0x%llx",
4213 (void *)VM_KERNEL_UNSLIDE_OR_PERM(waitq
), wqset
->wqset_id
);
4216 * We _might_ need a new link object here, so we'll grab outside
4217 * the lock because the alloc call _might_ block.
4219 * If the caller reserved a link beforehand, then wql_get_link
4220 * is guaranteed not to block because the caller holds an extra
4221 * reference to the link which, in turn, hold a reference to the
4224 if (reserved_link
&& *reserved_link
!= 0) {
4225 link
= wql_get_reserved(*reserved_link
, WQL_LINK
);
4226 /* always consume the caller's reference */
4229 link
= wql_alloc_link(WQL_LINK
);
4232 return KERN_NO_SPACE
;
4239 kr
= waitq_link_internal(waitq
, wqset
->wqset_id
, link
);
4242 waitq_unlock(waitq
);
4251 * helper: unlink 'waitq' from waitq set identified by 'setid'
4252 * this function also prunes invalid objects from the tree
4255 * MUST be called from walk_waitq_links link table walk
4259 * This is a helper function which compresses the link table by culling
4260 * unused or unnecessary links. See comments below for different
4264 waitq_maybe_remove_link(struct waitq
*waitq
,
4266 struct waitq_link
*parent
,
4267 struct waitq_link
*left
,
4268 struct waitq_link
*right
)
4270 uint64_t *wq_setid
= &waitq
->waitq_set_id
;
4273 * There are two scenarios:
4276 * --------------------------------------------------------------------
4277 * waitq->waitq_set_id == parent
4283 * L(LINK/WQS_l) R(LINK/WQS_r)
4285 * In this scenario, we assert that the original waitq points to the
4286 * parent link we were passed in. If WQS_l (or WQS_r) is the waitq
4287 * set we're looking for, we can set the corresponding parent
4288 * link id (left or right) to 0. To compress the tree, we can reset the
4289 * waitq_set_id of the original waitq to point to the side of the
4290 * parent that is still valid. We then discard the parent link object.
4292 if (*wq_setid
== parent
->wql_setid
.id
) {
4293 if (!left
&& !right
) {
4294 /* completely invalid children */
4295 wql_invalidate(parent
);
4298 return WQ_ITERATE_INVALID
;
4299 } else if (!left
|| left
->wql_setid
.id
== setid
) {
4301 * left side matches we know it points either to the
4302 * WQS we're unlinking, or to an invalid object:
4303 * no need to invalidate it
4305 *wq_setid
= right
? right
->wql_setid
.id
: 0;
4306 wql_invalidate(parent
);
4308 return left
? WQ_ITERATE_UNLINKED
: WQ_ITERATE_INVALID
;
4309 } else if (!right
|| right
->wql_setid
.id
== setid
) {
4311 * if right side matches we know it points either to the
4312 * WQS we're unlinking, or to an invalid object:
4313 * no need to invalidate it
4315 *wq_setid
= left
? left
->wql_setid
.id
: 0;
4316 wql_invalidate(parent
);
4318 return right
? WQ_ITERATE_UNLINKED
: WQ_ITERATE_INVALID
;
4323 * the tree walk starts at the top-of-tree and moves down,
4324 * so these are safe asserts.
4326 assert(left
|| right
); /* one of them has to be valid at this point */
4330 * --------------------------------------------------------------------
4331 * waitq->waitq_set_id == ... (OR parent)
4344 * In this scenario, a leaf node of either the left or right side
4345 * could be the wait queue set we're looking to unlink. We also handle
4346 * the case where one of these links is invalid. If a leaf node is
4347 * invalid or it's the set we're looking for, we can safely remove the
4348 * middle link (left or right) and point the parent link directly to
4349 * the remaining leaf node.
4351 if (left
&& wql_type(left
) == WQL_LINK
) {
4353 struct waitq_link
*linkLl
, *linkLr
;
4354 assert(left
->wql_setid
.id
!= setid
);
4355 Ll
= left
->wql_link
.left_setid
;
4356 Lr
= left
->wql_link
.right_setid
;
4357 linkLl
= wql_get_link(Ll
);
4358 linkLr
= wql_get_link(Lr
);
4359 if (!linkLl
&& !linkLr
) {
4361 * The left object points to two invalid objects!
4362 * We can invalidate the left w/o touching the parent.
4364 wql_invalidate(left
);
4365 wqdbg_v("S2, Ll+Lr");
4366 return WQ_ITERATE_INVALID
;
4367 } else if (!linkLl
|| Ll
== setid
) {
4368 /* Ll is invalid and/or the wait queue set we're looking for */
4369 parent
->wql_link
.left_setid
= Lr
;
4370 wql_invalidate(left
);
4371 wql_put_link(linkLl
);
4372 wql_put_link(linkLr
);
4374 return linkLl
? WQ_ITERATE_UNLINKED
: WQ_ITERATE_INVALID
;
4375 } else if (!linkLr
|| Lr
== setid
) {
4376 /* Lr is invalid and/or the wait queue set we're looking for */
4377 parent
->wql_link
.left_setid
= Ll
;
4378 wql_invalidate(left
);
4379 wql_put_link(linkLr
);
4380 wql_put_link(linkLl
);
4382 return linkLr
? WQ_ITERATE_UNLINKED
: WQ_ITERATE_INVALID
;
4384 wql_put_link(linkLl
);
4385 wql_put_link(linkLr
);
4388 if (right
&& wql_type(right
) == WQL_LINK
) {
4390 struct waitq_link
*linkRl
, *linkRr
;
4391 assert(right
->wql_setid
.id
!= setid
);
4392 Rl
= right
->wql_link
.left_setid
;
4393 Rr
= right
->wql_link
.right_setid
;
4394 linkRl
= wql_get_link(Rl
);
4395 linkRr
= wql_get_link(Rr
);
4396 if (!linkRl
&& !linkRr
) {
4398 * The right object points to two invalid objects!
4399 * We can invalidate the right w/o touching the parent.
4401 wql_invalidate(right
);
4402 wqdbg_v("S2, Rl+Rr");
4403 return WQ_ITERATE_INVALID
;
4404 } else if (!linkRl
|| Rl
== setid
) {
4405 /* Rl is invalid and/or the wait queue set we're looking for */
4406 parent
->wql_link
.right_setid
= Rr
;
4407 wql_invalidate(right
);
4408 wql_put_link(linkRl
);
4409 wql_put_link(linkRr
);
4411 return linkRl
? WQ_ITERATE_UNLINKED
: WQ_ITERATE_INVALID
;
4412 } else if (!linkRr
|| Rr
== setid
) {
4413 /* Rr is invalid and/or the wait queue set we're looking for */
4414 parent
->wql_link
.right_setid
= Rl
;
4415 wql_invalidate(right
);
4416 wql_put_link(linkRl
);
4417 wql_put_link(linkRr
);
4419 return linkRr
? WQ_ITERATE_UNLINKED
: WQ_ITERATE_INVALID
;
4421 wql_put_link(linkRl
);
4422 wql_put_link(linkRr
);
4425 return WQ_ITERATE_CONTINUE
;
4429 * link table walk callback that unlinks 'waitq' from 'ctx->setid'
4432 * called from walk_waitq_links
4436 * uses waitq_maybe_remove_link() to compress the linktable and
4437 * perform the actual unlinking
4440 waitq_unlink_cb(struct waitq
*waitq
, void *ctx
,
4441 struct waitq_link
*link
)
4443 uint64_t setid
= *((uint64_t *)ctx
);
4444 struct waitq_link
*right
, *left
;
4447 if (wql_type(link
) != WQL_LINK
) {
4448 return WQ_ITERATE_CONTINUE
;
4452 left
= wql_get_link(link
->wql_link
.left_setid
);
4453 right
= wql_get_link(link
->wql_link
.right_setid
);
4455 ret
= waitq_maybe_remove_link(waitq
, setid
, link
, left
, right
);
4458 wql_put_link(right
);
4460 if (!wql_is_valid(link
)) {
4461 return WQ_ITERATE_INVALID
;
4463 /* A ret value of UNLINKED will break us out of table walk */
4464 } while (ret
== WQ_ITERATE_INVALID
);
4471 * undo/remove a prepost from 'ctx' (waitq) to 'wqset'
4474 * Called from wq_prepost_foreach_locked OR wq_prepost_iterate
4475 * 'wqset' may be NULL
4476 * (ctx)->unlink_wqset is locked
4479 waitq_unlink_prepost_cb(struct waitq_set __unused
*wqset
, void *ctx
,
4480 struct wq_prepost
*wqp
, struct waitq
*waitq
)
4482 struct wq_unlink_ctx
*ulctx
= (struct wq_unlink_ctx
*)ctx
;
4484 if (waitq
!= ulctx
->unlink_wq
) {
4485 return WQ_ITERATE_CONTINUE
;
4488 if (wqp_type(wqp
) == WQP_WQ
&&
4489 wqp
->wqp_prepostid
.id
== ulctx
->unlink_wqset
->wqset_prepost_id
) {
4490 /* this is the only prepost on this wait queue set */
4491 wqdbg_v("unlink wqp (WQ) 0x%llx", wqp
->wqp_prepostid
.id
);
4492 ulctx
->unlink_wqset
->wqset_prepost_id
= 0;
4493 return WQ_ITERATE_BREAK
;
4496 assert(wqp_type(wqp
) == WQP_POST
);
4499 * The prepost object 'wqp' points to a waitq which should no longer
4500 * be preposted to 'ulctx->unlink_wqset'. We can remove the prepost
4501 * object from the list and break out of the iteration. Using the
4502 * context object in this way allows this same callback function to be
4503 * used from both wq_prepost_foreach_locked and wq_prepost_iterate.
4505 wq_prepost_remove(ulctx
->unlink_wqset
, wqp
);
4506 return WQ_ITERATE_BREAK
;
4510 * unlink 'waitq' from 'wqset'
4514 * 'wqset' is _not_ locked
4515 * may (rarely) spin in prepost clear and drop/re-acquire 'waitq' lock
4516 * (see waitq_clear_prepost_locked)
4518 static kern_return_t
4519 waitq_unlink_locked(struct waitq
*waitq
,
4520 struct waitq_set
*wqset
)
4525 assert(!waitq_irq_safe(waitq
));
4527 if (waitq
->waitq_set_id
== 0) {
4530 * it doesn't belong to anyone, and it has a prepost object?
4531 * This is an artifact of not cleaning up after kqueues when
4532 * they prepost into select sets...
4534 if (waitq
->waitq_prepost_id
!= 0) {
4535 (void)waitq_clear_prepost_locked(waitq
);
4537 return KERN_NOT_IN_SET
;
4540 if (!waitqs_is_linked(wqset
)) {
4542 * No link has been allocated for the wqset,
4543 * so no waitq could have been linked to it.
4545 return KERN_NOT_IN_SET
;
4548 setid
= wqset
->wqset_id
;
4550 if (waitq
->waitq_set_id
== setid
) {
4551 waitq
->waitq_set_id
= 0;
4553 * This was the only set to which the waitq belonged: we can
4554 * safely release the waitq's prepost object. It doesn't
4555 * matter if this function drops and re-acquires the lock
4556 * because we're not manipulating waitq state any more.
4558 (void)waitq_clear_prepost_locked(waitq
);
4559 return KERN_SUCCESS
;
4563 * The waitq was a member of more that 1 set, so we need to
4564 * handle potentially compressing the link table, and
4565 * adjusting the waitq->waitq_set_id value.
4567 * Note: we can't free the waitq's associated prepost object (if any)
4568 * because it may be in use by the one or more _other_ sets to
4569 * which this queue belongs.
4571 * Note: This function only handles a single level of the queue linkage.
4572 * Removing a waitq from a set to which it does not directly
4573 * belong is undefined. For example, if a waitq belonged to set
4574 * A, and set A belonged to set B. You can't remove the waitq
4577 kr
= walk_waitq_links(LINK_WALK_ONE_LEVEL
, waitq
, waitq
->waitq_set_id
,
4578 WQL_LINK
, (void *)&setid
, waitq_unlink_cb
);
4580 if (kr
== WQ_ITERATE_UNLINKED
) {
4581 struct wq_unlink_ctx ulctx
;
4583 kr
= KERN_SUCCESS
; /* found it and dis-associated it */
4585 /* don't look for preposts if it's not prepost-enabled */
4586 if (!wqset
->wqset_q
.waitq_prepost
) {
4590 assert(!waitq_irq_safe(&wqset
->wqset_q
));
4592 waitq_set_lock(wqset
);
4594 * clear out any prepost from waitq into wqset
4595 * TODO: this could be more efficient than a linear search of
4596 * the waitq set's prepost list.
4598 ulctx
.unlink_wq
= waitq
;
4599 ulctx
.unlink_wqset
= wqset
;
4600 (void)wq_prepost_iterate(wqset
->wqset_prepost_id
, (void *)&ulctx
,
4601 waitq_unlink_prepost_cb
);
4602 waitq_set_unlock(wqset
);
4604 kr
= KERN_NOT_IN_SET
; /* waitq is _not_ associated with wqset */
4612 * unlink 'waitq' from 'wqset'
4615 * neither 'waitq' nor 'wqset' is locked
4616 * may disable and re-enable interrupts
4617 * may (rarely) spin in prepost clear
4618 * (see waitq_clear_prepost_locked)
4621 waitq_unlink(struct waitq
*waitq
, struct waitq_set
*wqset
)
4623 kern_return_t kr
= KERN_SUCCESS
;
4625 assert(waitqs_is_set(wqset
));
4628 * we allow the waitq to be invalid because the caller may be trying
4629 * to clear out old/dirty state
4631 if (!waitq_valid(waitq
)) {
4632 return KERN_INVALID_ARGUMENT
;
4635 wqdbg_v("unlink waitq %p from set 0x%llx",
4636 (void *)VM_KERNEL_UNSLIDE_OR_PERM(waitq
), wqset
->wqset_id
);
4638 assert(!waitq_irq_safe(waitq
));
4642 kr
= waitq_unlink_locked(waitq
, wqset
);
4644 waitq_unlock(waitq
);
4649 * unlink a waitq from a waitq set, but reference the waitq by its prepost ID
4652 * 'wqset' is unlocked
4653 * wqp_id may be valid or invalid
4656 waitq_unlink_by_prepost_id(uint64_t wqp_id
, struct waitq_set
*wqset
)
4658 struct wq_prepost
*wqp
;
4660 disable_preemption();
4661 wqp
= wq_prepost_get(wqp_id
);
4665 wq
= wqp
->wqp_wq
.wqp_wq_ptr
;
4668 * lock the waitq, then release our prepost ID reference, then
4669 * unlink the waitq from the wqset: this ensures that we don't
4670 * hold a prepost ID reference during the unlink, but we also
4671 * complete the unlink operation atomically to avoid a race
4672 * with waitq_unlink[_all].
4674 assert(!waitq_irq_safe(wq
));
4677 wq_prepost_put(wqp
);
4679 if (!waitq_valid(wq
)) {
4680 /* someone already tore down this waitq! */
4682 enable_preemption();
4686 /* this _may_ drop the wq lock, but that's OK */
4687 waitq_unlink_locked(wq
, wqset
);
4691 enable_preemption();
4697 * reference and lock a waitq by its prepost ID
4700 * wqp_id may be valid or invalid
4703 * a locked waitq if wqp_id was valid
4707 waitq_lock_by_prepost_id(uint64_t wqp_id
)
4709 struct waitq
*wq
= NULL
;
4710 struct wq_prepost
*wqp
;
4712 disable_preemption();
4713 wqp
= wq_prepost_get(wqp_id
);
4715 wq
= wqp
->wqp_wq
.wqp_wq_ptr
;
4717 assert(!waitq_irq_safe(wq
));
4720 wq_prepost_put(wqp
);
4722 if (!waitq_valid(wq
)) {
4723 /* someone already tore down this waitq! */
4725 enable_preemption();
4729 enable_preemption();
4735 * unlink 'waitq' from all sets to which it belongs
4738 * 'waitq' is locked on entry
4739 * returns with waitq lock dropped
4742 * may (rarely) spin (see waitq_clear_prepost_locked)
4745 waitq_unlink_all_unlock(struct waitq
*waitq
)
4747 uint64_t old_set_id
= 0;
4748 wqdbg_v("unlink waitq %p from all sets",
4749 (void *)VM_KERNEL_UNSLIDE_OR_PERM(waitq
));
4750 assert(!waitq_irq_safe(waitq
));
4752 /* it's not a member of any sets */
4753 if (waitq
->waitq_set_id
== 0) {
4754 waitq_unlock(waitq
);
4755 return KERN_SUCCESS
;
4758 old_set_id
= waitq
->waitq_set_id
;
4759 waitq
->waitq_set_id
= 0;
4762 * invalidate the prepost entry for this waitq.
4763 * This may drop and re-acquire the waitq lock, but that's OK because
4764 * if it was added to another set and preposted to that set in the
4765 * time we drop the lock, the state will remain consistent.
4767 (void)waitq_clear_prepost_locked(waitq
);
4769 waitq_unlock(waitq
);
4773 * Walk the link table and invalidate each LINK object that
4774 * used to connect this waitq to one or more sets: this works
4775 * because WQL_LINK objects are private to each wait queue
4777 (void)walk_waitq_links(LINK_WALK_ONE_LEVEL
, waitq
, old_set_id
,
4778 WQL_LINK
, NULL
, waitq_unlink_all_cb
);
4781 return KERN_SUCCESS
;
4785 * unlink 'waitq' from all sets to which it belongs
4788 * 'waitq' is not locked
4789 * may disable and re-enable interrupts
4791 * (see waitq_unlink_all_locked, waitq_clear_prepost_locked)
4794 waitq_unlink_all(struct waitq
*waitq
)
4796 kern_return_t kr
= KERN_SUCCESS
;
4798 if (!waitq_valid(waitq
)) {
4799 panic("Invalid waitq: %p", waitq
);
4802 assert(!waitq_irq_safe(waitq
));
4804 if (!waitq_valid(waitq
)) {
4805 waitq_unlock(waitq
);
4806 return KERN_SUCCESS
;
4809 kr
= waitq_unlink_all_unlock(waitq
);
4810 /* waitq unlocked and set links deallocated */
4817 * unlink all waitqs from 'wqset'
4820 * 'wqset' is locked on entry
4821 * 'wqset' is unlocked on exit and spl is restored
4824 * may (rarely) spin/block (see waitq_clear_prepost_locked)
4827 waitq_set_unlink_all_unlock(struct waitq_set
*wqset
)
4829 struct waitq_link
*link
;
4830 uint64_t prepost_id
;
4832 wqdbg_v("unlink all queues from set 0x%llx", wqset
->wqset_id
);
4835 * This operation does not require interaction with any of the set's
4836 * constituent wait queues. All we have to do is invalidate the SetID
4839 if (waitqs_is_linked(wqset
)) {
4840 /* invalidate and re-alloc the link object first */
4841 link
= wql_get_link(wqset
->wqset_id
);
4843 /* we may have raced with a waitq_set_deinit: handle this */
4845 waitq_set_unlock(wqset
);
4846 return KERN_SUCCESS
;
4849 wql_invalidate(link
);
4851 /* re-alloc the object to get a new generation ID */
4852 wql_realloc_link(link
, WQL_WQS
);
4853 link
->wql_wqs
.wql_set
= wqset
;
4855 wqset
->wqset_id
= link
->wql_setid
.id
;
4860 /* clear any preposts attached to this set */
4862 if (wqset
->wqset_q
.waitq_prepost
&& wqset
->wqset_prepost_id
) {
4863 prepost_id
= wqset
->wqset_prepost_id
;
4865 /* else { TODO: notify kqueue subsystem? } */
4866 wqset
->wqset_prepost_id
= 0;
4869 * clear set linkage and prepost object associated with this set:
4870 * waitq sets may prepost to other sets if, for example, they are
4871 * associated with a kqueue which is in a select set.
4873 * This releases all the set link objects
4874 * (links to other sets to which this set was previously added)
4876 waitq_unlink_all_unlock(&wqset
->wqset_q
);
4877 /* wqset->wqset_q unlocked */
4879 /* drop / unlink all the prepost table objects */
4881 (void)wq_prepost_iterate(prepost_id
, NULL
,
4882 wqset_clear_prepost_chain_cb
);
4885 return KERN_SUCCESS
;
4889 * unlink all waitqs from 'wqset'
4892 * 'wqset' is not locked
4893 * may (rarely) spin/block (see waitq_clear_prepost_locked)
4896 waitq_set_unlink_all(struct waitq_set
*wqset
)
4898 assert(waitqs_is_set(wqset
));
4899 assert(!waitq_irq_safe(&wqset
->wqset_q
));
4901 waitq_set_lock(wqset
);
4902 return waitq_set_unlink_all_unlock(wqset
);
4903 /* wqset unlocked and set links and preposts deallocated */
4907 waitq_prepost_reserve_cb(struct waitq
*waitq
, void *ctx
,
4908 struct waitq_link
*link
)
4910 uint32_t *num
= (uint32_t *)ctx
;
4914 * In the worst case, we'll have to allocate 2 prepost objects
4915 * per waitq set (if the set was already preposted by another
4918 if (wql_type(link
) == WQL_WQS
) {
4920 * check to see if the associated waitq actually supports
4923 if (waitq_set_can_prepost(link
->wql_wqs
.wql_set
)) {
4927 return WQ_ITERATE_CONTINUE
;
4931 waitq_alloc_prepost_reservation(int nalloc
, struct waitq
*waitq
,
4932 int *did_unlock
, struct wq_prepost
**wqp
)
4934 struct wq_prepost
*tmp
;
4935 struct wqp_cache
*cache
;
4940 * Before we unlock the waitq, check the per-processor prepost object
4941 * cache to see if there's enough there for us. If so, do the
4942 * allocation, keep the lock and save an entire iteration over the set
4946 disable_preemption();
4947 cache
= PERCPU_GET(wqp_cache
);
4948 if (nalloc
<= (int)cache
->avail
) {
4951 enable_preemption();
4953 /* unlock the waitq to perform the allocation */
4955 waitq_unlock(waitq
);
4959 tmp
= wq_prepost_alloc(LT_RESERVED
, nalloc
);
4961 panic("Couldn't reserve %d preposts for waitq @%p (wqp@%p)",
4962 nalloc
, waitq
, *wqp
);
4965 /* link the two lists */
4966 int __assert_only rc
;
4967 rc
= wq_prepost_rlink(tmp
, *wqp
);
4968 assert(rc
== nalloc
);
4973 * If the caller can block, then enforce a minimum-free table element
4974 * policy here. This helps ensure that we will have enough prepost
4975 * objects for callers such as selwakeup() that can be called with
4978 if (get_preemption_level() == 0) {
4979 wq_prepost_ensure_free_space();
4983 if (*did_unlock
== 0) {
4984 /* decrement the preemption count if alloc from cache */
4985 enable_preemption();
4987 /* otherwise: re-lock the waitq */
4996 waitq_count_prepost_reservation(struct waitq
*waitq
, int extra
, int keep_locked
)
5001 * If the waitq is not currently part of a set, and we're not asked to
5002 * keep the waitq locked then we'll want to have 3 in reserve
5003 * just-in-case it becomes part of a set while we unlock and reserve.
5004 * We may need up to 1 object for the waitq, and 2 for the set.
5006 if (waitq
->waitq_set_id
== 0) {
5009 /* this queue has never been preposted before */
5010 if (waitq
->waitq_prepost_id
== 0) {
5015 * Walk the set of table linkages associated with this waitq
5016 * and count the worst-case number of prepost objects that
5017 * may be needed during a wakeup_all. We can walk this without
5018 * locking each set along the way because the table-based IDs
5019 * disconnect us from the set pointers themselves, and the
5020 * table walking is careful to read the setid values only once.
5021 * Locking each set up the chain also doesn't guarantee that
5022 * their membership won't change between the time we unlock
5023 * that set and when we actually go to prepost, so our
5024 * situation is no worse than before and we've alleviated lock
5025 * contention on any sets to which this waitq belongs.
5027 (void)walk_waitq_links(LINK_WALK_FULL_DAG_UNLOCKED
,
5028 waitq
, waitq
->waitq_set_id
,
5029 WQL_WQS
, (void *)&npreposts
,
5030 waitq_prepost_reserve_cb
);
5037 if (npreposts
== 0 && !keep_locked
) {
5039 * If we get here, we were asked to reserve some prepost
5040 * objects for a waitq that's previously preposted, and is not
5041 * currently a member of any sets. We have also been
5042 * instructed to unlock the waitq when we're done. In this
5043 * case, we pre-allocated enough reserved objects to handle
5044 * the case where the waitq gets added to a single set when
5045 * the lock is released.
5055 * pre-allocate prepost objects for 'waitq'
5058 * 'waitq' is not locked
5063 * 0 on success, '*reserved' is set to the head of a singly-linked
5064 * list of pre-allocated prepost objects.
5067 * If 'lock_state' is WAITQ_KEEP_LOCKED, this function performs the pre-allocation
5068 * atomically and returns 'waitq' locked.
5070 * This function attempts to pre-allocate precisely enough prepost
5071 * objects based on the current set membership of 'waitq'. If the
5072 * operation is performed atomically, then the caller
5073 * is guaranteed to have enough pre-allocated prepost object to avoid
5074 * any (rare) blocking in the wakeup path.
5077 waitq_prepost_reserve(struct waitq
*waitq
, int extra
,
5078 waitq_lock_state_t lock_state
)
5080 uint64_t reserved
= 0;
5081 uint64_t prev_setid
= 0, prev_prepostid
= 0;
5082 struct wq_prepost
*wqp
= NULL
;
5083 int nalloc
= 0, npreposts
= 0;
5084 int keep_locked
= (lock_state
== WAITQ_KEEP_LOCKED
);
5087 wqdbg_v("Attempting to reserve prepost linkages for waitq %p (extra:%d)",
5088 (void *)VM_KERNEL_UNSLIDE_OR_PERM(waitq
), extra
);
5090 if (waitq
== NULL
&& extra
> 0) {
5092 * Simple prepost object allocation:
5093 * we'll add 2 more because the waitq might need an object,
5094 * and the set itself may need a new POST object in addition
5095 * to the number of preposts requested by the caller
5097 nalloc
= waitq_alloc_prepost_reservation(extra
+ 2, NULL
,
5099 assert(nalloc
== extra
+ 2);
5100 return wqp
->wqp_prepostid
.id
;
5103 assert(lock_state
== WAITQ_KEEP_LOCKED
|| lock_state
== WAITQ_UNLOCK
);
5105 assert(!waitq_irq_safe(waitq
));
5109 /* remember the set ID that we started with */
5110 prev_setid
= waitq
->waitq_set_id
;
5111 prev_prepostid
= waitq
->waitq_prepost_id
;
5114 * If the waitq is not part of a set, and we're asked to
5115 * keep the set locked, then we don't have to reserve
5118 if (prev_setid
== 0 && keep_locked
) {
5122 npreposts
= waitq_count_prepost_reservation(waitq
, extra
, keep_locked
);
5124 /* nothing for us to do! */
5125 if (npreposts
== 0) {
5133 /* this _may_ unlock and relock the waitq! */
5134 nalloc
= waitq_alloc_prepost_reservation(npreposts
, waitq
,
5138 /* allocation held the waitq lock: we'd done! */
5146 * Before we return, if the allocation had to unlock the waitq, we
5147 * must check one more time to see if we have enough. If not, we'll
5148 * try to allocate the difference. If the caller requests it, we'll
5149 * also leave the waitq locked so that the use of the pre-allocated
5150 * prepost objects can be guaranteed to be enough if a wakeup_all is
5151 * performed before unlocking the waitq.
5155 * If the waitq is no longer associated with a set, or if the waitq's
5156 * set/prepostid has not changed since we first walked its linkage,
5159 if ((waitq
->waitq_set_id
== 0) ||
5160 (waitq
->waitq_set_id
== prev_setid
&&
5161 waitq
->waitq_prepost_id
== prev_prepostid
)) {
5168 npreposts
= waitq_count_prepost_reservation(waitq
, extra
, keep_locked
);
5170 if (npreposts
> nalloc
) {
5171 prev_setid
= waitq
->waitq_set_id
;
5172 prev_prepostid
= waitq
->waitq_prepost_id
;
5173 npreposts
= npreposts
- nalloc
; /* only allocate the diff */
5182 waitq_unlock(waitq
);
5185 reserved
= wqp
->wqp_prepostid
.id
;
5192 * release a linked list of prepost objects allocated via _prepost_reserve
5195 * may (rarely) spin waiting for prepost table growth memcpy
5198 waitq_prepost_release_reserve(uint64_t id
)
5200 struct wq_prepost
*wqp
;
5202 wqdbg_v("releasing reserved preposts starting at: 0x%llx", id
);
5204 wqp
= wq_prepost_rfirst(id
);
5209 wq_prepost_release_rlist(wqp
);
5214 * clear all preposts from 'wqset'
5217 * 'wqset' is not locked
5220 waitq_set_clear_preposts(struct waitq_set
*wqset
)
5222 uint64_t prepost_id
;
5225 assert(waitqs_is_set(wqset
));
5227 if (!wqset
->wqset_q
.waitq_prepost
|| !wqset
->wqset_prepost_id
) {
5231 wqdbg_v("Clearing all preposted queues on waitq_set: 0x%llx",
5234 if (waitq_irq_safe(&wqset
->wqset_q
)) {
5237 waitq_set_lock(wqset
);
5238 prepost_id
= wqset
->wqset_prepost_id
;
5239 wqset
->wqset_prepost_id
= 0;
5240 waitq_set_unlock(wqset
);
5241 if (waitq_irq_safe(&wqset
->wqset_q
)) {
5245 /* drop / unlink all the prepost table objects */
5247 (void)wq_prepost_iterate(prepost_id
, NULL
,
5248 wqset_clear_prepost_chain_cb
);
5253 /* ----------------------------------------------------------------------
5255 * Iteration: waitq -> sets / waitq_set -> preposts
5257 * ---------------------------------------------------------------------- */
5262 waitq_iterator_t it
;
5266 waitq_iterate_sets_cb(struct waitq
*waitq
, void *ctx
,
5267 struct waitq_link
*link
)
5269 struct wq_it_ctx
*wctx
= (struct wq_it_ctx
*)(ctx
);
5270 struct waitq_set
*wqset
;
5274 assert(!waitq_irq_safe(waitq
));
5275 assert(wql_type(link
) == WQL_WQS
);
5278 * the waitq is locked, so we can just take the set lock
5279 * and call the iterator function
5281 wqset
= link
->wql_wqs
.wql_set
;
5282 assert(wqset
!= NULL
);
5283 assert(!waitq_irq_safe(&wqset
->wqset_q
));
5284 waitq_set_lock(wqset
);
5286 ret
= wctx
->it(wctx
->ctx
, (struct waitq
*)wctx
->input
, wqset
);
5288 waitq_set_unlock(wqset
);
5293 * call external iterator function for each prepost object in wqset
5296 * Called from wq_prepost_foreach_locked
5297 * (wqset locked, waitq _not_ locked)
5300 wqset_iterate_prepost_cb(struct waitq_set
*wqset
, void *ctx
,
5301 struct wq_prepost
*wqp
, struct waitq
*waitq
)
5303 struct wq_it_ctx
*wctx
= (struct wq_it_ctx
*)(ctx
);
5310 * This is a bit tricky. The 'wqset' is locked, but the 'waitq' is not.
5311 * Taking the 'waitq' lock is a lock order violation, so we need to be
5312 * careful. We also must realize that we may have taken a reference to
5313 * the 'wqp' just as the associated waitq was being torn down (or
5314 * clearing all its preposts) - see waitq_clear_prepost_locked(). If
5315 * the 'wqp' is valid and we can get the waitq lock, then we are good
5316 * to go. If not, we need to back off, check that the 'wqp' hasn't
5317 * been invalidated, and try to re-take the locks.
5319 assert(!waitq_irq_safe(waitq
));
5321 if (waitq_lock_try(waitq
)) {
5325 if (!wqp_is_valid(wqp
)) {
5326 return WQ_ITERATE_RESTART
;
5329 /* We are passed a prepost object with a reference on it. If neither
5330 * the waitq set nor the waitq require interrupts disabled, then we
5331 * may block on the delay(1) call below. We can't hold a prepost
5332 * object reference while blocking, so we have to give that up as well
5333 * and re-acquire it when we come back.
5335 wqp_id
= wqp
->wqp_prepostid
.id
;
5336 wq_prepost_put(wqp
);
5337 waitq_set_unlock(wqset
);
5338 wqdbg_v("dropped set:%p lock waiting for wqp:%p (0x%llx -> wq:%p)",
5339 wqset
, wqp
, wqp
->wqp_prepostid
.id
, waitq
);
5341 waitq_set_lock(wqset
);
5342 wqp
= wq_prepost_get(wqp_id
);
5344 /* someone cleared preposts while we slept! */
5345 return WQ_ITERATE_DROPPED
;
5350 * This differs slightly from the logic in ipc_mqueue.c:
5351 * ipc_mqueue_receive_on_thread(). There, if the waitq lock
5352 * can't be obtained, the prepost link is placed on the back of
5353 * the chain, and the iteration starts from the beginning. Here,
5354 * we just restart from the beginning.
5356 return WQ_ITERATE_RESTART
;
5359 if (!wqp_is_valid(wqp
)) {
5360 ret
= WQ_ITERATE_RESTART
;
5364 /* call the external callback */
5365 ret
= wctx
->it(wctx
->ctx
, waitq
, wqset
);
5367 if (ret
== WQ_ITERATE_BREAK_KEEP_LOCKED
) {
5368 ret
= WQ_ITERATE_BREAK
;
5373 waitq_unlock(waitq
);
5379 * iterator over all sets to which the given waitq has been linked
5385 waitq_iterate_sets(struct waitq
*waitq
, void *ctx
, waitq_iterator_t it
)
5388 struct wq_it_ctx wctx
= {
5389 .input
= (void *)waitq
,
5393 if (!it
|| !waitq
) {
5394 return KERN_INVALID_ARGUMENT
;
5397 ret
= walk_waitq_links(LINK_WALK_ONE_LEVEL
, waitq
, waitq
->waitq_set_id
,
5398 WQL_WQS
, (void *)&wctx
, waitq_iterate_sets_cb
);
5399 if (ret
== WQ_ITERATE_CONTINUE
) {
5400 ret
= WQ_ITERATE_SUCCESS
;
5406 * iterator over all preposts in the given wqset
5412 waitq_set_iterate_preposts(struct waitq_set
*wqset
,
5413 void *ctx
, waitq_iterator_t it
)
5415 struct wq_it_ctx wctx
= {
5416 .input
= (void *)wqset
,
5420 if (!it
|| !wqset
) {
5421 return WQ_ITERATE_INVALID
;
5424 assert(waitq_held(&wqset
->wqset_q
));
5426 return wq_prepost_foreach_locked(wqset
, (void *)&wctx
,
5427 wqset_iterate_prepost_cb
);
5431 /* ----------------------------------------------------------------------
5435 * ---------------------------------------------------------------------- */
5439 * declare a thread's intent to wait on 'waitq' for 'wait_event'
5442 * 'waitq' is not locked
5445 waitq_assert_wait64(struct waitq
*waitq
,
5446 event64_t wait_event
,
5447 wait_interrupt_t interruptible
,
5450 thread_t thread
= current_thread();
5454 if (!waitq_valid(waitq
)) {
5455 panic("Invalid waitq: %p", waitq
);
5458 if (waitq_irq_safe(waitq
)) {
5463 ret
= waitq_assert_wait64_locked(waitq
, wait_event
, interruptible
,
5464 TIMEOUT_URGENCY_SYS_NORMAL
,
5465 deadline
, TIMEOUT_NO_LEEWAY
, thread
);
5466 waitq_unlock(waitq
);
5468 if (waitq_irq_safe(waitq
)) {
5476 * declare a thread's intent to wait on 'waitq' for 'wait_event'
5479 * 'waitq' is not locked
5480 * will disable and re-enable interrupts while locking current_thread()
5483 waitq_assert_wait64_leeway(struct waitq
*waitq
,
5484 event64_t wait_event
,
5485 wait_interrupt_t interruptible
,
5486 wait_timeout_urgency_t urgency
,
5491 thread_t thread
= current_thread();
5494 if (!waitq_valid(waitq
)) {
5495 panic("Invalid waitq: %p", waitq
);
5498 if (waitq_irq_safe(waitq
)) {
5503 ret
= waitq_assert_wait64_locked(waitq
, wait_event
, interruptible
,
5504 urgency
, deadline
, leeway
, thread
);
5505 waitq_unlock(waitq
);
5507 if (waitq_irq_safe(waitq
)) {
5515 * wakeup a single thread from a waitq that's waiting for a given event
5518 * 'waitq' is not locked
5519 * may (rarely) block if 'waitq' is non-global and a member of 1 or more sets
5520 * may disable and re-enable interrupts
5523 * will _not_ block if waitq is global (or not a member of any set)
5526 waitq_wakeup64_one(struct waitq
*waitq
, event64_t wake_event
,
5527 wait_result_t result
, int priority
)
5530 uint64_t reserved_preposts
= 0;
5533 if (!waitq_valid(waitq
)) {
5534 panic("Invalid waitq: %p", waitq
);
5537 if (!waitq_irq_safe(waitq
)) {
5538 /* reserve preposts in addition to locking the waitq */
5539 reserved_preposts
= waitq_prepost_reserve(waitq
, 0, WAITQ_KEEP_LOCKED
);
5545 /* waitq is locked upon return */
5546 kr
= waitq_wakeup64_one_locked(waitq
, wake_event
, result
,
5547 &reserved_preposts
, priority
, WAITQ_UNLOCK
, WQ_OPTION_NONE
);
5549 if (waitq_irq_safe(waitq
)) {
5553 /* release any left-over prepost object (won't block/lock anything) */
5554 waitq_prepost_release_reserve(reserved_preposts
);
5560 * wakeup all threads from a waitq that are waiting for a given event
5563 * 'waitq' is not locked
5564 * may (rarely) block if 'waitq' is non-global and a member of 1 or more sets
5565 * may disable and re-enable interrupts
5568 * will _not_ block if waitq is global (or not a member of any set)
5571 waitq_wakeup64_all(struct waitq
*waitq
,
5572 event64_t wake_event
,
5573 wait_result_t result
,
5577 uint64_t reserved_preposts
= 0;
5580 if (!waitq_valid(waitq
)) {
5581 panic("Invalid waitq: %p", waitq
);
5584 if (!waitq_irq_safe(waitq
)) {
5585 /* reserve preposts in addition to locking waitq */
5586 reserved_preposts
= waitq_prepost_reserve(waitq
, 0,
5593 ret
= waitq_wakeup64_all_locked(waitq
, wake_event
, result
,
5594 &reserved_preposts
, priority
,
5597 if (waitq_irq_safe(waitq
)) {
5601 waitq_prepost_release_reserve(reserved_preposts
);
5607 * wakeup a specific thread iff it's waiting on 'waitq' for 'wake_event'
5610 * 'waitq' is not locked
5613 * May temporarily disable and re-enable interrupts
5616 waitq_wakeup64_thread(struct waitq
*waitq
,
5617 event64_t wake_event
,
5619 wait_result_t result
)
5624 if (!waitq_valid(waitq
)) {
5625 panic("Invalid waitq: %p", waitq
);
5628 if (waitq_irq_safe(waitq
)) {
5633 ret
= waitq_select_thread_locked(waitq
, wake_event
, thread
, &th_spl
);
5634 /* on success, returns 'thread' locked */
5636 waitq_unlock(waitq
);
5638 if (ret
== KERN_SUCCESS
) {
5639 ret
= thread_go(thread
, result
, WQ_OPTION_NONE
);
5640 assert(ret
== KERN_SUCCESS
);
5641 thread_unlock(thread
);
5643 waitq_stats_count_wakeup(waitq
);
5645 ret
= KERN_NOT_WAITING
;
5646 waitq_stats_count_fail(waitq
);
5649 if (waitq_irq_safe(waitq
)) {
5657 * wakeup a single thread from a waitq that's waiting for a given event
5658 * and return a reference to that thread
5659 * returns THREAD_NULL if no thread was waiting
5662 * 'waitq' is not locked
5663 * may (rarely) block if 'waitq' is non-global and a member of 1 or more sets
5664 * may disable and re-enable interrupts
5667 * will _not_ block if waitq is global (or not a member of any set)
5670 waitq_wakeup64_identify(struct waitq
*waitq
,
5671 event64_t wake_event
,
5672 wait_result_t result
,
5675 uint64_t reserved_preposts
= 0;
5676 spl_t thread_spl
= 0;
5680 if (!waitq_valid(waitq
)) {
5681 panic("Invalid waitq: %p", waitq
);
5684 if (!waitq_irq_safe(waitq
)) {
5685 /* reserve preposts in addition to locking waitq */
5686 reserved_preposts
= waitq_prepost_reserve(waitq
, 0, WAITQ_KEEP_LOCKED
);
5692 thread
= waitq_wakeup64_identify_locked(waitq
, wake_event
, result
,
5693 &thread_spl
, &reserved_preposts
,
5694 priority
, WAITQ_UNLOCK
);
5695 /* waitq is unlocked, thread is locked */
5697 if (thread
!= THREAD_NULL
) {
5698 thread_reference(thread
);
5699 thread_unlock(thread
);
5703 if (waitq_irq_safe(waitq
)) {
5707 /* release any left-over prepost object (won't block/lock anything) */
5708 waitq_prepost_release_reserve(reserved_preposts
);
5710 /* returns +1 ref to running thread or THREAD_NULL */