2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon rights
54 * to redistribute these changes.
60 * Author: Avadis Tevanian, Jr.
63 * Type definitions for generic queues.
67 #ifndef _KERN_QUEUE_H_
68 #define _KERN_QUEUE_H_
70 #include <mach/mach_types.h>
71 #include <kern/macro_help.h>
74 * Queue of abstract objects. Queue is maintained
77 * Supports fast removal from within the queue.
79 * How to declare a queue of elements of type "foo_t":
80 * In the "*foo_t" type, you must have a field of
81 * type "queue_chain_t" to hold together this queue.
82 * There may be more than one chain through a
83 * "foo_t", for use by different queues.
85 * Declare the queue as a "queue_t" type.
87 * Elements of the queue (of type "foo_t", that is)
88 * are referred to by reference, and cast to type
89 * "queue_entry_t" within this module.
93 * A generic doubly-linked list (queue).
97 struct queue_entry
*next
; /* next element */
98 struct queue_entry
*prev
; /* previous element */
101 typedef struct queue_entry
*queue_t
;
102 typedef struct queue_entry queue_head_t
;
103 typedef struct queue_entry queue_chain_t
;
104 typedef struct queue_entry
*queue_entry_t
;
107 * enqueue puts "elt" on the "queue".
108 * dequeue returns the first element in the "queue".
109 * remqueue removes the specified "elt" from its queue.
112 #define enqueue(queue,elt) enqueue_tail(queue, elt)
113 #define dequeue(queue) dequeue_head(queue)
115 #if !defined(__GNUC__)
117 #include <sys/cdefs.h>
120 /* Enqueue element to head of queue */
121 extern void enqueue_head(
125 /* Enqueue element to tail of queue */
126 extern void enqueue_tail(
130 /* Dequeue element from head of queue */
131 extern queue_entry_t
dequeue_head(
134 /* Dequeue element from tail of queue */
135 extern queue_entry_t
dequeue_tail(
138 /* Dequeue element */
139 extern void remqueue(
142 /* Enqueue element after a particular elem */
147 /* Dequeue element */
153 #else /* !__GNUC__ */
155 #ifdef XNU_KERNEL_PRIVATE
156 #define __DEQUEUE_ELT_CLEANUP(elt) do { \
157 (elt)->next = (queue_entry_t) 0; \
158 (elt)->prev = (queue_entry_t) 0; \
161 #define __DEQUEUE_ELT_CLEANUP(elt) do { } while(0)
162 #endif /* !XNU_KERNEL_PRIVATE */
164 static __inline__
void
169 elt
->next
= que
->next
;
171 elt
->next
->prev
= elt
;
175 static __inline__
void
181 elt
->prev
= que
->prev
;
182 elt
->prev
->next
= elt
;
186 static __inline__ queue_entry_t
190 register queue_entry_t elt
= (queue_entry_t
) 0;
192 if (que
->next
!= que
) {
194 elt
->next
->prev
= que
;
195 que
->next
= elt
->next
;
196 __DEQUEUE_ELT_CLEANUP(elt
);
202 static __inline__ queue_entry_t
206 register queue_entry_t elt
= (queue_entry_t
) 0;
208 if (que
->prev
!= que
) {
210 elt
->prev
->next
= que
;
211 que
->prev
= elt
->prev
;
212 __DEQUEUE_ELT_CLEANUP(elt
);
218 static __inline__
void
222 elt
->next
->prev
= elt
->prev
;
223 elt
->prev
->next
= elt
->next
;
224 __DEQUEUE_ELT_CLEANUP(elt
);
227 static __inline__
void
232 entry
->next
= pred
->next
;
234 (pred
->next
)->prev
= entry
;
238 static __inline__
void
240 register queue_entry_t elt
)
242 (elt
->next
)->prev
= elt
->prev
;
243 (elt
->prev
)->next
= elt
->next
;
244 __DEQUEUE_ELT_CLEANUP(elt
);
247 #endif /* !__GNUC__ */
252 * Initialize the given queue.
255 * queue_t q; \* MODIFIED *\
257 #define queue_init(q) \
266 * Returns the first entry in the queue,
268 * queue_entry_t queue_first(q)
269 * queue_t q; \* IN *\
271 #define queue_first(q) ((q)->next)
276 * Returns the entry after an item in the queue.
278 * queue_entry_t queue_next(qc)
281 #define queue_next(qc) ((qc)->next)
286 * Returns the last entry in the queue.
288 * queue_entry_t queue_last(q)
289 * queue_t q; \* IN *\
291 #define queue_last(q) ((q)->prev)
296 * Returns the entry before an item in the queue.
298 * queue_entry_t queue_prev(qc)
301 #define queue_prev(qc) ((qc)->prev)
306 * Tests whether a new entry is really the end of
309 * boolean_t queue_end(q, qe)
313 #define queue_end(q, qe) ((q) == (qe))
318 * Tests whether a queue is empty.
320 * boolean_t queue_empty(q)
323 #define queue_empty(q) queue_end((q), queue_first(q))
326 /*----------------------------------------------------------------*/
328 * Macros that operate on generic structures. The queue
329 * chain may be at any location within the structure, and there
330 * may be more than one chain.
336 * Insert a new element at the tail of the queue.
338 * void queue_enter(q, elt, type, field)
341 * <type> is what's in our queue
342 * <field> is the chain field in (*<type>)
344 #define queue_enter(head, elt, type, field) \
346 register queue_entry_t __prev; \
348 __prev = (head)->prev; \
349 if ((head) == __prev) { \
350 (head)->next = (queue_entry_t) (elt); \
353 ((type)__prev)->field.next = (queue_entry_t)(elt);\
355 (elt)->field.prev = __prev; \
356 (elt)->field.next = head; \
357 (head)->prev = (queue_entry_t) elt; \
361 * Macro: queue_enter_first
363 * Insert a new element at the head of the queue.
365 * void queue_enter_first(q, elt, type, field)
368 * <type> is what's in our queue
369 * <field> is the chain field in (*<type>)
371 #define queue_enter_first(head, elt, type, field) \
373 register queue_entry_t __next; \
375 __next = (head)->next; \
376 if ((head) == __next) { \
377 (head)->prev = (queue_entry_t) (elt); \
380 ((type)__next)->field.prev = (queue_entry_t)(elt);\
382 (elt)->field.next = __next; \
383 (elt)->field.prev = head; \
384 (head)->next = (queue_entry_t) elt; \
388 * Macro: queue_insert_before
390 * Insert a new element before a given element.
392 * void queue_insert_before(q, elt, cur, type, field)
396 * <type> is what's in our queue
397 * <field> is the chain field in (*<type>)
399 #define queue_insert_before(head, elt, cur, type, field) \
401 register queue_entry_t __prev; \
403 if ((head) == (queue_entry_t)(cur)) { \
404 (elt)->field.next = (head); \
405 if ((head)->next == (head)) { /* only element */ \
406 (elt)->field.prev = (head); \
407 (head)->next = (queue_entry_t)(elt); \
408 } else { /* last element */ \
409 __prev = (elt)->field.prev = (head)->prev; \
410 ((type)__prev)->field.next = (queue_entry_t)(elt);\
412 (head)->prev = (queue_entry_t)(elt); \
414 (elt)->field.next = (queue_entry_t)(cur); \
415 if ((head)->next == (queue_entry_t)(cur)) { \
416 /* first element */ \
417 (elt)->field.prev = (head); \
418 (head)->next = (queue_entry_t)(elt); \
419 } else { /* middle element */ \
420 __prev = (elt)->field.prev = (cur)->field.prev; \
421 ((type)__prev)->field.next = (queue_entry_t)(elt);\
423 (cur)->field.prev = (queue_entry_t)(elt); \
428 * Macro: queue_insert_after
430 * Insert a new element after a given element.
432 * void queue_insert_after(q, elt, cur, type, field)
436 * <type> is what's in our queue
437 * <field> is the chain field in (*<type>)
439 #define queue_insert_after(head, elt, cur, type, field) \
441 register queue_entry_t __next; \
443 if ((head) == (queue_entry_t)(cur)) { \
444 (elt)->field.prev = (head); \
445 if ((head)->next == (head)) { /* only element */ \
446 (elt)->field.next = (head); \
447 (head)->prev = (queue_entry_t)(elt); \
448 } else { /* first element */ \
449 __next = (elt)->field.next = (head)->next; \
450 ((type)__next)->field.prev = (queue_entry_t)(elt);\
452 (head)->next = (queue_entry_t)(elt); \
454 (elt)->field.prev = (queue_entry_t)(cur); \
455 if ((head)->prev == (queue_entry_t)(cur)) { \
457 (elt)->field.next = (head); \
458 (head)->prev = (queue_entry_t)(elt); \
459 } else { /* middle element */ \
460 __next = (elt)->field.next = (cur)->field.next; \
461 ((type)__next)->field.prev = (queue_entry_t)(elt);\
463 (cur)->field.next = (queue_entry_t)(elt); \
468 * Macro: queue_field [internal use only]
470 * Find the queue_chain_t (or queue_t) for the
471 * given element (thing) in the given queue (head)
473 #define queue_field(head, thing, type, field) \
474 (((head) == (thing)) ? (head) : &((type)(thing))->field)
477 * Macro: queue_remove
479 * Remove an arbitrary item from the queue.
481 * void queue_remove(q, qe, type, field)
482 * arguments as in queue_enter
484 #define queue_remove(head, elt, type, field) \
486 register queue_entry_t __next, __prev; \
488 __next = (elt)->field.next; \
489 __prev = (elt)->field.prev; \
491 if ((head) == __next) \
492 (head)->prev = __prev; \
494 ((type)__next)->field.prev = __prev; \
496 if ((head) == __prev) \
497 (head)->next = __next; \
499 ((type)__prev)->field.next = __next; \
501 (elt)->field.next = NULL; \
502 (elt)->field.prev = NULL; \
506 * Macro: queue_remove_first
508 * Remove and return the entry at the head of
511 * queue_remove_first(head, entry, type, field)
512 * entry is returned by reference
514 #define queue_remove_first(head, entry, type, field) \
516 register queue_entry_t __next; \
518 (entry) = (type) ((head)->next); \
519 __next = (entry)->field.next; \
521 if ((head) == __next) \
522 (head)->prev = (head); \
524 ((type)(__next))->field.prev = (head); \
525 (head)->next = __next; \
527 (entry)->field.next = NULL; \
528 (entry)->field.prev = NULL; \
532 * Macro: queue_remove_last
534 * Remove and return the entry at the tail of
537 * queue_remove_last(head, entry, type, field)
538 * entry is returned by reference
540 #define queue_remove_last(head, entry, type, field) \
542 register queue_entry_t __prev; \
544 (entry) = (type) ((head)->prev); \
545 __prev = (entry)->field.prev; \
547 if ((head) == __prev) \
548 (head)->next = (head); \
550 ((type)(__prev))->field.next = (head); \
551 (head)->prev = __prev; \
553 (entry)->field.next = NULL; \
554 (entry)->field.prev = NULL; \
558 * Macro: queue_assign
560 #define queue_assign(to, from, type, field) \
562 ((type)((from)->prev))->field.next = (to); \
563 ((type)((from)->next))->field.prev = (to); \
568 * Macro: queue_new_head
570 * rebase old queue to new queue head
572 * queue_new_head(old, new, type, field)
575 * <type> is what's in our queue
576 * <field> is the chain field in (*<type>)
578 #define queue_new_head(old, new, type, field) \
580 if (!queue_empty(old)) { \
582 ((type)((new)->next))->field.prev = (new); \
583 ((type)((new)->prev))->field.next = (new); \
590 * Macro: queue_iterate
592 * iterate over each item in the queue.
593 * Generates a 'for' loop, setting elt to
594 * each item in turn (by reference).
596 * queue_iterate(q, elt, type, field)
599 * <type> is what's in our queue
600 * <field> is the chain field in (*<type>)
602 #define queue_iterate(head, elt, type, field) \
603 for ((elt) = (type) queue_first(head); \
604 !queue_end((head), (queue_entry_t)(elt)); \
605 (elt) = (type) queue_next(&(elt)->field))
607 #ifdef MACH_KERNEL_PRIVATE
609 #include <kern/lock.h>
611 /*----------------------------------------------------------------*/
613 * Define macros for queues with locks.
615 struct mpqueue_head
{
616 struct queue_entry head
; /* header for queue */
618 lck_mtx_ext_t lock_data_ext
;
621 typedef struct mpqueue_head mpqueue_head_t
;
623 #define round_mpq(size) (size)
626 #if defined(__i386__) || defined(__x86_64__)
628 #define mpqueue_init(q, lck_grp, lck_attr) \
630 queue_init(&(q)->head); \
631 lck_mtx_init_ext(&(q)->lock_data, \
632 &(q)->lock_data_ext, \
639 #define mpqueue_init(q, lck_grp, lck_attr) \
641 queue_init(&(q)->head); \
642 lck_spin_init(&(q)->lock_data, \
649 #define mpenqueue_tail(q, elt) \
651 lck_mtx_lock_spin_always(&(q)->lock_data); \
652 enqueue_tail(&(q)->head, elt); \
653 lck_mtx_unlock_always(&(q)->lock_data); \
656 #define mpdequeue_head(q, elt) \
658 lck_mtx_lock_spin_always(&(q)->lock_data); \
659 if (queue_empty(&(q)->head)) \
662 *(elt) = dequeue_head(&(q)->head); \
663 lck_mtx_unlock_always(&(q)->lock_data); \
666 #endif /* MACH_KERNEL_PRIVATE */
668 #endif /* _KERN_QUEUE_H_ */