xref: /xnu-12377.81.4/osfmk/kern/mpsc_queue.h (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1*043036a2SApple OSS Distributions /*
2*043036a2SApple OSS Distributions  * Copyright (c) 2018 Apple Inc. All rights reserved.
3*043036a2SApple OSS Distributions  *
4*043036a2SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*043036a2SApple OSS Distributions  *
6*043036a2SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*043036a2SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*043036a2SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*043036a2SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*043036a2SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*043036a2SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*043036a2SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*043036a2SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*043036a2SApple OSS Distributions  *
15*043036a2SApple OSS Distributions  * Please obtain a copy of the License at
16*043036a2SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*043036a2SApple OSS Distributions  *
18*043036a2SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*043036a2SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*043036a2SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*043036a2SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*043036a2SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*043036a2SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*043036a2SApple OSS Distributions  * limitations under the License.
25*043036a2SApple OSS Distributions  *
26*043036a2SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*043036a2SApple OSS Distributions  */
28*043036a2SApple OSS Distributions 
29*043036a2SApple OSS Distributions #ifndef _KERN_MPSC_QUEUE_H_
30*043036a2SApple OSS Distributions #define _KERN_MPSC_QUEUE_H_
31*043036a2SApple OSS Distributions 
32*043036a2SApple OSS Distributions #ifdef XNU_KERNEL_PRIVATE
33*043036a2SApple OSS Distributions 
34*043036a2SApple OSS Distributions #include <machine/atomic.h>
35*043036a2SApple OSS Distributions #include <kern/macro_help.h>
36*043036a2SApple OSS Distributions #include <kern/thread_call.h>
37*043036a2SApple OSS Distributions 
38*043036a2SApple OSS Distributions #endif // XNU_KERNEL_PRIVATE
39*043036a2SApple OSS Distributions 
40*043036a2SApple OSS Distributions #include <sys/cdefs.h>
41*043036a2SApple OSS Distributions 
42*043036a2SApple OSS Distributions __BEGIN_DECLS __ASSUME_PTR_ABI_SINGLE_BEGIN
43*043036a2SApple OSS Distributions 
44*043036a2SApple OSS Distributions /*!
45*043036a2SApple OSS Distributions  * @typedef struct mpsc_queue_chain
46*043036a2SApple OSS Distributions  *
47*043036a2SApple OSS Distributions  * @brief
48*043036a2SApple OSS Distributions  * Type for the intrusive linkage used by MPSC queues.
49*043036a2SApple OSS Distributions  */
50*043036a2SApple OSS Distributions typedef struct mpsc_queue_chain {
51*043036a2SApple OSS Distributions #if __has_ptrcheck // work around 78354145
52*043036a2SApple OSS Distributions 	struct mpsc_queue_chain *volatile mpqc_next;
53*043036a2SApple OSS Distributions #else
54*043036a2SApple OSS Distributions 	struct mpsc_queue_chain *_Atomic mpqc_next;
55*043036a2SApple OSS Distributions #endif
56*043036a2SApple OSS Distributions } *mpsc_queue_chain_t;
57*043036a2SApple OSS Distributions 
58*043036a2SApple OSS Distributions /*!
59*043036a2SApple OSS Distributions  * @typedef struct mpsc_queue_head
60*043036a2SApple OSS Distributions  *
61*043036a2SApple OSS Distributions  * @brief
62*043036a2SApple OSS Distributions  * The type for a multi-producer single-consumer queue.
63*043036a2SApple OSS Distributions  *
64*043036a2SApple OSS Distributions  * @discussion
65*043036a2SApple OSS Distributions  * MPSC queues allow for producers to not be affected by other producers or the
66*043036a2SApple OSS Distributions  * consumer. Which means in turn that having producers in interrupt context
67*043036a2SApple OSS Distributions  * does not require that other producers disable interrupts like a traditional
68*043036a2SApple OSS Distributions  * spinlock based approach would require.
69*043036a2SApple OSS Distributions  *
70*043036a2SApple OSS Distributions  * These queues shine when data is produced from the entire system and is
71*043036a2SApple OSS Distributions  * consumed from a single serial context (logging, tracing, ...).
72*043036a2SApple OSS Distributions  * mpsc_daemon_queue_t is provided as a fully ready/easy-to-use pre-packaged
73*043036a2SApple OSS Distributions  * solution for these common use cases.
74*043036a2SApple OSS Distributions  *
75*043036a2SApple OSS Distributions  * - mpsc_queue_append() can be used to append a single item
76*043036a2SApple OSS Distributions  * - mpsc_queue_append_list() can be used to append a batch of items at once.
77*043036a2SApple OSS Distributions  *
78*043036a2SApple OSS Distributions  * Functions for the consumer side assume proper serialization that is not
79*043036a2SApple OSS Distributions  * provided by the MPSC queue itself. Dequeuing doesn't require preemption
80*043036a2SApple OSS Distributions  * to be disabled.
81*043036a2SApple OSS Distributions  *
82*043036a2SApple OSS Distributions  * <h2>Algorithm</h2>
83*043036a2SApple OSS Distributions  *
84*043036a2SApple OSS Distributions  * The base of the enqueue algorithm is a single atomic exchange (first half,
85*043036a2SApple OSS Distributions  * called __mpsc_queue_append_update_tail) and a list fixup (2nd half, called
86*043036a2SApple OSS Distributions  * __mpsc_queue_append_update_prev).
87*043036a2SApple OSS Distributions  *
88*043036a2SApple OSS Distributions  * Graphically, enqueuing `X` looks like this, with each step being done
89*043036a2SApple OSS Distributions  * atomically (for the empty queue case, `tail` points to `head`):
90*043036a2SApple OSS Distributions  *
91*043036a2SApple OSS Distributions  *     | orig state          | update_tail         | update_prev         |
92*043036a2SApple OSS Distributions  *     +---------------------+---------------------+---------------------+
93*043036a2SApple OSS Distributions  *     |                     |                     |                     |
94*043036a2SApple OSS Distributions  *     | head -> e1 -> e2 -. | head -> e1 -> e2 -. | head -> e1 -> e2 -. |
95*043036a2SApple OSS Distributions  *     |                   | |                   | |                   | |
96*043036a2SApple OSS Distributions  *     |         ,- ... <--' |         ,- ... <--' |         ,- ... <--' |
97*043036a2SApple OSS Distributions  *     |         |           |         |           |         |           |
98*043036a2SApple OSS Distributions  *     |         v           |         v           |         v           |
99*043036a2SApple OSS Distributions  *     | tail -> eN -> NULL  | tail    eN -> NULL  | tail    eN          |
100*043036a2SApple OSS Distributions  *     |                     |   |                 |   |     |           |
101*043036a2SApple OSS Distributions  *     |                     |   |                 |   |     v           |
102*043036a2SApple OSS Distributions  *     |         X -> NULL   |   `---> X -> NULL   |   '---> X -> NULL   |
103*043036a2SApple OSS Distributions  *     |                     |                     |                     |
104*043036a2SApple OSS Distributions  *     +---------------------+---------------------+---------------------+
105*043036a2SApple OSS Distributions  *
106*043036a2SApple OSS Distributions  *
107*043036a2SApple OSS Distributions  * There is a small 1-instruction gap of inconsistency which makes the chosen
108*043036a2SApple OSS Distributions  * algorithm non linearizable, and requires enqueuers to disable preemption
109*043036a2SApple OSS Distributions  * during the enqueue so as not to starve the consumer forever.
110*043036a2SApple OSS Distributions  *
111*043036a2SApple OSS Distributions  * As far as memory visibility is concerned, enqueuing uses a release fence in
112*043036a2SApple OSS Distributions  * update_tail which pairs with memory fences in mpsc_queue_dequeue_batch().
113*043036a2SApple OSS Distributions  *
114*043036a2SApple OSS Distributions  * Note: as far as the data structure in memory, its layout is equivalent to
115*043036a2SApple OSS Distributions  *       a BSD <sys/queue.h> STAILQ. However because of this inconsistency
116*043036a2SApple OSS Distributions  *       window and memory ordering concerns, it is incorrect to use STAILQ
117*043036a2SApple OSS Distributions  *       macros on an MPSC queue.
118*043036a2SApple OSS Distributions  */
119*043036a2SApple OSS Distributions typedef struct mpsc_queue_head {
120*043036a2SApple OSS Distributions 	struct mpsc_queue_chain mpqh_head;
121*043036a2SApple OSS Distributions #if __has_ptrcheck // work around 78354145
122*043036a2SApple OSS Distributions 	struct mpsc_queue_chain *volatile mpqh_tail;
123*043036a2SApple OSS Distributions #else
124*043036a2SApple OSS Distributions 	struct mpsc_queue_chain *_Atomic mpqh_tail;
125*043036a2SApple OSS Distributions #endif
126*043036a2SApple OSS Distributions } *mpsc_queue_head_t;
127*043036a2SApple OSS Distributions 
128*043036a2SApple OSS Distributions /*!
129*043036a2SApple OSS Distributions  * @macro MPSC_QUEUE_INITIALIZER
130*043036a2SApple OSS Distributions  *
131*043036a2SApple OSS Distributions  * @brief
132*043036a2SApple OSS Distributions  * Macro to use in static initializers for mpsc queues.
133*043036a2SApple OSS Distributions  *
134*043036a2SApple OSS Distributions  * @param head
135*043036a2SApple OSS Distributions  * The name of the variable to initialize.
136*043036a2SApple OSS Distributions  */
137*043036a2SApple OSS Distributions #define MPSC_QUEUE_INITIALIZER(head)   { .mpqh_tail = &(head).mpqh_head }
138*043036a2SApple OSS Distributions 
139*043036a2SApple OSS Distributions #ifdef XNU_KERNEL_PRIVATE
140*043036a2SApple OSS Distributions 
141*043036a2SApple OSS Distributions /*!
142*043036a2SApple OSS Distributions  * @function mpsc_queue_init
143*043036a2SApple OSS Distributions  *
144*043036a2SApple OSS Distributions  * @brief
145*043036a2SApple OSS Distributions  * Dynamically initialize an mpsc queue.
146*043036a2SApple OSS Distributions  *
147*043036a2SApple OSS Distributions  * @discussion
148*043036a2SApple OSS Distributions  * This initialization assumes that the object holding the queue head
149*043036a2SApple OSS Distributions  * is initialized before it can be made visible to other threads/cores.
150*043036a2SApple OSS Distributions  *
151*043036a2SApple OSS Distributions  * @param q
152*043036a2SApple OSS Distributions  * The queue to initialize.
153*043036a2SApple OSS Distributions  */
154*043036a2SApple OSS Distributions static inline void
mpsc_queue_init(mpsc_queue_head_t q)155*043036a2SApple OSS Distributions mpsc_queue_init(mpsc_queue_head_t q)
156*043036a2SApple OSS Distributions {
157*043036a2SApple OSS Distributions 	os_atomic_init(&q->mpqh_head.mpqc_next, NULL);
158*043036a2SApple OSS Distributions 	os_atomic_init(&q->mpqh_tail, &q->mpqh_head);
159*043036a2SApple OSS Distributions }
160*043036a2SApple OSS Distributions 
161*043036a2SApple OSS Distributions /*!
162*043036a2SApple OSS Distributions  * @typedef enum mpsc_queue_options
163*043036a2SApple OSS Distributions  */
164*043036a2SApple OSS Distributions typedef enum mpsc_queue_options {
165*043036a2SApple OSS Distributions 	MPSC_QUEUE_NONE                = 0,
166*043036a2SApple OSS Distributions 	MPSC_QUEUE_DISABLE_PREEMPTION  = 1 << 0,
167*043036a2SApple OSS Distributions } mpsc_queue_options_t;
168*043036a2SApple OSS Distributions 
169*043036a2SApple OSS Distributions /*!
170*043036a2SApple OSS Distributions  * @const MPSC_QUEUE_NOTQUEUED_MARKER
171*043036a2SApple OSS Distributions  *
172*043036a2SApple OSS Distributions  * @brief
173*043036a2SApple OSS Distributions  * Magical marker that implementations can use to poison the chain pointer of
174*043036a2SApple OSS Distributions  * elements not on any MPSC queue.
175*043036a2SApple OSS Distributions  */
176*043036a2SApple OSS Distributions #define MPSC_QUEUE_NOTQUEUED_MARKER ((mpsc_queue_chain_t)~0ul)
177*043036a2SApple OSS Distributions 
178*043036a2SApple OSS Distributions /*!
179*043036a2SApple OSS Distributions  * @macro mpsc_queue_element
180*043036a2SApple OSS Distributions  *
181*043036a2SApple OSS Distributions  * @brief
182*043036a2SApple OSS Distributions  * Macro to find the pointer of an element back from its MPSC chain linkage.
183*043036a2SApple OSS Distributions  */
184*043036a2SApple OSS Distributions #define mpsc_queue_element(ptr, type, field) __container_of(ptr, type, field)
185*043036a2SApple OSS Distributions 
186*043036a2SApple OSS Distributions 
187*043036a2SApple OSS Distributions #pragma mark Advanced Multi Producer calls
188*043036a2SApple OSS Distributions 
189*043036a2SApple OSS Distributions /**
190*043036a2SApple OSS Distributions  * @function __mpsc_queue_append_update_tail
191*043036a2SApple OSS Distributions  *
192*043036a2SApple OSS Distributions  * @brief
193*043036a2SApple OSS Distributions  * First half of the enqueue operation onto a multi-producer single-consumer
194*043036a2SApple OSS Distributions  * queue.
195*043036a2SApple OSS Distributions  *
196*043036a2SApple OSS Distributions  * @discussion
197*043036a2SApple OSS Distributions  * This function is available for algorithms that need to do things (such as
198*043036a2SApple OSS Distributions  * taking a refcount) before calling __mpsc_queue_append_update_prev().
199*043036a2SApple OSS Distributions  *
200*043036a2SApple OSS Distributions  * Preemption should be disabled before calling
201*043036a2SApple OSS Distributions  * __mpsc_queue_append_update_tail(), and until
202*043036a2SApple OSS Distributions  * __mpsc_queue_append_update_prev() has returned.
203*043036a2SApple OSS Distributions  *
204*043036a2SApple OSS Distributions  * @param q
205*043036a2SApple OSS Distributions  * The queue to update.
206*043036a2SApple OSS Distributions  *
207*043036a2SApple OSS Distributions  * @param elm
208*043036a2SApple OSS Distributions  * The element to append to `q`.
209*043036a2SApple OSS Distributions  *
210*043036a2SApple OSS Distributions  * @returns
211*043036a2SApple OSS Distributions  * A token to later pass to __mpsc_queue_append_update_prev()
212*043036a2SApple OSS Distributions  * to complete the enqueue.
213*043036a2SApple OSS Distributions  */
214*043036a2SApple OSS Distributions static inline mpsc_queue_chain_t
__mpsc_queue_append_update_tail(mpsc_queue_head_t q,mpsc_queue_chain_t elm)215*043036a2SApple OSS Distributions __mpsc_queue_append_update_tail(mpsc_queue_head_t q, mpsc_queue_chain_t elm)
216*043036a2SApple OSS Distributions {
217*043036a2SApple OSS Distributions 	os_atomic_store(&elm->mpqc_next, (struct mpsc_queue_chain *__single)NULL, relaxed);
218*043036a2SApple OSS Distributions 	return os_atomic_xchg(&q->mpqh_tail, elm, release);
219*043036a2SApple OSS Distributions }
220*043036a2SApple OSS Distributions 
221*043036a2SApple OSS Distributions /**
222*043036a2SApple OSS Distributions  * @function __mpsc_queue_append_was_empty
223*043036a2SApple OSS Distributions  *
224*043036a2SApple OSS Distributions  * @brief
225*043036a2SApple OSS Distributions  * Tests whether the queue was empty at the time
226*043036a2SApple OSS Distributions  * __mpsc_queue_append_update_tail() was called.
227*043036a2SApple OSS Distributions  *
228*043036a2SApple OSS Distributions  * @param q
229*043036a2SApple OSS Distributions  * The queue to test emptiness for.
230*043036a2SApple OSS Distributions  *
231*043036a2SApple OSS Distributions  * @param prev
232*043036a2SApple OSS Distributions  * The token returned by __mpsc_queue_append_update_tail().
233*043036a2SApple OSS Distributions  *
234*043036a2SApple OSS Distributions  * @returns
235*043036a2SApple OSS Distributions  * Whether the queue was empty (true) or not (false).
236*043036a2SApple OSS Distributions  */
237*043036a2SApple OSS Distributions static inline bool
__mpsc_queue_append_was_empty(mpsc_queue_head_t q,mpsc_queue_chain_t prev)238*043036a2SApple OSS Distributions __mpsc_queue_append_was_empty(mpsc_queue_head_t q, mpsc_queue_chain_t prev)
239*043036a2SApple OSS Distributions {
240*043036a2SApple OSS Distributions 	return &q->mpqh_head == prev;
241*043036a2SApple OSS Distributions }
242*043036a2SApple OSS Distributions 
243*043036a2SApple OSS Distributions /**
244*043036a2SApple OSS Distributions  * @function __mpsc_queue_append_update_prev
245*043036a2SApple OSS Distributions  *
246*043036a2SApple OSS Distributions  * @brief
247*043036a2SApple OSS Distributions  * Second half of the enqueue operation onto a multi-producer single-consumer
248*043036a2SApple OSS Distributions  * queue.
249*043036a2SApple OSS Distributions  *
250*043036a2SApple OSS Distributions  * @discussion
251*043036a2SApple OSS Distributions  * This function is available for algorithms that need to do things (such as
252*043036a2SApple OSS Distributions  * taking a refcount) before calling __mpsc_queue_append_update_prev().
253*043036a2SApple OSS Distributions  *
254*043036a2SApple OSS Distributions  * Preemption should be disabled before calling
255*043036a2SApple OSS Distributions  * __mpsc_queue_append_update_tail(), and until
256*043036a2SApple OSS Distributions  * __mpsc_queue_append_update_prev() has returned.
257*043036a2SApple OSS Distributions  *
258*043036a2SApple OSS Distributions  * @param prev
259*043036a2SApple OSS Distributions  * The token returned by __mpsc_queue_append_update_tail().
260*043036a2SApple OSS Distributions  *
261*043036a2SApple OSS Distributions  * @param elm
262*043036a2SApple OSS Distributions  * The element to append to the queue.
263*043036a2SApple OSS Distributions  */
264*043036a2SApple OSS Distributions static inline void
__mpsc_queue_append_update_prev(mpsc_queue_chain_t prev,mpsc_queue_chain_t elm)265*043036a2SApple OSS Distributions __mpsc_queue_append_update_prev(mpsc_queue_chain_t prev, mpsc_queue_chain_t elm)
266*043036a2SApple OSS Distributions {
267*043036a2SApple OSS Distributions 	os_atomic_store(&prev->mpqc_next, elm, relaxed);
268*043036a2SApple OSS Distributions }
269*043036a2SApple OSS Distributions 
270*043036a2SApple OSS Distributions 
271*043036a2SApple OSS Distributions #pragma mark Multi Producer calls
272*043036a2SApple OSS Distributions 
273*043036a2SApple OSS Distributions /**
274*043036a2SApple OSS Distributions  * @function mpsc_queue_append_list
275*043036a2SApple OSS Distributions  *
276*043036a2SApple OSS Distributions  * @brief
277*043036a2SApple OSS Distributions  * Enqueues a list of elements onto a queue.
278*043036a2SApple OSS Distributions  *
279*043036a2SApple OSS Distributions  * @discussion
280*043036a2SApple OSS Distributions  * This enqueues a list that has to be fully formed from `first` to `last`
281*043036a2SApple OSS Distributions  * at the end of `q`.
282*043036a2SApple OSS Distributions  *
283*043036a2SApple OSS Distributions  * Preemption should be disabled when calling mpsc_queue_append_list().
284*043036a2SApple OSS Distributions  *
285*043036a2SApple OSS Distributions  * @param q
286*043036a2SApple OSS Distributions  * The queue to update.
287*043036a2SApple OSS Distributions  *
288*043036a2SApple OSS Distributions  * @param first
289*043036a2SApple OSS Distributions  * The first of the list elements being appended.
290*043036a2SApple OSS Distributions  *
291*043036a2SApple OSS Distributions  * @param last
292*043036a2SApple OSS Distributions  * The last of the list elements being appended.
293*043036a2SApple OSS Distributions  */
294*043036a2SApple OSS Distributions static inline bool
mpsc_queue_append_list(mpsc_queue_head_t q,mpsc_queue_chain_t first,mpsc_queue_chain_t last)295*043036a2SApple OSS Distributions mpsc_queue_append_list(mpsc_queue_head_t q, mpsc_queue_chain_t first,
296*043036a2SApple OSS Distributions     mpsc_queue_chain_t last)
297*043036a2SApple OSS Distributions {
298*043036a2SApple OSS Distributions 	mpsc_queue_chain_t prev = __mpsc_queue_append_update_tail(q, last);
299*043036a2SApple OSS Distributions 	__mpsc_queue_append_update_prev(prev, first);
300*043036a2SApple OSS Distributions 	return __mpsc_queue_append_was_empty(q, prev);
301*043036a2SApple OSS Distributions }
302*043036a2SApple OSS Distributions 
303*043036a2SApple OSS Distributions /**
304*043036a2SApple OSS Distributions  * @function mpsc_queue_append
305*043036a2SApple OSS Distributions  *
306*043036a2SApple OSS Distributions  * @brief
307*043036a2SApple OSS Distributions  * Enqueues an element onto a queue.
308*043036a2SApple OSS Distributions  *
309*043036a2SApple OSS Distributions  * @discussion
310*043036a2SApple OSS Distributions  * Preemption should be disabled when calling mpsc_queue_append().
311*043036a2SApple OSS Distributions  *
312*043036a2SApple OSS Distributions  * @param q    the queue to update
313*043036a2SApple OSS Distributions  * @param elm  the element to append
314*043036a2SApple OSS Distributions  */
315*043036a2SApple OSS Distributions static inline bool
mpsc_queue_append(mpsc_queue_head_t q,mpsc_queue_chain_t elm)316*043036a2SApple OSS Distributions mpsc_queue_append(mpsc_queue_head_t q, mpsc_queue_chain_t elm)
317*043036a2SApple OSS Distributions {
318*043036a2SApple OSS Distributions 	return mpsc_queue_append_list(q, elm, elm);
319*043036a2SApple OSS Distributions }
320*043036a2SApple OSS Distributions 
321*043036a2SApple OSS Distributions 
322*043036a2SApple OSS Distributions #pragma mark Single Consumer calls
323*043036a2SApple OSS Distributions 
324*043036a2SApple OSS Distributions /**
325*043036a2SApple OSS Distributions  * @function mpsc_queue_dequeue_batch()
326*043036a2SApple OSS Distributions  *
327*043036a2SApple OSS Distributions  * @brief
328*043036a2SApple OSS Distributions  * Atomically empty a queue at once and return the batch head and tail.
329*043036a2SApple OSS Distributions  *
330*043036a2SApple OSS Distributions  * @discussion
331*043036a2SApple OSS Distributions  * Consumer function, must be called in a serialized way with respect to any
332*043036a2SApple OSS Distributions  * other consumer function.
333*043036a2SApple OSS Distributions  *
334*043036a2SApple OSS Distributions  * @param q
335*043036a2SApple OSS Distributions  * The queue
336*043036a2SApple OSS Distributions  *
337*043036a2SApple OSS Distributions  * @param tail
338*043036a2SApple OSS Distributions  * An out pointer filled with the last element captured.
339*043036a2SApple OSS Distributions  *
340*043036a2SApple OSS Distributions  * @param dependency
341*043036a2SApple OSS Distributions  * A dependency token (to rely on consume / hardware dependencies)
342*043036a2SApple OSS Distributions  * When not trying to take advantage of hardware dependencies, just pass NULL.
343*043036a2SApple OSS Distributions  *
344*043036a2SApple OSS Distributions  * @returns
345*043036a2SApple OSS Distributions  * The first element of the batch if any, or NULL the queue was empty.
346*043036a2SApple OSS Distributions  */
347*043036a2SApple OSS Distributions mpsc_queue_chain_t
348*043036a2SApple OSS Distributions mpsc_queue_dequeue_batch(mpsc_queue_head_t q, mpsc_queue_chain_t *tail,
349*043036a2SApple OSS Distributions     os_atomic_dependency_t dependency);
350*043036a2SApple OSS Distributions 
351*043036a2SApple OSS Distributions /**
352*043036a2SApple OSS Distributions  * @function mpsc_queue_batch_next()
353*043036a2SApple OSS Distributions  *
354*043036a2SApple OSS Distributions  * @brief
355*043036a2SApple OSS Distributions  * Function used to consume an element from a batch dequeued with
356*043036a2SApple OSS Distributions  * mpsc_queue_dequeue_batch().
357*043036a2SApple OSS Distributions  *
358*043036a2SApple OSS Distributions  * @discussion
359*043036a2SApple OSS Distributions  * Once a batch has been dequeued, there is no need to hold the consumer lock
360*043036a2SApple OSS Distributions  * anymore to consume it.
361*043036a2SApple OSS Distributions  *
362*043036a2SApple OSS Distributions  * mpsc_queue_batch_foreach_safe() is the preferred interface to consume
363*043036a2SApple OSS Distributions  * the whole batch.
364*043036a2SApple OSS Distributions  *
365*043036a2SApple OSS Distributions  * @param cur
366*043036a2SApple OSS Distributions  * The current inspected element of the batch (must be the batch head or
367*043036a2SApple OSS Distributions  * a value returned by mpsc_queue_batch_next()).
368*043036a2SApple OSS Distributions  *
369*043036a2SApple OSS Distributions  * @param tail
370*043036a2SApple OSS Distributions  * The last element of the batch.
371*043036a2SApple OSS Distributions  *
372*043036a2SApple OSS Distributions  * @returns
373*043036a2SApple OSS Distributions  * The next element if any.
374*043036a2SApple OSS Distributions  */
375*043036a2SApple OSS Distributions mpsc_queue_chain_t
376*043036a2SApple OSS Distributions mpsc_queue_batch_next(mpsc_queue_chain_t cur, mpsc_queue_chain_t tail);
377*043036a2SApple OSS Distributions 
378*043036a2SApple OSS Distributions /**
379*043036a2SApple OSS Distributions  * @macro mpsc_queue_batch_foreach_safe
380*043036a2SApple OSS Distributions  *
381*043036a2SApple OSS Distributions  * @brief
382*043036a2SApple OSS Distributions  * Macro used to enumerate a batch dequeued with mpsc_queue_dequeue_batch().
383*043036a2SApple OSS Distributions  *
384*043036a2SApple OSS Distributions  * @param item
385*043036a2SApple OSS Distributions  * The item being currently visited.
386*043036a2SApple OSS Distributions  *
387*043036a2SApple OSS Distributions  * @param head
388*043036a2SApple OSS Distributions  * The first element of the batch.
389*043036a2SApple OSS Distributions  *
390*043036a2SApple OSS Distributions  * @param tail
391*043036a2SApple OSS Distributions  * The last element of the batch.
392*043036a2SApple OSS Distributions  */
393*043036a2SApple OSS Distributions #define mpsc_queue_batch_foreach_safe(item, head, tail) \
394*043036a2SApple OSS Distributions 	for (mpsc_queue_chain_t __tmp, __item = (head), __tail = (tail); \
395*043036a2SApple OSS Distributions 	    __tmp = mpsc_queue_batch_next(__item, __tail), (item) = __item; \
396*043036a2SApple OSS Distributions 	    __item = __tmp)
397*043036a2SApple OSS Distributions 
398*043036a2SApple OSS Distributions /**
399*043036a2SApple OSS Distributions  * @function mpsc_queue_restore_batch()
400*043036a2SApple OSS Distributions  *
401*043036a2SApple OSS Distributions  * @brief
402*043036a2SApple OSS Distributions  * "Restore"s a batch at the head of the queue.
403*043036a2SApple OSS Distributions  *
404*043036a2SApple OSS Distributions  * @discussion
405*043036a2SApple OSS Distributions  * Consumer function, must be called in a serialized way with respect to any
406*043036a2SApple OSS Distributions  * other consumer function.
407*043036a2SApple OSS Distributions  *
408*043036a2SApple OSS Distributions  * @param q
409*043036a2SApple OSS Distributions  * The queue
410*043036a2SApple OSS Distributions  *
411*043036a2SApple OSS Distributions  * @param first
412*043036a2SApple OSS Distributions  * The first element to put back.
413*043036a2SApple OSS Distributions  *
414*043036a2SApple OSS Distributions  * @param last
415*043036a2SApple OSS Distributions  * The last element to put back.
416*043036a2SApple OSS Distributions  * It is the responsibility of the caller to ensure the linkages from first to
417*043036a2SApple OSS Distributions  * last are properly set up before calling this function.
418*043036a2SApple OSS Distributions  */
419*043036a2SApple OSS Distributions void
420*043036a2SApple OSS Distributions mpsc_queue_restore_batch(mpsc_queue_head_t q, mpsc_queue_chain_t first,
421*043036a2SApple OSS Distributions     mpsc_queue_chain_t last);
422*043036a2SApple OSS Distributions 
423*043036a2SApple OSS Distributions 
424*043036a2SApple OSS Distributions #pragma mark "GCD"-like facilities
425*043036a2SApple OSS Distributions 
426*043036a2SApple OSS Distributions /*!
427*043036a2SApple OSS Distributions  * @typedef enum mpsc_daemon_init_options
428*043036a2SApple OSS Distributions  *
429*043036a2SApple OSS Distributions  * @const MPSC_DAEMON_INIT_NONE
430*043036a2SApple OSS Distributions  * Default options (no specific behavior)
431*043036a2SApple OSS Distributions  *
432*043036a2SApple OSS Distributions  * @const MPSC_DAEMON_INIT_INACTIVE
433*043036a2SApple OSS Distributions  * Create the queue inactive, which requires an explicit call
434*043036a2SApple OSS Distributions  * to @c mpsc_daemon_queue_activate() to start draining.
435*043036a2SApple OSS Distributions  *
436*043036a2SApple OSS Distributions  */
437*043036a2SApple OSS Distributions __options_decl(mpsc_daemon_init_options_t, uint32_t, {
438*043036a2SApple OSS Distributions 	MPSC_DAEMON_INIT_NONE          = 0,
439*043036a2SApple OSS Distributions 	MPSC_DAEMON_INIT_INACTIVE      = 1 << 0,
440*043036a2SApple OSS Distributions });
441*043036a2SApple OSS Distributions 
442*043036a2SApple OSS Distributions /*!
443*043036a2SApple OSS Distributions  * @typedef struct mpsc_daemon_queue
444*043036a2SApple OSS Distributions  *
445*043036a2SApple OSS Distributions  * @brief
446*043036a2SApple OSS Distributions  * Daemon queues are a ready-to use packaging of the low level MPSC queue
447*043036a2SApple OSS Distributions  * primitive.
448*043036a2SApple OSS Distributions  *
449*043036a2SApple OSS Distributions  * @discussion
450*043036a2SApple OSS Distributions  * mpsc_queue_t requires handling of state transitions of the queue and
451*043036a2SApple OSS Distributions  * dequeuing yourself, which is a non trivial task.
452*043036a2SApple OSS Distributions  *
453*043036a2SApple OSS Distributions  * Daemon queues are a simple packaged solution that allows for mpsc_queue_t to
454*043036a2SApple OSS Distributions  * form hierarchies (mostly for layering purposes), and be serviced at the
455*043036a2SApple OSS Distributions  * bottom of such a hierarchy by a thread or a thread call.
456*043036a2SApple OSS Distributions  *
457*043036a2SApple OSS Distributions  * Daemon queues assume homogenous items, and are setup with an `invoke`
458*043036a2SApple OSS Distributions  * callback that is called in the dequeuer on every item as they are dequeued.
459*043036a2SApple OSS Distributions  */
460*043036a2SApple OSS Distributions typedef struct mpsc_daemon_queue *mpsc_daemon_queue_t;
461*043036a2SApple OSS Distributions 
462*043036a2SApple OSS Distributions #define MPSC_QUEUE_BATCH_END  ((mpsc_queue_chain_t)~0ul)
463*043036a2SApple OSS Distributions 
464*043036a2SApple OSS Distributions /*!
465*043036a2SApple OSS Distributions  * @typedef struct mpsc_daemon_queue
466*043036a2SApple OSS Distributions  *
467*043036a2SApple OSS Distributions  * @brief
468*043036a2SApple OSS Distributions  * The type for MPSC Daemon Queues invoke callbacks.
469*043036a2SApple OSS Distributions  */
470*043036a2SApple OSS Distributions typedef void (*mpsc_daemon_invoke_fn_t)(mpsc_queue_chain_t elm,
471*043036a2SApple OSS Distributions     mpsc_daemon_queue_t dq);
472*043036a2SApple OSS Distributions 
473*043036a2SApple OSS Distributions /*!
474*043036a2SApple OSS Distributions  * @enum mpsc_daemon_queue_kind
475*043036a2SApple OSS Distributions  *
476*043036a2SApple OSS Distributions  * @brief
477*043036a2SApple OSS Distributions  * Internal type, not to be used by clients.
478*043036a2SApple OSS Distributions  */
479*043036a2SApple OSS Distributions __enum_decl(mpsc_daemon_queue_kind_t, uint16_t, {
480*043036a2SApple OSS Distributions 	MPSC_QUEUE_KIND_UNKNOWN,
481*043036a2SApple OSS Distributions 	MPSC_QUEUE_KIND_NESTED,
482*043036a2SApple OSS Distributions 	MPSC_QUEUE_KIND_THREAD,
483*043036a2SApple OSS Distributions 	MPSC_QUEUE_KIND_THREAD_CRITICAL,
484*043036a2SApple OSS Distributions 	MPSC_QUEUE_KIND_THREAD_CALL,
485*043036a2SApple OSS Distributions });
486*043036a2SApple OSS Distributions 
487*043036a2SApple OSS Distributions /*!
488*043036a2SApple OSS Distributions  * @enum mpsc_daemon_queue_options
489*043036a2SApple OSS Distributions  *
490*043036a2SApple OSS Distributions  * @brief
491*043036a2SApple OSS Distributions  * Options clients can set on their queue before first use.
492*043036a2SApple OSS Distributions  *
493*043036a2SApple OSS Distributions  * @const MPSC_QUEUE_OPTION_BATCH
494*043036a2SApple OSS Distributions  * Call the `invoke` callback at the end of a batch
495*043036a2SApple OSS Distributions  * with the magic @c MPSC_QUEUE_BATCH_END marker.
496*043036a2SApple OSS Distributions  */
497*043036a2SApple OSS Distributions __options_decl(mpsc_daemon_queue_options_t, uint16_t, {
498*043036a2SApple OSS Distributions 	MPSC_QUEUE_OPTION_BATCH  = 0x0001,
499*043036a2SApple OSS Distributions });
500*043036a2SApple OSS Distributions 
501*043036a2SApple OSS Distributions /*!
502*043036a2SApple OSS Distributions  * @enum mpsc_daemon_queue_state
503*043036a2SApple OSS Distributions  *
504*043036a2SApple OSS Distributions  * @brief
505*043036a2SApple OSS Distributions  * Internal type, not to be used by clients.
506*043036a2SApple OSS Distributions  */
507*043036a2SApple OSS Distributions __options_decl(mpsc_daemon_queue_state_t, uint32_t, {
508*043036a2SApple OSS Distributions 	MPSC_QUEUE_STATE_DRAINING = 0x0001,
509*043036a2SApple OSS Distributions 	MPSC_QUEUE_STATE_WAKEUP   = 0x0002,
510*043036a2SApple OSS Distributions 	MPSC_QUEUE_STATE_CANCELED = 0x0004,
511*043036a2SApple OSS Distributions 	MPSC_QUEUE_STATE_INACTIVE = 0x0008,
512*043036a2SApple OSS Distributions });
513*043036a2SApple OSS Distributions 
514*043036a2SApple OSS Distributions struct mpsc_daemon_queue {
515*043036a2SApple OSS Distributions 	mpsc_daemon_queue_kind_t    mpd_kind;
516*043036a2SApple OSS Distributions 	mpsc_daemon_queue_options_t mpd_options;
517*043036a2SApple OSS Distributions 	mpsc_daemon_queue_state_t _Atomic mpd_state;
518*043036a2SApple OSS Distributions 	mpsc_daemon_invoke_fn_t     mpd_invoke;
519*043036a2SApple OSS Distributions 	union {
520*043036a2SApple OSS Distributions 		mpsc_daemon_queue_t     mpd_target;
521*043036a2SApple OSS Distributions 		struct thread          *mpd_thread;
522*043036a2SApple OSS Distributions 		struct thread_call     *mpd_call;
523*043036a2SApple OSS Distributions 	};
524*043036a2SApple OSS Distributions 	struct mpsc_queue_head      mpd_queue;
525*043036a2SApple OSS Distributions 	struct mpsc_queue_chain     mpd_chain;
526*043036a2SApple OSS Distributions };
527*043036a2SApple OSS Distributions 
528*043036a2SApple OSS Distributions /*!
529*043036a2SApple OSS Distributions  * @function mpsc_daemon_queue_init_with_thread
530*043036a2SApple OSS Distributions  *
531*043036a2SApple OSS Distributions  * @brief
532*043036a2SApple OSS Distributions  * Sets up a daemon queue to be a base queue drained by a kernel thread.
533*043036a2SApple OSS Distributions  *
534*043036a2SApple OSS Distributions  * @discussion
535*043036a2SApple OSS Distributions  * The function will allocate the thread and start it in assert_wait.
536*043036a2SApple OSS Distributions  *
537*043036a2SApple OSS Distributions  * @param dq
538*043036a2SApple OSS Distributions  * The queue to initialize
539*043036a2SApple OSS Distributions  *
540*043036a2SApple OSS Distributions  * @param invoke
541*043036a2SApple OSS Distributions  * The invoke function called on individual items on the queue during drain.
542*043036a2SApple OSS Distributions  *
543*043036a2SApple OSS Distributions  * @param pri
544*043036a2SApple OSS Distributions  * The scheduler priority for the created thread.
545*043036a2SApple OSS Distributions  *
546*043036a2SApple OSS Distributions  * @param name
547*043036a2SApple OSS Distributions  * The name to give to the created thread.
548*043036a2SApple OSS Distributions  *
549*043036a2SApple OSS Distributions  * @param flags
550*043036a2SApple OSS Distributions  * See mpsc_daemon_init_options_t.
551*043036a2SApple OSS Distributions  *
552*043036a2SApple OSS Distributions  * @returns
553*043036a2SApple OSS Distributions  * Whether creating the thread was successful.
554*043036a2SApple OSS Distributions  */
555*043036a2SApple OSS Distributions kern_return_t
556*043036a2SApple OSS Distributions mpsc_daemon_queue_init_with_thread(mpsc_daemon_queue_t dq,
557*043036a2SApple OSS Distributions     mpsc_daemon_invoke_fn_t invoke, int pri, const char *name,
558*043036a2SApple OSS Distributions     mpsc_daemon_init_options_t flags);
559*043036a2SApple OSS Distributions 
560*043036a2SApple OSS Distributions 
561*043036a2SApple OSS Distributions /*!
562*043036a2SApple OSS Distributions  * @function mpsc_daemon_queue_init_with_thread_call
563*043036a2SApple OSS Distributions  *
564*043036a2SApple OSS Distributions  * @brief
565*043036a2SApple OSS Distributions  * Sets up a daemon queue to be a base queue drained by a thread call.
566*043036a2SApple OSS Distributions  *
567*043036a2SApple OSS Distributions  * @param dq
568*043036a2SApple OSS Distributions  * The queue to initialize
569*043036a2SApple OSS Distributions  *
570*043036a2SApple OSS Distributions  * @param invoke
571*043036a2SApple OSS Distributions  * The invoke function called on individual items on the queue during drain.
572*043036a2SApple OSS Distributions  *
573*043036a2SApple OSS Distributions  * @param pri
574*043036a2SApple OSS Distributions  * The priority the thread call will run at.
575*043036a2SApple OSS Distributions  *
576*043036a2SApple OSS Distributions  * @param flags
577*043036a2SApple OSS Distributions  * See mpsc_daemon_init_options_t.
578*043036a2SApple OSS Distributions  */
579*043036a2SApple OSS Distributions void
580*043036a2SApple OSS Distributions mpsc_daemon_queue_init_with_thread_call(mpsc_daemon_queue_t dq,
581*043036a2SApple OSS Distributions     mpsc_daemon_invoke_fn_t invoke, thread_call_priority_t pri,
582*043036a2SApple OSS Distributions     mpsc_daemon_init_options_t flags);
583*043036a2SApple OSS Distributions 
584*043036a2SApple OSS Distributions /*!
585*043036a2SApple OSS Distributions  * @function mpsc_daemon_queue_init_with_target
586*043036a2SApple OSS Distributions  *
587*043036a2SApple OSS Distributions  * @brief
588*043036a2SApple OSS Distributions  * Sets up a daemon queue to target another daemon queue.
589*043036a2SApple OSS Distributions  *
590*043036a2SApple OSS Distributions  * @discussion
591*043036a2SApple OSS Distributions  * The targetting relationship is useful for subsystem layering purposes only.
592*043036a2SApple OSS Distributions  * Because draining a given queue is atomic with respect to its target, target
593*043036a2SApple OSS Distributions  * queue hierarchies are prone to starvation.
594*043036a2SApple OSS Distributions  *
595*043036a2SApple OSS Distributions  * @param dq
596*043036a2SApple OSS Distributions  * The queue to initialize
597*043036a2SApple OSS Distributions  *
598*043036a2SApple OSS Distributions  * @param invoke
599*043036a2SApple OSS Distributions  * The invoke function called on individual items on the queue during drain.
600*043036a2SApple OSS Distributions  *
601*043036a2SApple OSS Distributions  * @param target
602*043036a2SApple OSS Distributions  * The target queue of the initialized queue, which has to be initialized with
603*043036a2SApple OSS Distributions  * the mpsc_daemon_queue_nested_invoke invoke handler.
604*043036a2SApple OSS Distributions  *
605*043036a2SApple OSS Distributions  * @param flags
606*043036a2SApple OSS Distributions  * See mpsc_daemon_init_options_t.
607*043036a2SApple OSS Distributions  */
608*043036a2SApple OSS Distributions void
609*043036a2SApple OSS Distributions mpsc_daemon_queue_init_with_target(mpsc_daemon_queue_t dq,
610*043036a2SApple OSS Distributions     mpsc_daemon_invoke_fn_t invoke, mpsc_daemon_queue_t target,
611*043036a2SApple OSS Distributions     mpsc_daemon_init_options_t flags);
612*043036a2SApple OSS Distributions 
613*043036a2SApple OSS Distributions /*!
614*043036a2SApple OSS Distributions  * @function mpsc_daemon_queue_nested_invoke
615*043036a2SApple OSS Distributions  *
616*043036a2SApple OSS Distributions  * @brief
617*043036a2SApple OSS Distributions  * The invoke function to pass to mpsc_daemon_queue_init_* when a queue is meant
618*043036a2SApple OSS Distributions  * to be targeted by other queues.
619*043036a2SApple OSS Distributions  */
620*043036a2SApple OSS Distributions void
621*043036a2SApple OSS Distributions mpsc_daemon_queue_nested_invoke(mpsc_queue_chain_t elm,
622*043036a2SApple OSS Distributions     mpsc_daemon_queue_t dq);
623*043036a2SApple OSS Distributions 
624*043036a2SApple OSS Distributions /*!
625*043036a2SApple OSS Distributions  * @function mpsc_daemon_queue_activate
626*043036a2SApple OSS Distributions  *
627*043036a2SApple OSS Distributions  * @brief
628*043036a2SApple OSS Distributions  * Activate a queue that was created with the @c MPSC_DAEMON_INIT_INACTIVE flag.
629*043036a2SApple OSS Distributions  *
630*043036a2SApple OSS Distributions  * @param dq
631*043036a2SApple OSS Distributions  * The queue to activate.
632*043036a2SApple OSS Distributions  */
633*043036a2SApple OSS Distributions void
634*043036a2SApple OSS Distributions mpsc_daemon_queue_activate(mpsc_daemon_queue_t dq);
635*043036a2SApple OSS Distributions 
636*043036a2SApple OSS Distributions /*!
637*043036a2SApple OSS Distributions  * @function mpsc_daemon_queue_cancel_and_wait
638*043036a2SApple OSS Distributions  *
639*043036a2SApple OSS Distributions  * @brief
640*043036a2SApple OSS Distributions  * Cancels the queue so that the object owning it can be destroyed.
641*043036a2SApple OSS Distributions  *
642*043036a2SApple OSS Distributions  * @discussion
643*043036a2SApple OSS Distributions  * This interface will cancel the queue and wait synchronously for the
644*043036a2SApple OSS Distributions  * cancelation to have taken effect, possibly waiting on elements currently
645*043036a2SApple OSS Distributions  * draining.
646*043036a2SApple OSS Distributions  *
647*043036a2SApple OSS Distributions  * Sending objects to the daemon queue after cancelation is undefined.
648*043036a2SApple OSS Distributions  *
649*043036a2SApple OSS Distributions  * Calling this function multiple times is undefined.
650*043036a2SApple OSS Distributions  *
651*043036a2SApple OSS Distributions  * Tearing down daemon queue hierarchies is the responsibility of the adopter.
652*043036a2SApple OSS Distributions  */
653*043036a2SApple OSS Distributions void
654*043036a2SApple OSS Distributions mpsc_daemon_queue_cancel_and_wait(mpsc_daemon_queue_t dq);
655*043036a2SApple OSS Distributions 
656*043036a2SApple OSS Distributions /*!
657*043036a2SApple OSS Distributions  * @function mpsc_daemon_enqueue
658*043036a2SApple OSS Distributions  *
659*043036a2SApple OSS Distributions  * @brief
660*043036a2SApple OSS Distributions  * Send ("async") an item to a given daemon on a given queue.
661*043036a2SApple OSS Distributions  *
662*043036a2SApple OSS Distributions  * @discussion
663*043036a2SApple OSS Distributions  * It is the responsibility of the caller to ensure preemption is disabled when
664*043036a2SApple OSS Distributions  * this call is made.
665*043036a2SApple OSS Distributions  *
666*043036a2SApple OSS Distributions  * @param dq
667*043036a2SApple OSS Distributions  * The daemon queue to enqueue the element onto.
668*043036a2SApple OSS Distributions  *
669*043036a2SApple OSS Distributions  * @param elm
670*043036a2SApple OSS Distributions  * The item to enqueue.
671*043036a2SApple OSS Distributions  *
672*043036a2SApple OSS Distributions  * @param options
673*043036a2SApple OSS Distributions  * Options applicable to the enqueue. In particupar passing
674*043036a2SApple OSS Distributions  * MPSC_QUEUE_DISABLE_PREEMPTION makes sure preemption is properly disabled
675*043036a2SApple OSS Distributions  * during the enqueue.
676*043036a2SApple OSS Distributions  */
677*043036a2SApple OSS Distributions void
678*043036a2SApple OSS Distributions mpsc_daemon_enqueue(mpsc_daemon_queue_t dq, mpsc_queue_chain_t elm,
679*043036a2SApple OSS Distributions     mpsc_queue_options_t options);
680*043036a2SApple OSS Distributions 
681*043036a2SApple OSS Distributions 
682*043036a2SApple OSS Distributions #pragma mark Deferred deallocation daemon
683*043036a2SApple OSS Distributions 
684*043036a2SApple OSS Distributions /*!
685*043036a2SApple OSS Distributions  * @function thread_deallocate_daemon_init
686*043036a2SApple OSS Distributions  *
687*043036a2SApple OSS Distributions  * @brief
688*043036a2SApple OSS Distributions  * Initializes the deferred deallocation daemon, called by thread_daemon_init().
689*043036a2SApple OSS Distributions  *
690*043036a2SApple OSS Distributions  * @discussion
691*043036a2SApple OSS Distributions  * The deferred deallocation daemon is a kernel thread based daemon queue that
692*043036a2SApple OSS Distributions  * is targeted by nested daemon queues.
693*043036a2SApple OSS Distributions  *
694*043036a2SApple OSS Distributions  * It is used to perform deferred deallocation for objects that can't safely be
695*043036a2SApple OSS Distributions  * deallocated from the context where the deallocation should normally occur.
696*043036a2SApple OSS Distributions  *
697*043036a2SApple OSS Distributions  * Subsystems using it are for example: turnstiles, workqueues, threads.
698*043036a2SApple OSS Distributions  *
699*043036a2SApple OSS Distributions  * @warning
700*043036a2SApple OSS Distributions  * New queues should be added to this daemon with great care,
701*043036a2SApple OSS Distributions  * as abusing it can lead to unbounded amount of kernel work.
702*043036a2SApple OSS Distributions  */
703*043036a2SApple OSS Distributions void
704*043036a2SApple OSS Distributions thread_deallocate_daemon_init(void);
705*043036a2SApple OSS Distributions 
706*043036a2SApple OSS Distributions /*!
707*043036a2SApple OSS Distributions  * @function thread_deallocate_daemon_register_queue
708*043036a2SApple OSS Distributions  *
709*043036a2SApple OSS Distributions  * @brief
710*043036a2SApple OSS Distributions  * Dynamically register a queue for deferred deletion with the deferred
711*043036a2SApple OSS Distributions  * deallocation daemon.
712*043036a2SApple OSS Distributions  *
713*043036a2SApple OSS Distributions  * @param dq
714*043036a2SApple OSS Distributions  * The daemon queue to register with the deferred deallocation daemon.
715*043036a2SApple OSS Distributions  *
716*043036a2SApple OSS Distributions  * @param invoke
717*043036a2SApple OSS Distributions  * The callback called on every element of this queue by the deallocation
718*043036a2SApple OSS Distributions  * daemon.
719*043036a2SApple OSS Distributions  */
720*043036a2SApple OSS Distributions void
721*043036a2SApple OSS Distributions thread_deallocate_daemon_register_queue(mpsc_daemon_queue_t dq,
722*043036a2SApple OSS Distributions     mpsc_daemon_invoke_fn_t invoke);
723*043036a2SApple OSS Distributions 
724*043036a2SApple OSS Distributions 
725*043036a2SApple OSS Distributions #pragma mark tests
726*043036a2SApple OSS Distributions #if DEBUG || DEVELOPMENT
727*043036a2SApple OSS Distributions 
728*043036a2SApple OSS Distributions int
729*043036a2SApple OSS Distributions mpsc_test_pingpong(uint64_t count, uint64_t *out);
730*043036a2SApple OSS Distributions 
731*043036a2SApple OSS Distributions #endif /* DEBUG || DEVELOPMENT */
732*043036a2SApple OSS Distributions 
733*043036a2SApple OSS Distributions #endif /* XNU_KERNEL_PRIVATE */
734*043036a2SApple OSS Distributions 
735*043036a2SApple OSS Distributions __ASSUME_PTR_ABI_SINGLE_END __END_DECLS
736*043036a2SApple OSS Distributions 
737*043036a2SApple OSS Distributions #endif /* _KERN_MPSC_QUEUE_H_ */
738