]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/queue.h
xnu-517.3.15.tar.gz
[apple/xnu.git] / osfmk / kern / queue.h
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * @OSF_COPYRIGHT@
27 */
28/*
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon rights
51 * to redistribute these changes.
52 */
53/*
54 */
55/*
56 * File: queue.h
57 * Author: Avadis Tevanian, Jr.
58 * Date: 1985
59 *
60 * Type definitions for generic queues.
61 *
62 */
63
64#ifndef _KERN_QUEUE_H_
65#define _KERN_QUEUE_H_
66
67#include <kern/lock.h>
68#include <kern/macro_help.h>
69
70/*
71 * Queue of abstract objects. Queue is maintained
72 * within that object.
73 *
74 * Supports fast removal from within the queue.
75 *
76 * How to declare a queue of elements of type "foo_t":
77 * In the "*foo_t" type, you must have a field of
78 * type "queue_chain_t" to hold together this queue.
79 * There may be more than one chain through a
80 * "foo_t", for use by different queues.
81 *
82 * Declare the queue as a "queue_t" type.
83 *
84 * Elements of the queue (of type "foo_t", that is)
85 * are referred to by reference, and cast to type
86 * "queue_entry_t" within this module.
87 */
88
89/*
90 * A generic doubly-linked list (queue).
91 */
92
93struct queue_entry {
94 struct queue_entry *next; /* next element */
95 struct queue_entry *prev; /* previous element */
96};
97
98typedef struct queue_entry *queue_t;
99typedef struct queue_entry queue_head_t;
100typedef struct queue_entry queue_chain_t;
101typedef struct queue_entry *queue_entry_t;
102
103/*
104 * enqueue puts "elt" on the "queue".
105 * dequeue returns the first element in the "queue".
106 * remqueue removes the specified "elt" from the specified "queue".
107 */
108
109#define enqueue(queue,elt) enqueue_tail(queue, elt)
110#define dequeue(queue) dequeue_head(queue)
111
112#if !defined(__GNUC__)
113
114/* Enqueue element to head of queue */
115extern void enqueue_head(
116 queue_t que,
117 queue_entry_t elt);
118
119/* Enqueue element to tail of queue */
120extern void enqueue_tail(
121 queue_t que,
122 queue_entry_t elt);
123
124/* Dequeue element from head of queue */
125extern queue_entry_t dequeue_head(
126 queue_t que);
127
128/* Dequeue element from tail of queue */
129extern queue_entry_t dequeue_tail(
130 queue_t que);
131
132/* Dequeue element */
133extern void remqueue(
134 queue_t que,
135 queue_entry_t elt);
136
137/* Enqueue element after a particular elem */
138extern void insque(
139 queue_entry_t entry,
140 queue_entry_t pred);
141
142/* Dequeue element */
143extern int remque(
144 queue_entry_t elt);
145
146#else
147
148static __inline__ void
149enqueue_head(
150 queue_t que,
151 queue_entry_t elt)
152{
153 elt->next = que->next;
154 elt->prev = que;
155 elt->next->prev = elt;
156 que->next = elt;
157}
158
159static __inline__ void
160enqueue_tail(
161 queue_t que,
162 queue_entry_t elt)
163{
164 elt->next = que;
165 elt->prev = que->prev;
166 elt->prev->next = elt;
167 que->prev = elt;
168}
169
170static __inline__ queue_entry_t
171dequeue_head(
172 queue_t que)
173{
174 register queue_entry_t elt = (queue_entry_t) 0;
175
176 if (que->next != que) {
177 elt = que->next;
178 elt->next->prev = que;
179 que->next = elt->next;
180 }
181
182 return (elt);
183}
184
185static __inline__ queue_entry_t
186dequeue_tail(
187 queue_t que)
188{
189 register queue_entry_t elt = (queue_entry_t) 0;
190
191 if (que->prev != que) {
192 elt = que->prev;
193 elt->prev->next = que;
194 que->prev = elt->prev;
195 }
196
197 return (elt);
198}
199
200static __inline__ void
201remqueue(
202 queue_t que,
203 queue_entry_t elt)
204{
205 elt->next->prev = elt->prev;
206 elt->prev->next = elt->next;
207}
208
209static __inline__ void
210insque(
211 queue_entry_t entry,
212 queue_entry_t pred)
213{
214 entry->next = pred->next;
215 entry->prev = pred;
216 (pred->next)->prev = entry;
217 pred->next = entry;
218}
219
220static __inline__ integer_t
221remque(
222 register queue_entry_t elt)
223{
224 (elt->next)->prev = elt->prev;
225 (elt->prev)->next = elt->next;
226
227 return((integer_t)elt);
228}
229
230#endif /* defined(__GNUC__) */
231
232/*
233 * Macro: queue_init
234 * Function:
235 * Initialize the given queue.
236 * Header:
237 * void queue_init(q)
238 * queue_t q; \* MODIFIED *\
239 */
240#define queue_init(q) \
241MACRO_BEGIN \
242 (q)->next = (q);\
243 (q)->prev = (q);\
244MACRO_END
245
246/*
247 * Macro: queue_first
248 * Function:
249 * Returns the first entry in the queue,
250 * Header:
251 * queue_entry_t queue_first(q)
252 * queue_t q; \* IN *\
253 */
254#define queue_first(q) ((q)->next)
255
256/*
257 * Macro: queue_next
258 * Function:
259 * Returns the entry after an item in the queue.
260 * Header:
261 * queue_entry_t queue_next(qc)
262 * queue_t qc;
263 */
264#define queue_next(qc) ((qc)->next)
265
266/*
267 * Macro: queue_last
268 * Function:
269 * Returns the last entry in the queue.
270 * Header:
271 * queue_entry_t queue_last(q)
272 * queue_t q; \* IN *\
273 */
274#define queue_last(q) ((q)->prev)
275
276/*
277 * Macro: queue_prev
278 * Function:
279 * Returns the entry before an item in the queue.
280 * Header:
281 * queue_entry_t queue_prev(qc)
282 * queue_t qc;
283 */
284#define queue_prev(qc) ((qc)->prev)
285
286/*
287 * Macro: queue_end
288 * Function:
289 * Tests whether a new entry is really the end of
290 * the queue.
291 * Header:
292 * boolean_t queue_end(q, qe)
293 * queue_t q;
294 * queue_entry_t qe;
295 */
296#define queue_end(q, qe) ((q) == (qe))
297
298/*
299 * Macro: queue_empty
300 * Function:
301 * Tests whether a queue is empty.
302 * Header:
303 * boolean_t queue_empty(q)
304 * queue_t q;
305 */
306#define queue_empty(q) queue_end((q), queue_first(q))
307
308
309/*----------------------------------------------------------------*/
310/*
311 * Macros that operate on generic structures. The queue
312 * chain may be at any location within the structure, and there
313 * may be more than one chain.
314 */
315
316/*
317 * Macro: queue_enter
318 * Function:
319 * Insert a new element at the tail of the queue.
320 * Header:
321 * void queue_enter(q, elt, type, field)
322 * queue_t q;
323 * <type> elt;
324 * <type> is what's in our queue
325 * <field> is the chain field in (*<type>)
326 */
327#define queue_enter(head, elt, type, field) \
328MACRO_BEGIN \
329 register queue_entry_t prev; \
330 \
331 prev = (head)->prev; \
332 if ((head) == prev) { \
333 (head)->next = (queue_entry_t) (elt); \
334 } \
335 else { \
336 ((type)prev)->field.next = (queue_entry_t)(elt);\
337 } \
338 (elt)->field.prev = prev; \
339 (elt)->field.next = head; \
340 (head)->prev = (queue_entry_t) elt; \
341MACRO_END
342
343/*
344 * Macro: queue_enter_first
345 * Function:
346 * Insert a new element at the head of the queue.
347 * Header:
348 * void queue_enter_first(q, elt, type, field)
349 * queue_t q;
350 * <type> elt;
351 * <type> is what's in our queue
352 * <field> is the chain field in (*<type>)
353 */
354#define queue_enter_first(head, elt, type, field) \
355MACRO_BEGIN \
356 register queue_entry_t next; \
357 \
358 next = (head)->next; \
359 if ((head) == next) { \
360 (head)->prev = (queue_entry_t) (elt); \
361 } \
362 else { \
363 ((type)next)->field.prev = (queue_entry_t)(elt);\
364 } \
365 (elt)->field.next = next; \
366 (elt)->field.prev = head; \
367 (head)->next = (queue_entry_t) elt; \
368MACRO_END
369
370/*
371 * Macro: queue_insert_before
372 * Function:
373 * Insert a new element before a given element.
374 * Header:
375 * void queue_insert_before(q, elt, cur, type, field)
376 * queue_t q;
377 * <type> elt;
378 * <type> cur;
379 * <type> is what's in our queue
380 * <field> is the chain field in (*<type>)
381 */
382#define queue_insert_before(head, elt, cur, type, field) \
383MACRO_BEGIN \
384 register queue_entry_t prev; \
385 \
386 if ((head) == (queue_entry_t)(cur)) { \
387 (elt)->field.next = (head); \
388 if ((head)->next == (head)) { /* only element */ \
389 (elt)->field.prev = (head); \
390 (head)->next = (queue_entry_t)(elt); \
391 } else { /* last element */ \
392 prev = (elt)->field.prev = (head)->prev; \
393 ((type)prev)->field.next = (queue_entry_t)(elt);\
394 } \
395 (head)->prev = (queue_entry_t)(elt); \
396 } else { \
397 (elt)->field.next = (queue_entry_t)(cur); \
398 if ((head)->next == (queue_entry_t)(cur)) { \
399 /* first element */ \
400 (elt)->field.prev = (head); \
401 (head)->next = (queue_entry_t)(elt); \
402 } else { /* middle element */ \
403 prev = (elt)->field.prev = (cur)->field.prev; \
404 ((type)prev)->field.next = (queue_entry_t)(elt);\
405 } \
406 (cur)->field.prev = (queue_entry_t)(elt); \
407 } \
408MACRO_END
409
410/*
411 * Macro: queue_insert_after
412 * Function:
413 * Insert a new element after a given element.
414 * Header:
415 * void queue_insert_after(q, elt, cur, type, field)
416 * queue_t q;
417 * <type> elt;
418 * <type> cur;
419 * <type> is what's in our queue
420 * <field> is the chain field in (*<type>)
421 */
422#define queue_insert_after(head, elt, cur, type, field) \
423MACRO_BEGIN \
424 register queue_entry_t next; \
425 \
426 if ((head) == (queue_entry_t)(cur)) { \
427 (elt)->field.prev = (head); \
428 if ((head)->next == (head)) { /* only element */ \
429 (elt)->field.next = (head); \
430 (head)->prev = (queue_entry_t)(elt); \
431 } else { /* first element */ \
432 next = (elt)->field.next = (head)->next; \
433 ((type)next)->field.prev = (queue_entry_t)(elt);\
434 } \
435 (head)->next = (queue_entry_t)(elt); \
436 } else { \
437 (elt)->field.prev = (queue_entry_t)(cur); \
438 if ((head)->prev == (queue_entry_t)(cur)) { \
439 /* last element */ \
440 (elt)->field.next = (head); \
441 (head)->prev = (queue_entry_t)(elt); \
442 } else { /* middle element */ \
443 next = (elt)->field.next = (cur)->field.next; \
444 ((type)next)->field.prev = (queue_entry_t)(elt);\
445 } \
446 (cur)->field.next = (queue_entry_t)(elt); \
447 } \
448MACRO_END
449
450/*
451 * Macro: queue_field [internal use only]
452 * Function:
453 * Find the queue_chain_t (or queue_t) for the
454 * given element (thing) in the given queue (head)
455 */
456#define queue_field(head, thing, type, field) \
457 (((head) == (thing)) ? (head) : &((type)(thing))->field)
458
459/*
460 * Macro: queue_remove
461 * Function:
462 * Remove an arbitrary item from the queue.
463 * Header:
464 * void queue_remove(q, qe, type, field)
465 * arguments as in queue_enter
466 */
467#define queue_remove(head, elt, type, field) \
468MACRO_BEGIN \
469 register queue_entry_t next, prev; \
470 \
471 next = (elt)->field.next; \
472 prev = (elt)->field.prev; \
473 \
474 if ((head) == next) \
475 (head)->prev = prev; \
476 else \
477 ((type)next)->field.prev = prev; \
478 \
479 if ((head) == prev) \
480 (head)->next = next; \
481 else \
482 ((type)prev)->field.next = next; \
483MACRO_END
484
485/*
486 * Macro: queue_remove_first
487 * Function:
488 * Remove and return the entry at the head of
489 * the queue.
490 * Header:
491 * queue_remove_first(head, entry, type, field)
492 * entry is returned by reference
493 */
494#define queue_remove_first(head, entry, type, field) \
495MACRO_BEGIN \
496 register queue_entry_t next; \
497 \
498 (entry) = (type) ((head)->next); \
499 next = (entry)->field.next; \
500 \
501 if ((head) == next) \
502 (head)->prev = (head); \
503 else \
504 ((type)(next))->field.prev = (head); \
505 (head)->next = next; \
506MACRO_END
507
508/*
509 * Macro: queue_remove_last
510 * Function:
511 * Remove and return the entry at the tail of
512 * the queue.
513 * Header:
514 * queue_remove_last(head, entry, type, field)
515 * entry is returned by reference
516 */
517#define queue_remove_last(head, entry, type, field) \
518MACRO_BEGIN \
519 register queue_entry_t prev; \
520 \
521 (entry) = (type) ((head)->prev); \
522 prev = (entry)->field.prev; \
523 \
524 if ((head) == prev) \
525 (head)->next = (head); \
526 else \
527 ((type)(prev))->field.next = (head); \
528 (head)->prev = prev; \
529MACRO_END
530
531/*
532 * Macro: queue_assign
533 */
534#define queue_assign(to, from, type, field) \
535MACRO_BEGIN \
536 ((type)((from)->prev))->field.next = (to); \
537 ((type)((from)->next))->field.prev = (to); \
538 *to = *from; \
539MACRO_END
540
541/*
542 * Macro: queue_new_head
543 * Function:
544 * rebase old queue to new queue head
545 * Header:
546 * queue_new_head(old, new, type, field)
547 * queue_t old;
548 * queue_t new;
549 * <type> is what's in our queue
550 * <field> is the chain field in (*<type>)
551 */
552#define queue_new_head(old, new, type, field) \
553MACRO_BEGIN \
554 if (!queue_empty(new)) { \
555 *(new) = *(old); \
556 ((type)((new)->next))->field.prev = (new); \
557 ((type)((new)->prev))->field.next = (new); \
558 } else { \
559 queue_init(new); \
560 } \
561MACRO_END
562
563/*
564 * Macro: queue_iterate
565 * Function:
566 * iterate over each item in the queue.
567 * Generates a 'for' loop, setting elt to
568 * each item in turn (by reference).
569 * Header:
570 * queue_iterate(q, elt, type, field)
571 * queue_t q;
572 * <type> elt;
573 * <type> is what's in our queue
574 * <field> is the chain field in (*<type>)
575 */
576#define queue_iterate(head, elt, type, field) \
577 for ((elt) = (type) queue_first(head); \
578 !queue_end((head), (queue_entry_t)(elt)); \
579 (elt) = (type) queue_next(&(elt)->field))
580
9bccf70c
A
581#include <sys/appleapiopts.h>
582
583#ifdef __APPLE_API_PRIVATE
584
585#ifdef MACH_KERNEL_PRIVATE
1c79356b 586
1c79356b
A
587/*----------------------------------------------------------------*/
588/*
589 * Define macros for queues with locks.
590 */
591struct mpqueue_head {
592 struct queue_entry head; /* header for queue */
593 decl_simple_lock_data(, lock) /* lock for queue */
594};
595
596typedef struct mpqueue_head mpqueue_head_t;
597
598#define round_mpq(size) (size)
599
600#define mpqueue_init(q) \
601MACRO_BEGIN \
602 queue_init(&(q)->head); \
603 simple_lock_init(&(q)->lock, ETAP_MISC_Q); \
604MACRO_END
605
606#define mpenqueue_tail(q, elt) \
607MACRO_BEGIN \
608 simple_lock(&(q)->lock); \
609 enqueue_tail(&(q)->head, elt); \
610 simple_unlock(&(q)->lock); \
611MACRO_END
612
613#define mpdequeue_head(q, elt) \
614MACRO_BEGIN \
615 simple_lock(&(q)->lock); \
616 if (queue_empty(&(q)->head)) \
617 *(elt) = 0; \
618 else \
619 *(elt) = dequeue_head(&(q)->head); \
620 simple_unlock(&(q)->lock); \
621MACRO_END
622
9bccf70c
A
623#endif /* MACH_KERNEL_PRIVATE */
624
625#endif /* __APPLE_API_PRIVATE */
1c79356b
A
626
627#endif /* _KERN_QUEUE_H_ */