xref: /xnu-11215.41.3/osfmk/kern/turnstile.h (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1 /*
2  * Copyright (c) 2017 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #ifndef _TURNSTILE_H_
30 #define _TURNSTILE_H_
31 
32 #include <mach/mach_types.h>
33 #include <mach/kern_return.h>
34 #include <sys/cdefs.h>
35 
36 __BEGIN_DECLS
37 
38 #if PRIVATE
39 #define TURNSTILE_MAX_HOP_DEFAULT (10)
40 struct turnstile_stats {
41 	uint64_t ts_priority_propagation;
42 	uint64_t ts_no_inheritor;
43 	uint64_t ts_thread_runnable;
44 	uint64_t ts_no_priority_change_required;
45 	uint64_t ts_above_ui_pri_change;
46 	uint64_t ts_no_turnstile;
47 };
48 #endif
49 
50 #ifdef KERNEL_PRIVATE
51 #include <kern/queue.h>
52 #include <sys/queue.h>
53 #include <kern/waitq.h>
54 #include <kern/priority_queue.h>
55 #include <os/refcnt.h>
56 #include <kern/assert.h>
57 #include <kern/kern_types.h>
58 #include <kern/locks.h>
59 
60 /*
61  * turnstile_type_t : Indicates the type of primitive the turnstile is associated with
62  *                    Please populate turnstile_promote_policy array if a new type is added here.
63  */
64 typedef enum __attribute__((packed)) turnstile_type {
65 	TURNSTILE_NONE = 0,
66 	TURNSTILE_KERNEL_MUTEX = 1,
67 	TURNSTILE_ULOCK = 2,
68 	TURNSTILE_PTHREAD_MUTEX = 3,
69 	TURNSTILE_SYNC_IPC = 4,
70 	TURNSTILE_WORKLOOPS = 5,
71 	TURNSTILE_WORKQS = 6,
72 	TURNSTILE_KNOTE = 7,
73 	TURNSTILE_SLEEP_INHERITOR = 8,
74 	TURNSTILE_EPOCH_KERNEL = 9,
75 	TURNSTILE_EPOCH_USER = 10,
76 	TURNSTILE_TOTAL_TYPES = 11,
77 } turnstile_type_t;
78 
79 /*
80  * For each type of turnstile, following are the type of
81  * inheritors passed:
82  *
83  * TURNSTILE_KERNEL_MUTEX
84  *    Interlock: kernel mutex interlock.
85  *    Inheritor: threads.
86  *    Lock order: turnstile lock, thread lock.
87  *
88  * TURNSTILE_ULOCK
89  *    Interlock: ulocks interlock.
90  *    Inheritor: threads.
91  *    Lock order: turnstile lock, thread lock.
92  *
93  * TURNSTILE_PTHREAD_MUTEX
94  *    Interlock: pthread mtx interlock.
95  *    Inheritor: threads.
96  *    Lock order: turnstile lock, thread lock.
97  *
98  * TURNSTILE_SYNC_IPC
99  *    Interlock: port's mqueue lock
100  *    Inheritor: turnstile (of port in which we are enqueued or WL turnstile.
101  *    Lock order: Our turnstile, then turnstile of the port we are enqueued in.
102  *                Port circularity will make sure there is never a cycle formation
103  *                and lock order is maintained.
104  *
105  * TURNSTILE_WORKLOOPS
106  *    Interlock:
107  *    - kq req lock
108  *    - wq lock when "filt_wlworkq_interlock_needed() is true"
109  *    Inheritor: thread, turnstile (of workq)
110  *    Lock order: turnstile lock, thread lock
111  *                WL turnstile lock, Workq turnstile lock
112  *
113  * TURNSTILE_WORKQS
114  *    Interlock: workqueue lock
115  *    Inheritor: thread
116  *    Lock order: turnstile lock, thread lock.
117  *
118  * TURNSTILE_KNOTE
119  *    Interlock: the knote lock
120  *    Inheritor: WL turnstile
121  *
122  * TURNSTILE_SLEEP_INHERITOR
123  *    Interlock: turnstile_htable bucket spinlock.
124  *    Inheritor: threads.
125  *    Lock order: turnstile lock, thread lock.
126  *
127  * TURNSTILE_EPOCH_KERNEL
128  *    Interlock: the epoch sync interlock.
129  *    Inheritor: threads.
130  *    Lock order: turnstile lock, thread lock.
131  *
132  * TURNSTILE_EPOCH_USER
133  *    Interlock: the epoch sync interlock.
134  *    Inheritor: threads.
135  *    Lock order: turnstile lock, thread lock.
136  */
137 
138 typedef enum __attribute__((flag_enum)) turnstile_promote_policy {
139 	TURNSTILE_PROMOTE_NONE = 0,
140 	TURNSTILE_KERNEL_PROMOTE = 0x1,
141 	TURNSTILE_USER_PROMOTE = 0x2,
142 	TURNSTILE_USER_IPC_PROMOTE = 0x4,
143 } turnstile_promote_policy_t;
144 
145 typedef enum __attribute__((flag_enum)) turnstile_hash_lock_policy {
146 	TURNSTILE_HASH_LOCK_POLICY_NONE = 0,
147 	TURNSTILE_IRQ_UNSAFE_HASH = 0x1,
148 	TURNSTILE_LOCKED_HASH = 0x2,
149 } turnstile_hash_lock_policy_t;
150 
151 /*
152  * Turnstile state flags
153  *
154  * The turnstile state flags represent the current ownership of a turnstile.
155  * The supported flags are:
156  * - TURNSTILE_STATE_THREAD	: Turnstile is attached to a thread
157  * - TURNSTILE_STATE_FREELIST	: Turnstile is hanging off the freelist of another turnstile
158  * - TURNSTILE_STATE_HASHTABLE	: Turnstile is in the global hash table as the turnstile for a primitive
159  * - TURNSTILE_STATE_PROPRIETOR : Turnstile is attached to a proprietor
160  *
161  * The flag updates are done while holding the primitive interlock.
162  * */
163 
164 #define TURNSTILE_STATE_THREAD          0x1
165 #define TURNSTILE_STATE_FREELIST        0x2
166 #define TURNSTILE_STATE_HASHTABLE       0x4
167 #define TURNSTILE_STATE_PROPRIETOR      0x8
168 
169 /* Helper macros to set/unset turnstile state flags */
170 #if DEVELOPMENT || DEBUG
171 
172 #define turnstile_state_init(ts, state)         \
173 MACRO_BEGIN                                     \
174 	        ts->ts_state = state;           \
175 MACRO_END
176 
177 #define turnstile_state_add(ts, state)          \
178 MACRO_BEGIN                                     \
179 	        assert((ts->ts_state & (state)) == 0);  \
180 	        ts->ts_state |= state;                  \
181 MACRO_END
182 
183 #define turnstile_state_remove(ts, state)       \
184 MACRO_BEGIN                                     \
185 	        assert(ts->ts_state & (state));         \
186 	        ts->ts_state &= ~(state);               \
187 MACRO_END
188 
189 #else  /* DEVELOPMENT || DEBUG */
190 
191 #define turnstile_state_init(ts, state)         \
192 MACRO_BEGIN                                     \
193 	        (void)ts;                       \
194 MACRO_END
195 
196 #define turnstile_state_add(ts, state)          \
197 MACRO_BEGIN                                     \
198 	        (void)ts;                       \
199 MACRO_END
200 
201 #define turnstile_state_remove(ts, state)       \
202 MACRO_BEGIN                                     \
203 	        (void)ts;                       \
204 MACRO_END
205 
206 #endif /* DEVELOPMENT || DEBUG */
207 
208 struct knote;
209 struct turnstile;
210 
211 /*
212  * Turnstile update flags
213  *
214  * TURNSTILE_IMMEDIATE_UPDATE
215  *    When passed to turnstile_update_inheritor
216  *    update the inheritor of the turnstile in
217  *    the same call.
218  *
219  * TURNSTILE_DELAYED_UPDATE
220  *    When passed to turnstile_update_inheritor
221  *    it stashed the inheritor on the thread and
222  *    turnstile's inheritor is updated in
223  *    assert wait.
224  *
225  * TURNSTILE_INHERITOR_THREAD
226  *    The turnstile inheritor is of type thread.
227  *
228  * TURNSTILE_INHERITOR_TURNSTILE
229  *    The turnstile inheritor is of type turnstile.
230  *
231  * TURNSTILE_INHERITOR_WORKQ
232  *    The turnstile inheritor is of type workqueue
233  *
234  * TURNSTILE_INHERITOR_NEEDS_PRI_UPDATE
235  *    The inheritor needs a chain priority update.
236  *
237  * TURNSTILE_NEEDS_PRI_UPDATE
238  *    Current turnstile needs a chain priority update.
239  *
240  * Locking order for passing thread and turnstile as inheritor
241  *
242  * Thread as an inheritor:
243  *    When thread is passed as an inheritor of a turnstile
244  *    turnstile lock is taken and then thread lock.
245  *
246  * Turnstile as in inheritor:
247  *    When turnstile (T1) is passed as an inheritor of
248  *    a turnstile (T2), turnstile lock of T2 is taken
249  *    and then turnstile lock of T1 is taken.
250  *
251  * Caution: While passing turnstile as an inheritor, its
252  *    job of the adopter to make sure that there is no
253  *    lock inversion.
254  */
255 typedef enum __attribute__((flag_enum)) __attribute__((packed)) turnstile_update_flags {
256 	TURNSTILE_UPDATE_FLAGS_NONE = 0,
257 	TURNSTILE_IMMEDIATE_UPDATE = 0x1,
258 	TURNSTILE_DELAYED_UPDATE = 0x2,
259 	TURNSTILE_INHERITOR_THREAD = 0x4,
260 	TURNSTILE_INHERITOR_TURNSTILE = 0x8,
261 	TURNSTILE_INHERITOR_NEEDS_PRI_UPDATE = 0x10,
262 	TURNSTILE_NEEDS_PRI_UPDATE = 0x20,
263 	TURNSTILE_INHERITOR_WORKQ = 0x40,
264 	TURNSTILE_UPDATE_BOOST = 0x80,
265 } turnstile_update_flags_t;
266 
267 #define TURNSTILE_NULL ((struct turnstile *)0)
268 
269 typedef void * turnstile_inheritor_t;
270 
271 #define TURNSTILE_INHERITOR_NULL NULL
272 
273 #ifdef XNU_KERNEL_PRIVATE
274 #pragma GCC visibility push(hidden)
275 
276 /* Turnstile stats update flags
277  *
278  * TSU_TURNSTILE_BLOCK_COUNT
279  *    thread blocking on turnstile waitq, increment global
280  *    thread block on turnstile count.
281  *
282  * TSU_REGULAR_WAITQ_BLOCK_COUNT
283  *    thread blocking on regular waitq, increment global
284  *    thread block on regular waitq count.
285  *
286  * TSU_PRI_PROPAGATION
287  *    turnstile propagation update stopped at nth hop, update
288  *    priority change count for nth element in stats array.
289  *
290  * TSU_NO_INHERITOR
291  *    turnstile propagation update stopped due to turnstile
292  *    not having an inheritor after nth hop, update the no
293  *    inheritor count for nth element in the stats array.
294  *
295  * TSU_NO_TURNSTILE
296  *    turnstile propagation update stopped due to thread
297  *    not blocked on a turnstile waitq after nth hop, update
298  *    the no turnstile count for the nth element in the stats
299  *    array.
300  *
301  * TSU_NO_PRI_CHANGE_NEEDED
302  *    turnstile propagation update stopped due to thread or
303  *    turnstile having the correct priority or not blocked.
304  *    update the no priority change count for the nth element
305  *    in the stats array.
306  *
307  * TSU_THREAD_RUNNABLE
308  *    turnstile propagation update stopped due to thread
309  *    being runnable, update the thread runnable count for
310  *    the nth element in the stats array.
311  *
312  * TSU_ABOVE_UI_PRI_CHANGE
313  *    turnstile propagation caused an above UI priority change.
314  */
315 typedef enum __attribute__((flag_enum)) turnstile_stats_update_flags {
316 	TSU_FLAGS_NONE = 0,
317 	TSU_TURNSTILE_BLOCK_COUNT = 0x1,
318 	TSU_REGULAR_WAITQ_BLOCK_COUNT = 0x2,
319 	TSU_PRI_PROPAGATION = 0x4,
320 	TSU_NO_INHERITOR = 0x8,
321 	TSU_NO_TURNSTILE = 0x10,
322 	TSU_NO_PRI_CHANGE_NEEDED = 0x20,
323 	TSU_THREAD_RUNNABLE = 0x40,
324 	TSU_ABOVE_UI_PRI_CHANGE = 0x80,
325 	TSU_THREAD_ARG = 0x100,
326 	TSU_TURNSTILE_ARG = 0x200,
327 	TSU_BOOST_ARG = 0x400,
328 } turnstile_stats_update_flags_t;
329 
330 SLIST_HEAD(turnstile_list, turnstile);
331 
332 #define CTSID_BITS         20
333 #define CTSID_MASK         ((1u << CTSID_BITS) - 1)
334 #define CTSID_MAX          (CTSID_MASK - 1)
335 
336 struct turnstile {
337 	union {
338 		/*
339 		 * The waitq_eventmask field is only used on the global queues.
340 		 * We hence repurpose all those bits for our own use.
341 		 */
342 #if MACH_KERNEL_PRIVATE
343 		WAITQ_FLAGS(ts_waitq
344 		    , __ts_unused_bits: 7
345 		    , ts_compact_id: CTSID_BITS);
346 #endif
347 		struct waitq          ts_waitq;              /* waitq embedded in turnstile */
348 	};
349 #define ts_inheritor  ts_waitq.waitq_inheritor               /* thread/turnstile inheriting the priority (IL, WL) */
350 	union {
351 		struct turnstile_list ts_free_turnstiles;    /* turnstile free list (IL) */
352 		SLIST_ENTRY(turnstile) ts_free_elm;          /* turnstile free list element (IL) */
353 	};
354 	struct priority_queue_sched_max ts_inheritor_queue;  /* Queue of turnstile with us as an inheritor (WL) */
355 	struct priority_queue_entry_sched ts_inheritor_links;    /* Inheritor queue links */
356 	SLIST_ENTRY(turnstile)        ts_htable_link;        /* linkage for turnstile in global hash table */
357 	uintptr_t                     ts_proprietor;         /* hash key lookup turnstile (IL) */
358 	os_ref_atomic_t               ts_refcount;           /* reference count for turnstiles */
359 	_Atomic uint32_t              ts_type_gencount;      /* gen count used for priority chaining (IL), type of turnstile (IL) */
360 	uint32_t                      ts_prim_count;         /* counter used by the primitive */
361 	turnstile_update_flags_t      ts_inheritor_flags;    /* flags for turnstile inheritor (IL, WL) */
362 	uint8_t                       ts_priority;           /* priority of turnstile (WL) */
363 
364 #if DEVELOPMENT || DEBUG
365 	uint8_t                       ts_state;              /* current state of turnstile (IL) */
366 	thread_t                      ts_thread;             /* thread the turnstile is attached to */
367 	thread_t                      ts_prev_thread;        /* thread the turnstile was attached before donation */
368 #endif
369 };
370 
371 #define waitq_to_turnstile(waitq) __container_of(waitq, struct turnstile, ts_waitq)
372 
373 /* IL - interlock, WL - turnstile lock i.e. waitq lock */
374 
375 #define TURNSTILE_PROPRIETOR_NULL 0ul
376 
377 /*
378  * Name: turnstiles_init
379  *
380  * Description: Initialize turnstile sub system.
381  *
382  * Args: None.
383  *
384  * Returns: None.
385  */
386 void
387 turnstiles_init(void);
388 
389 /*
390  * Name: turnstile_alloc
391  *
392  * Description: Allocate a turnstile.
393  *
394  * Args: None.
395  *
396  * Returns:
397  *   turnstile on Success.
398  */
399 struct turnstile *
400 turnstile_alloc(void);
401 
402 /*
403  * Name: turnstile_compact_id_get()
404  *
405  * Description: Allocate a compact turnstile ID slot.
406  *
407  * Args: None.
408  *
409  * Returns:
410  *   A non 0 compact compact turnstile ID.
411  */
412 uint32_t
413 turnstile_compact_id_get(void);
414 
415 /*
416  * Name: turnstile_compact_id_put()
417  *
418  * Description: Frees a compact turnstile ID slot.
419  *
420  * Args:
421  *   Args1: the compact ID to free.
422  */
423 void
424 turnstile_compact_id_put(uint32_t cid);
425 
426 /*
427  * Name: turnstile_get_by_id
428  *
429  * Description: Resolve a turnstile by compact ID
430  *
431  * Args:
432  *   Arg1: turnstile compact ID
433  *
434  * Returns: a turnstile
435  */
436 struct turnstile *
437 turnstile_get_by_id(uint32_t tsid);
438 
439 /*
440  * Name: turnstile_reference
441  *
442  * Description: Take a reference on the turnstile.
443  *
444  * Arg1: turnstile
445  *
446  * Returns: None.
447  */
448 void
449 turnstile_reference(struct turnstile *turnstile);
450 
451 /*
452  * Name: turnstile_deallocate
453  *
454  * Description: Drop a reference on the turnstile.
455  *              Destroy the turnstile if the last ref.
456  *
457  * Arg1: turnstile
458  *
459  * Returns: None.
460  */
461 void
462 turnstile_deallocate(struct turnstile *turnstile);
463 
464 /*
465  * Name: turnstile_waitq_add_thread_priority_queue
466  *
467  * Description: add thread to the turnstile waitq
468  *
469  * Arg1: waitq
470  * Arg2: thread
471  *
472  * Conditions: waitq locked
473  */
474 void
475 turnstile_waitq_add_thread_priority_queue(
476 	struct waitq* wq,
477 	thread_t thread);
478 
479 /*
480  * Name: turnstile_recompute_priority_locked
481  *
482  * Description: Update turnstile priority based
483  *              on highest waiter thread and highest blocking
484  *              turnstile.
485  *
486  * Args: turnstile
487  *
488  * Returns: TRUE: if the turnstile priority changed and needs propagation.
489  *          FALSE: if the turnstile priority did not change or it does not need propagation.
490  *
491  * Condition: turnstile locked
492  */
493 boolean_t
494 turnstile_recompute_priority_locked(
495 	struct turnstile *turnstile);
496 
497 /*
498  * Name: turnstile_recompute_priority
499  *
500  * Description: Update turnstile priority based
501  *              on highest waiter thread and highest blocking
502  *              turnstile.
503  *
504  * Args: turnstile
505  *
506  * Returns: TRUE: if the turnstile priority changed and needs propagation.
507  *          FALSE: if the turnstile priority did not change or it does not need propagation.
508  */
509 boolean_t
510 turnstile_recompute_priority(
511 	struct turnstile *turnstile);
512 
513 /*
514  * Name: turnstile_workq_proprietor_of_max_turnstile
515  *
516  * Description: Returns the highest priority and proprietor of a turnstile
517  *              pushing on a workqueue turnstile.
518  *
519  *              This will not return waiters that are at priority
520  *              MAXPRI_THROTTLE or lower.
521  *
522  * Args: turnstile
523  *
524  * Returns:
525  *    Priority of the max entry, or 0
526  *    Pointer to the max entry proprietor
527  */
528 int
529 turnstile_workq_proprietor_of_max_turnstile(
530 	struct turnstile *turnstile,
531 	uintptr_t *proprietor);
532 
533 /*
534  * Name: turnstile_workloop_pusher_info
535  *
536  * Description: Returns the priority of the turnstile push for a workloop,
537  *              and the thread or knote responsible for this push.
538  *
539  * Args: workloop turnstile
540  *
541  * Returns:
542  *    Priority of the push or 0
543  *    Thread (with a +1 reference) with that push or THREAD_NULL.
544  *    Port (with a +1 reference) with that push, or IP_NULL.
545  *    Sync IPC knote with the highest push (or NULL)
546  */
547 int
548 turnstile_workloop_pusher_info(
549 	struct turnstile *turnstile,
550 	thread_t *thread,
551 	ipc_port_t *port,
552 	struct knote **knote_out);
553 
554 /*
555  * Name: turnstile_cleanup
556  *
557  * Description: Update priority of a turnstile inheritor
558  *              if needed.
559  *
560  * Args: inheritor and flags passed on thread struct.
561  *
562  * Returns: None.
563  */
564 void
565 turnstile_cleanup(void);
566 
567 /*
568  * Name: turnstile_update_thread_priority_chain
569  *
570  * Description: Priority of a thread blocked on a turnstile
571  *              has changed, update the turnstile priority.
572  *
573  * Arg1: thread: thread whose priority has changed.
574  *
575  * Returns: None.
576  */
577 void
578 turnstile_update_thread_priority_chain(thread_t thread);
579 
580 /*
581  * Name: turnstile_update_inheritor_locked
582  *
583  * Description: Update the inheritor of the turnstile and boost the
584  *              inheritor, called with turnstile locked.
585  *
586  * Args:
587  *   Arg1: turnstile
588  *   Implicit arg: new inheritor value is stashed in current thread's struct
589  *
590  * Returns:
591  *   old inheritor reference is returned on current thread's struct.
592  */
593 void
594 turnstile_update_inheritor_locked(struct turnstile *turnstile);
595 
596 /*
597  * Name: thread_get_inheritor_turnstile_base_priority
598  *
599  * Description: Get the max base priority of all the inheritor turnstiles
600  *
601  * Arg1: thread
602  *
603  * Returns: Max base priority of all the inheritor turnstiles.
604  *
605  * Condition: thread locked
606  */
607 int
608 thread_get_inheritor_turnstile_base_priority(thread_t thread);
609 
610 /*
611  * Name: thread_get_inheritor_turnstile_sched_priority
612  *
613  * Description: Get the max sched priority of all the inheritor turnstiles
614  *
615  * Arg1: thread
616  *
617  * Returns: Max sched priority of all the inheritor turnstiles.
618  *
619  * Condition: thread locked
620  */
621 int
622 thread_get_inheritor_turnstile_sched_priority(thread_t thread);
623 
624 /*
625  * Name: thread_get_waiting_turnstile
626  *
627  * Description: Get the turnstile if the thread is waiting on a turnstile.
628  *
629  * Arg1: thread
630  *
631  * Returns: turnstile: if the thread is blocked on a turnstile.
632  *          TURNSTILE_NULL: otherwise.
633  *
634  * Condition: thread locked.
635  */
636 struct turnstile *
637 thread_get_waiting_turnstile(thread_t thread);
638 
639 /*
640  * Name: turnstile_lookup_by_proprietor
641  *
642  * Description: Get turnstile for a proprietor from global
643  *              turnstile hash.
644  *
645  * Arg1: port
646  * Arg2: turnstile_type_t type
647  *
648  * Returns: turnstile: if the proprietor has a turnstile.
649  *          TURNSTILE_NULL: otherwise.
650  *
651  * Condition: proprietor interlock held.
652  */
653 struct turnstile *
654 turnstile_lookup_by_proprietor(uintptr_t proprietor, turnstile_type_t type);
655 
656 /*
657  * Name: turnstile_has_waiters
658  *
659  * Description: returns if there are waiters on the turnstile
660  *
661  * Arg1: turnstile: turnstile
662  *
663  * Returns: TRUE if there are waiters, FALSE otherwise.
664  */
665 
666 boolean_t
667 turnstile_has_waiters(struct turnstile *turnstile);
668 
669 /*
670  * Name: turnstile_stats_update
671  *
672  * Description: Function to update turnstile stats for dev kernel.
673  *
674  * Arg1: hops : number of thread hops in priority propagation
675  * Arg2: flags : turnstile stats update flags
676  * Arg3: inheritor: inheritor
677  *
678  * Returns: Nothing
679  */
680 void
681 turnstile_stats_update(
682 	int hop __assert_only,
683 	turnstile_stats_update_flags_t flags __assert_only,
684 	turnstile_inheritor_t inheritor __assert_only);
685 
686 #if DEVELOPMENT || DEBUG
687 
688 #define SYSCTL_TURNSTILE_TEST_USER_DEFAULT              1
689 #define SYSCTL_TURNSTILE_TEST_USER_HASHTABLE            2
690 #define SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT            3
691 #define SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE          4
692 
693 /* Functions used by debug test primitive exported by sysctls */
694 int
695 tstile_test_prim_lock(int val);
696 
697 int
698 tstile_test_prim_unlock(int val);
699 
700 int
701 turnstile_get_boost_stats_sysctl(void *req);
702 int
703 turnstile_get_unboost_stats_sysctl(void *req);
704 #endif /* DEVELOPMENT || DEBUG */
705 
706 #pragma GCC visibility pop
707 #endif /* XNU_KERNEL_PRIVATE */
708 
709 /* Interface */
710 
711 /*
712  * Name: turnstile_hash_bucket_lock
713  *
714  * Description: locks the spinlock associated with proprietor's bucket.
715  *              if proprietor is specified the index for the hash will be
716  *              recomputed and returned in index_proprietor,
717  *              otherwise the value save in index_proprietor is used as index.
718  *
719  * Args:
720  *   Arg1: proprietor (key) for hashing
721  *   Arg2: index for proprietor in the hash
722  *   Arg3: turnstile type
723  *
724  * Returns: old value of irq if irq were disabled before acquiring the lock.
725  */
726 unsigned
727 turnstile_hash_bucket_lock(uintptr_t proprietor, uint32_t *index_proprietor, turnstile_type_t type);
728 
729 /*
730  * Name: turnstile_hash_bucket_unlock
731  *
732  * Description: unlocks the spinlock associated with proprietor's bucket.
733  *              if proprietor is specified the index for the hash will be
734  *              recomputed and returned in index_proprietor,
735  *              otherwise the value save in index_proprietor is used as index.
736  *
737  * Args:
738  *   Arg1: proprietor (key) for hashing
739  *   Arg2: index for proprietor in the hash
740  *   Arg3: turnstile type
741  *   Arg4: irq value returned by turnstile_hash_bucket_lock
742  *
743  */
744 void
745 turnstile_hash_bucket_unlock(uintptr_t proprietor, uint32_t *index_proprietor, turnstile_type_t type, unsigned s);
746 
747 /*
748  * Name: turnstile_prepare
749  *
750  * Description: Transfer current thread's turnstile to primitive or it's free turnstile list.
751  *              Function is called holding the interlock (spinlock) of the primitive.
752  *              The turnstile returned by this function is safe to use until
753  *              the thread calls turnstile_complete.
754  *              When no turnstile is provided explicitly, the calling thread will not have a turnstile attached to
755  *              it until it calls turnstile_complete.
756  *
757  * Args:
758  *   Arg1: proprietor
759  *   Arg2: pointer in primitive struct to store turnstile
760  *   Arg3: turnstile to use instead of taking it from thread.
761  *   Arg4: type of primitive
762  *
763  * Returns:
764  *   turnstile.
765  */
766 struct turnstile *
767 turnstile_prepare(
768 	uintptr_t proprietor,
769 	struct turnstile **tstore,
770 	struct turnstile *turnstile,
771 	turnstile_type_t type);
772 
773 /*
774  * Name: turnstile_complete
775  *
776  * Description: Transfer the primitive's turnstile or from it's freelist to current thread.
777  *              Function is called holding the interlock (spinlock) of the primitive.
778  *              Current thread will have a turnstile attached to it after this call.
779  *
780  * Args:
781  *   Arg1: proprietor
782  *   Arg2: pointer in primitive struct to update turnstile
783  *   Arg3: pointer to store the returned turnstile instead of attaching it to thread
784  *   Arg4: type of primitive
785  *
786  * Returns:
787  *   None.
788  */
789 void
790 turnstile_complete(
791 	uintptr_t proprietor,
792 	struct turnstile **tstore,
793 	struct turnstile **turnstile,
794 	turnstile_type_t type);
795 
796 /*
797  * Name: turnstile_prepare_compact_id
798  *
799  * Description: Transfer current thread's turnstile to primitive or it's free turnstile list.
800  *              Function is called holding the interlock (spinlock) of the primitive.
801  *              The turnstile returned by this function is safe to use until
802  *              the thread calls turnstile_complete_compact_id.
803  *              The calling thread will not have a turnstile attached to
804  *              it until it calls turnstile_complete_compact_id.
805  *
806  * Args:
807  *   Arg1: proprietor
808  *   Arg2: the current compact ID for the turnstile head
809  *   Arg3: type of primitive
810  *
811  * Returns:
812  *   turnstile.
813  */
814 struct turnstile *
815 turnstile_prepare_compact_id(
816 	uintptr_t proprietor,
817 	uint32_t compact_id,
818 	turnstile_type_t type);
819 
820 /*
821  * Name: turnstile_complete_compact_id
822  *
823  * Description: Transfer the primitive's turnstile or from it's freelist to current thread.
824  *              Function is called holding the interlock (spinlock) of the primitive.
825  *              Current thread will have a turnstile attached to it after this call.
826  *
827  * Args:
828  *   Arg1: proprietor
829  *   Arg2: the turnstile pointer that was returned by turnstile_prepare_compact_id()
830  *   Arg3: type of primitive
831  *
832  * Returns:
833  *   Whether the primitive no longer has a turnstile.
834  */
835 bool
836 turnstile_complete_compact_id(
837 	uintptr_t proprietor,
838 	struct turnstile *turnstile,
839 	turnstile_type_t type);
840 
841 /*
842  * Name: turnstile_prepare_hash
843  *
844  * Description: Transfer current thread's turnstile to primitive or it's free turnstile list.
845  *              Function is called holding the interlock (spinlock) of the primitive.
846  *              The turnstile returned by this function is safe to use until
847  *              the thread calls turnstile_complete_hash.
848  *              The calling thread will not have a turnstile attached to
849  *              it until it calls turnstile_complete_hash.
850  *
851  *              The turnstile used for this proprietor will be stored in
852  *              a global hash table.
853  *
854  * Args:
855  *   Arg1: proprietor
856  *   Arg3: type of primitive
857  *
858  * Returns:
859  *   turnstile.
860  */
861 struct turnstile *
862 turnstile_prepare_hash(
863 	uintptr_t proprietor,
864 	turnstile_type_t type);
865 
866 /*
867  * Name: turnstile_complete_hash
868  *
869  * Description: Transfer the primitive's turnstile or from it's freelist to current thread.
870  *              Function is called holding the interlock (spinlock) of the primitive.
871  *              Current thread will have a turnstile attached to it after this call.
872  *
873  * Args:
874  *   Arg1: proprietor
875  *   Arg3: type of primitive
876  *
877  * Returns:
878  *   None.
879  */
880 void
881 turnstile_complete_hash(
882 	uintptr_t proprietor,
883 	turnstile_type_t type);
884 
885 /*
886  * Name: turnstile_update_inheritor
887  *
888  * Description: Update the inheritor of the turnstile and boost the
889  *              inheritor. It will take a thread reference on the inheritor.
890  *              Called with the interlock of the primitive held.
891  *
892  * Args:
893  *   Arg1: turnstile
894  *   Arg2: inheritor
895  *   Arg3: flags - TURNSTILE_DELAYED_UPDATE - update will happen later in assert_wait
896  *
897  * Returns:
898  *   old inheritor reference is stashed on current thread's struct.
899  */
900 void
901 turnstile_update_inheritor(
902 	struct turnstile *turnstile,
903 	turnstile_inheritor_t new_inheritor,
904 	turnstile_update_flags_t flags);
905 
906 typedef enum turnstile_update_complete_flags {
907 	TURNSTILE_INTERLOCK_NOT_HELD = 0x1,
908 	TURNSTILE_INTERLOCK_HELD = 0x2,
909 } turnstile_update_complete_flags_t;
910 
911 /*
912  * Name: turnstile_update_inheritor_complete
913  *
914  * Description: Update turnstile inheritor's priority and propagate the
915  *              priority if the inheritor is blocked on a turnstile.
916  *              Consumes thread ref of old inheritor returned by
917  *              turnstile_update_inheritor. Recursive priority update
918  *              will only happen when called with interlock dropped.
919  *
920  * Args:
921  *   Arg1: turnstile
922  *   Arg2: interlock held
923  *
924  * Returns: None.
925  */
926 void
927 turnstile_update_inheritor_complete(
928 	struct turnstile *turnstile,
929 	turnstile_update_complete_flags_t flags);
930 
931 
932 /*
933  * Name: turnstile_kernel_update_inheritor_on_wake_locked
934  *
935  * Description: Set thread as the inheritor of the turnstile and
936  *		boost the inheritor.
937  * Args:
938  *   Arg1: turnstile
939  *   Arg2: new_inheritor
940  *   Arg3: flags
941  *
942  * Called with turnstile locked
943  */
944 void
945 turnstile_kernel_update_inheritor_on_wake_locked(
946 	struct turnstile *turnstile,
947 	turnstile_inheritor_t new_inheritor,
948 	turnstile_update_flags_t flags);
949 
950 #endif /* KERNEL_PRIVATE */
951 #if XNU_KERNEL_PRIVATE
952 
953 struct workqueue;
954 
955 /* pthread_workqueue.c */
956 extern void workq_reference(struct workqueue *wq);
957 extern void workq_deallocate_safe(struct workqueue *wq);
958 extern bool workq_is_current_thread_updating_turnstile(struct workqueue *wq);
959 extern void workq_schedule_creator_turnstile_redrive(struct workqueue *wq,
960     bool locked);
961 
962 #endif /* XNU_KERNEL_PRIVATE */
963 
964 __END_DECLS
965 
966 #endif /* _TURNSTILE_H_ */
967