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