2 * Copyright (c) 2018 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@
29 #ifndef _KERN_PRIORITY_QUEUE_H_
30 #define _KERN_PRIORITY_QUEUE_H_
32 #include <mach/mach_types.h>
33 #include <kern/macro_help.h>
34 #include <kern/assert.h>
36 #include <sys/cdefs.h>
41 * A generic priorty ordered queue implementation based on pairing heaps.
44 * - A Back-to-Basics Empirical Study of Priority Queues (https://arxiv.org/abs/1403.0252)
45 * - The Pairing Heap: A New Form of Self-Adjusting Heap (https://www.cs.cmu.edu/~sleator/papers/pairing-heaps.pdf)
47 * The XNU implementation is a basic version of the pairing heap. It allows for O(1) insertion and amortized O(log n)
48 * deletion. It is not a stable data structure since adding stability would need more pointers and hence more memory.
50 * The implementation supports two types of key storage:
52 * Type 1: PRIORITY_QUEUE_GENERIC_KEY
54 * This flag is useful when the priorities are either larger than 8-bits or the node comparision needs
55 * extra information other than the priority. The nodes do not store the priorities themselves and on
56 * comparision, callout to the comparator (of type priority_queue_compare_fn_t) provided as part of
59 * Sample Initialization:
62 * static struct priority_queue pq;
63 * priority_queue_init(pq, PRIORITY_QUEUE_MAX_HEAP | PRIORITY_QUEUE_GENERIC_KEY);
66 * For this type, all insertions, priority_increase, priority_decrease must pass PRIORITY_QUEUE_KEY_NONE
67 * as the priority key field.
69 * Type 2: PRIORITY_QUEUE_BUILTIN_KEY
71 * This type is useful when the priorities need to be stored within the data structure itself.
72 * Each node in the priority queue maintains a 8-bit priority key.
74 * Sample Initialization:
76 * static struct priority_queue pq;
77 * priority_queue_init(pq, PRIORITY_QUEUE_MAX_HEAP | PRIORITY_QUEUE_BUILTIN_KEY);
83 * The semantics of Min/Max heap are not used by the implementation, it assumes that the comparison block
84 * that is passed to the insertion / removal / ... macros provides the right ordering.
86 * However for human readability purposes, whether this heap is a MIN or MAX heap is passed
87 * at initialization time, and will influence whether accessors like priority_queue_min
88 * or priority_queue_max can be used.
93 * Both types use a common queue head and linkage pattern.
94 * The head of a priority queue is declared as:
96 * struct priority_queue pq_head;
98 * Elements in this queue are linked together using struct priority_queue_entry objects embedded within a structure:
103 * struct priority_queue_entry link;
107 * struct some_data is referred to as the queue "element"
109 * This method uses the next, prev and child pointers of the struct priority_queue_entry linkage object embedded in a
110 * queue element to point to other elements in the queue. The head of the priority queue (the priority_queue
111 * object) will point to the root of the pairing heap (NULL if heap is empty). This method allows multiple chains
112 * through a given object, by embedding multiple priority_queue_entry objects in the structure, while simultaneously
113 * providing fast removal and insertion into the heap using only priority_queue_entry object pointers.
118 * Priority keys maintained by the data structure.
119 * Since the priority is packed in the node itself, it restricts keys to be 8-bits only.
121 #define PRIORITY_QUEUE_KEY_NONE 0
122 typedef uint8_t priority_queue_key_t
;
125 * Flags passed to priority_queue_init()
127 * One key type must be picked (default is BUILTIN_KEY)
128 * Min or Max heap must be picked (default is MAX_HEAP)
130 typedef enum priority_queue_flags
{
131 PRIORITY_QUEUE_BUILTIN_KEY
= 0x0,
132 PRIORITY_QUEUE_GENERIC_KEY
= 0x1,
133 PRIORITY_QUEUE_MAX_HEAP
= 0x0,
134 PRIORITY_QUEUE_MIN_HEAP
= 0x2,
135 #define PRIORITY_QUEUE_BUILTIN_MAX_HEAP (PRIORITY_QUEUE_MAX_HEAP | PRIORITY_QUEUE_BUILTIN_KEY)
136 } priority_queue_flags_t
;
141 * For 64-bit platforms, pack the priority key into the child pointer
142 * The packing/unpacking is done using a compiler trick to sign extend long.
143 * This avoids additional NULL checks which are needed in typical packing
144 * implementation. The idea is to define the packed location as a long and
145 * for unpacking simply cast it to a full pointer which sign extends it.
147 #define PRIORITY_QUEUE_ENTRY_CHILD_BITS 56
148 #define PRIORITY_QUEUE_ENTRY_KEY_BITS 8
150 typedef struct priority_queue_entry
{
151 struct priority_queue_entry
*next
;
152 struct priority_queue_entry
*prev
;
153 long key
: PRIORITY_QUEUE_ENTRY_KEY_BITS
;
154 long child
: PRIORITY_QUEUE_ENTRY_CHILD_BITS
;
155 } *priority_queue_entry_t
;
160 * For 32-bit platforms, use an extra field to store the key since child pointer packing
161 * is not an option. The child is maintained as a long to use the same packing/unpacking
162 * routines that work for 64-bit platforms.
164 typedef struct priority_queue_entry
{
165 struct priority_queue_entry
*next
;
166 struct priority_queue_entry
*prev
;
168 priority_queue_key_t key
;
169 } *priority_queue_entry_t
;
171 #endif /* __LP64__ */
174 * Comparator block prototype
176 * - elements to compare
178 * comparision result to indicate relative ordering of elements according to the heap type
180 typedef int (^priority_queue_compare_fn_t
)(struct priority_queue_entry
*e1
,
181 struct priority_queue_entry
*e2
);
184 * Standard comparision routines for max and min heap.
185 * Must be used with PRIORITY_QUEUE_BUILTIN_KEY only.
188 priority_queue_element_builtin_key_compare(priority_queue_entry_t e1
, priority_queue_entry_t e2
)
190 return (int)e2
->key
- (int)e1
->key
;
193 #define priority_heap_make_comparator(name1, name2, type, field, ...) \
194 (^int(priority_queue_entry_t __e1, priority_queue_entry_t __e2){ \
195 type *name1 = pqe_element_fast(__e1, type, field); \
196 type *name2 = pqe_element_fast(__e2, type, field); \
200 #define PRIORITY_QUEUE_SCHED_PRI_MAX_HEAP_COMPARE \
201 (^int(priority_queue_entry_t e1, priority_queue_entry_t e2){ \
202 return -priority_queue_element_builtin_key_compare(e1, e2); \
205 #define PRIORITY_QUEUE_SCHED_PRI_MIN_HEAP_COMPARE \
206 (^int(priority_queue_entry_t e1, priority_queue_entry_t e2){ \
207 return priority_queue_element_builtin_key_compare(e1, e2); \
211 * Helper routines for packing/unpacking the child pointer in heap nodes.
212 * On 64-bit platforms, these routines rely on the fact that the sign extension
213 * for the lower 56-bits of a kernel pointer results in the real pointer. The trick
214 * works for NULL pointers as well.
216 #define pqueue_entry_pack_child(qe, child_ptr) ((qe)->child = (long)(child_ptr))
217 #define pqueue_entry_unpack_child(qe) ((struct priority_queue_entry *)((qe)->child))
220 * Priority queue head structure.
221 * Stores the comparision function using pointer packing. The remaining bit is used
222 * for type of the queue.
224 struct priority_queue
{
226 * we pack priority_queue_flags_t in the least significant two bits
227 * of the root pointer.
229 #define PRIORITY_QUEUE_ROOT_FLAGS_MASK (3ul)
230 #define PRIORITY_QUEUE_ROOT_POINTER_MASK (~PRIORITY_QUEUE_ROOT_FLAGS_MASK)
231 unsigned long pq_root_packed
;
235 * Macro: pqe_element_fast
237 * Convert a priority_queue_entry_t to a queue element pointer.
238 * Get a pointer to the user-defined element containing
239 * a given priority_queue_entry_t
241 * The fast variant assumes that `qe` is not NULL
243 * pqe_element_fast(qe, type, field)
244 * <priority_queue_entry_t> qe
245 * <type> type of element in priority queue
246 * <field> chain field in (*<type>)
248 * <type *> containing qe
250 #define pqe_element_fast(qe, type, field) __container_of(qe, type, field)
255 * Convert a priority_queue_entry_t to a queue element pointer.
256 * Get a pointer to the user-defined element containing
257 * a given priority_queue_entry_t
259 * The non fast variant handles NULL `qe`
261 * pqe_element(qe, type, field)
262 * <priority_queue_entry_t> qe
263 * <type> type of element in priority queue
264 * <field> chain field in (*<type>)
266 * <type *> containing qe
268 #define pqe_element(qe, type, field) ({ \
269 priority_queue_entry_t _tmp_entry = (qe); \
270 _tmp_entry ? pqe_element_fast(_tmp_entry, type, field) : ((type *)NULL); \
273 #define pqueue_has_generic_keys(p) \
274 (((p)->pq_root_packed & PRIORITY_QUEUE_GENERIC_KEY) != 0)
276 #define pqueue_has_builtin_keys(p) \
277 (((p)->pq_root_packed & PRIORITY_QUEUE_GENERIC_KEY) == 0)
279 #define pqueue_is_min_heap(p) \
280 (((p)->pq_root_packed & PRIORITY_QUEUE_MIN_HEAP) != 0)
282 #define pqueue_is_max_heap(p) \
283 (((p)->pq_root_packed & PRIORITY_QUEUE_MIN_HEAP) == 0)
286 * Macro: pqueue_pack_root
288 * Pack the root pointer of the head.
290 * pqueue_pack_root(q, root_ptr)
291 * <struct priority_queue *> q
292 * <priority_queue_entry_t> root_ptr
294 #define pqueue_pack_root(q, root_ptr) \
296 uintptr_t __flags = (q)->pq_root_packed & PRIORITY_QUEUE_ROOT_FLAGS_MASK; \
297 (q)->pq_root_packed = (uintptr_t)(root_ptr) | __flags; \
301 * Macro: pqueue_unpack_root
303 * Unpack the root pointer from the head of the priority queue.
305 * pqueue_unpack_root(q)
306 * <struct priority_queue *> q
308 * <priority_queue_entry_t>
310 #define pqueue_unpack_root(q) \
311 ((priority_queue_entry_t)((q)->pq_root_packed & PRIORITY_QUEUE_ROOT_POINTER_MASK))
314 * Macro: pqueue_list_remove
316 * Helper routine to remove an element from the list at its level
318 * pqueue_list_remove(elt)
319 * <priority_queue_entry_t> elt
324 pqueue_list_remove(priority_queue_entry_t elt
)
326 assert(elt
->prev
!= NULL
);
327 /* Check if elt is head of list at its level; */
328 /* If yes, make the next node the head at that level */
329 /* Else, remove elt from the list at that level */
330 if (pqueue_entry_unpack_child(elt
->prev
) == elt
) {
331 pqueue_entry_pack_child(elt
->prev
, elt
->next
);
333 elt
->prev
->next
= elt
->next
;
335 /* Update prev for next element in list */
336 if (elt
->next
!= NULL
)
337 elt
->next
->prev
= elt
->prev
;
341 * Macro: pqueue_merge
343 * Helper routine to merge two subtrees of the heap to form a single tree and
344 * maintain the parent > child invariant. If the two keys are equal, the current
345 * implementation makes the first subtree the parent and the second one the child.
347 * pqueue_merge(subtree_a, subtree_b, cmp_fn)
348 * <priority_queue_entry_t> subtree_a
349 * <priority_queue_entry_t> subtree_b
350 * <cmp_fn> comparator function
352 * <priority_queue_entry_t> pointing to root of the merged tree
354 static inline priority_queue_entry_t
355 pqueue_merge(priority_queue_entry_t subtree_a
, priority_queue_entry_t subtree_b
,
356 priority_queue_compare_fn_t cmp_fn
)
358 priority_queue_entry_t merge_result
= NULL
;
359 if (subtree_a
== NULL
) {
360 merge_result
= subtree_b
;
361 } else if (subtree_b
== NULL
|| (subtree_a
== subtree_b
)) {
362 merge_result
= subtree_a
;
364 priority_queue_entry_t parent
= subtree_a
;
365 priority_queue_entry_t child
= subtree_b
;
366 if (cmp_fn(subtree_a
, subtree_b
) < 0) {
370 /* Insert the child as the first element in the parent's child list */
371 child
->next
= pqueue_entry_unpack_child(parent
);
372 child
->prev
= parent
;
373 if (pqueue_entry_unpack_child(parent
) != NULL
)
374 pqueue_entry_unpack_child(parent
)->prev
= child
;
375 /* Create the parent child relationship */
376 pqueue_entry_pack_child(parent
, child
);
379 merge_result
= parent
;
385 * Macro: pqueue_pair_meld
387 * Helper routine to splitwise pair a set of subtrees on a list at a given level and then
388 * meld them together to form a new tree while maintaining the invariant parent > child.
390 * The caller must check the element is non NULL.
393 * pqueue_pair_meld(elt, cmp_fn)
394 * <priority_queue_entry_t> elt
395 * <cmp_fn> comparator function
397 * <priority_queue_entry_t> pointing to root of the melded tree
399 priority_queue_entry_t
400 pqueue_pair_meld(priority_queue_entry_t e
, priority_queue_compare_fn_t cmp_fn
);
403 * Macro: pqueue_update_key
405 * Helper routine to update the key for a node in the heap. Note that the priority keys are only
406 * maintained for the PRIORITY_QUEUE_BUILTIN_KEY type of priority queue. For PRIORITY_QUEUE_GENERIC_KEY,
407 * this routine does nothing.
409 * pqueue_update_key(que, elt, new_key)
410 * <struct priority_queue *> que
411 * <priority_queue_entry_t> elt
412 * <priority_queue_key_t> new_key
417 pqueue_update_key(struct priority_queue
*que
, priority_queue_entry_t elt
,
418 priority_queue_key_t new_key
)
420 if (pqueue_has_builtin_keys(que
)) {
421 assert(new_key
<= UINT8_MAX
);
424 assert(new_key
== PRIORITY_QUEUE_KEY_NONE
);
429 * Macro: pqueue_remove_root
431 * Helper routine to remove the root element in a priority queue.
433 * pqueue_remove_root(que, cmp_fn)
434 * <struct priority_queue *> que
435 * <priority_queue_entry_t> old_root
436 * <cmp_fn> comparator function
440 static inline priority_queue_entry_t
441 pqueue_remove_root(struct priority_queue
*que
, priority_queue_entry_t old_root
,
442 priority_queue_compare_fn_t cmp_fn
)
444 priority_queue_entry_t new_root
= pqueue_entry_unpack_child(old_root
);
445 if (new_root
) new_root
= pqueue_pair_meld(new_root
, cmp_fn
);
446 pqueue_pack_root(que
, new_root
);
451 * Macro: pqueue_remove_non_root
453 * Helper routine to remove a non root element in a priority queue.
455 * pqueue_remove_non_root(que, cmp_fn)
456 * <struct priority_queue *> que
457 * <priority_queue_entry_t> elt
458 * <cmp_fn> comparator function
462 static inline priority_queue_entry_t
463 pqueue_remove_non_root(struct priority_queue
*que
, priority_queue_entry_t elt
,
464 priority_queue_compare_fn_t cmp_fn
)
466 priority_queue_entry_t child
, new_root
;
468 /* To remove a non-root element with children levels, */
469 /* - Remove element from its current level iist */
470 /* - Pairwise split all the elements in the child level list */
471 /* - Meld all these splits (right-to-left) to form new subtree */
472 /* - Merge the root subtree with the newly formed subtree */
473 pqueue_list_remove(elt
);
475 child
= pqueue_entry_unpack_child(elt
);
477 child
= pqueue_pair_meld(child
, cmp_fn
);
478 new_root
= pqueue_merge(pqueue_unpack_root(que
), child
, cmp_fn
);
479 pqueue_pack_root(que
, new_root
);
486 * Macro: pqueue_destroy
488 * Destroy a priority queue safely. This routine accepts a callback
489 * to handle any cleanup for elements in the priority queue. The queue does
490 * not maintain its invariants while getting destroyed. The priority queue and
491 * the linkage nodes need to be re-initialized before re-using them.
493 * Note: the offset is the offset to the linkage inside the elements
494 * That are linked inside the priority heap, because pqueue_destroy
495 * can't use pqe_element.
497 * pqueue_destroy(q, offset, callback)
498 * <struct priority_queue *> q
500 * <callback> callback for each element
506 pqueue_destroy(struct priority_queue
*q
, size_t offset
,
507 void (^callback
)(void *e
));
510 * Priority Queue functionality routines
514 * Macro: priority_queue_empty
516 * Tests whether a priority queue is empty.
518 * boolean_t priority_queue_empty(q)
519 * <struct priority_queue *> q
521 #define priority_queue_empty(q) (pqueue_unpack_root((q)) == NULL)
524 * Macro: priority_queue_entry_key
526 * Returns the priority queue entry key for an element on a PRIORITY_QUEUE_BUILTIN_KEY
527 * queue. It should not be called for an element on a PRIORITY_QUEUE_GENERIC_KEY queue.
529 * priority_queue_key_t priority_queue_entry_key(q, elt)
530 * <struct priority_queue *> q
531 * <struct priority_queue_entry *> elt
533 #define priority_queue_entry_key(q, elt) ({ \
534 assert(pqueue_has_builtin_keys(q)); \
535 (priority_queue_key_t)((elt)->key); \
539 * Macro: priority_queue_init
541 * Initialze a <struct priority_queue *> by setting the flags
543 * - PRIORITY_QUEUE_BUILTIN_KEY or PRIORITY_QUEUE_GENERIC_KEY
544 * - PRIORITY_QUEUE_MAX_HEAP or PRIORITY_QUEUE_MIN_HEAP
546 * priority_queue_init(q, cmp_fn, queue_type)
547 * <struct priority_queue *> q
548 * <priority_queue_flags_t> queue_flags
552 #define priority_queue_init(q, flags) \
554 pqueue_pack_root((q), NULL); \
555 (q)->pq_root_packed = (flags); \
559 * Macro: priority_queue_entry_init
561 * Initialze a priority_queue_entry_t
563 * priority_queue_entry_init(qe)
564 * <priority_queue_entry_t> qe
568 #define priority_queue_entry_init(qe) \
572 pqueue_entry_pack_child((qe), NULL); \
573 (qe)->key = PRIORITY_QUEUE_KEY_NONE; \
577 * Macro: priority_queue_insert
579 * Insert an element into the priority queue
581 * priority_queue_insert(que, elt, new_key, cmp_fn)
582 * <struct priority_queue *> que
583 * <priority_queue_entry_t> elt
584 * <priority_queue_key_t> new_key
585 * <cmp_fn> comparator function
587 * Whether the inserted element became the new root
589 static inline boolean_t
590 priority_queue_insert(struct priority_queue
*que
, priority_queue_entry_t elt
,
591 priority_queue_key_t new_key
, priority_queue_compare_fn_t cmp_fn
)
593 priority_queue_entry_t new_root
;
595 pqueue_update_key(que
, elt
, new_key
);
596 new_root
= pqueue_merge(pqueue_unpack_root(que
), elt
, cmp_fn
);
597 pqueue_pack_root(que
, new_root
);
598 return new_root
== elt
;
602 * Macro: priority_queue_remove
604 * Removes an element from the priority queue
606 * priority_queue_remove(que, elt, cmp_fn)
607 * <struct priority_queue *> que
608 * <priority_queue_entry_t> elt
609 * <cmp_fn> comparator function
611 * Whether the removed element was the root
613 static inline boolean_t
614 priority_queue_remove(struct priority_queue
*que
, priority_queue_entry_t elt
,
615 priority_queue_compare_fn_t cmp_fn
)
617 if (elt
== pqueue_unpack_root(que
)) {
618 pqueue_remove_root(que
, elt
, cmp_fn
);
619 priority_queue_entry_init(elt
);
622 pqueue_remove_non_root(que
, elt
, cmp_fn
);
623 priority_queue_entry_init(elt
);
629 * Macro: priority_queue_entry_decrease
632 * This function is badly named for a min-heap, as it means the element
633 * moves toward the root, which happens if the key value became smaller.
636 * Decrease the priority of an element in the priority queue. Since the heap invariant is to always
637 * have the maximum element at the root, the most efficient way to implement this is to remove
638 * the element and re-insert it into the heap.
640 * For PRIORITY_QUEUE_BUILTIN_KEY, the new_key is passed into this routine since the priority is
641 * maintained by the data structure. For PRIORITY_QUEUE_GENERIC_KEY, the caller must update the priority
642 * in the element and then call this routine. For the new_key field, it must pass PRIORITY_QUEUE_KEY_NONE.
644 * priority_queue_entry_decrease(que, elt, new_key, cmp_fn)
645 * <struct priority_queue *> que
646 * <priority_queue_entry_t> elt
647 * <priority_queue_key_t> new_key
648 * <cmp_fn> comparator function
650 * Whether the update caused the root or its key to change.
652 static inline boolean_t
653 priority_queue_entry_decrease(struct priority_queue
*que
, priority_queue_entry_t elt
,
654 priority_queue_key_t new_key
, priority_queue_compare_fn_t cmp_fn
)
656 boolean_t was_root
= priority_queue_remove(que
, elt
, cmp_fn
);
657 /* Insert it back in the heap; insertion also causes the priority update in the element */
658 priority_queue_insert(que
, elt
, new_key
, cmp_fn
);
663 * Macro: priority_queue_entry_increase
666 * This function is badly named for a min-heap, as it means the element
667 * moves away from the root, which happens if the key value became larger.
670 * Increase the priority of an element in the priority queue. If the root is being increased, no change
671 * to the data structure is needed. For elements at any other level, unhook it from that level and
674 * For PRIORITY_QUEUE_BUILTIN_KEY, the new_key is passed into this routine since the priority is
675 * maintained by the data structure. For PRIORITY_QUEUE_GENERIC_KEY, the caller must update the priority
676 * in the element and then call this routine. For the new_key field, it must pass PRIORITY_QUEUE_KEY_NONE.
678 * priority_queue_entry_increase(que, elt, new_key, cmp_fn)
679 * <struct priority_queue *> que
680 * <priority_queue_entry_t> elt
681 * <priority_queue_key_t> new_key
682 * <cmp_fn> comparator function
684 * Whether the update caused the root or its key to change.
686 static inline boolean_t
687 priority_queue_entry_increase(struct priority_queue
*que
, priority_queue_entry_t elt
,
688 priority_queue_key_t new_key
, priority_queue_compare_fn_t cmp_fn
)
690 if (elt
== pqueue_unpack_root(que
)) {
691 pqueue_update_key(que
, elt
, new_key
);
695 /* Remove the element from its current level list */
696 pqueue_list_remove(elt
);
697 /* Re-insert the element into the heap with a merge */
698 return priority_queue_insert(que
, elt
, new_key
, cmp_fn
);
702 * Min/Max nodes lookup and removal routines
703 * Since the data structure is unaware of the type of heap being constructed, it provides both the min
704 * and max variants of the lookup and removal routines. Both variants do the exact same operation and
705 * it is up to the callers to call the right variant which makes semantic sense for the type of heap.
709 * Macro: priority_queue_max
711 * Lookup the max element in a priority queue. It simply returns the root of the
714 * priority_queue_max(q, type, field)
715 * <struct priority_queue *> q
716 * <type> type of element in priority queue
717 * <field> chain field in (*<type>)
719 * <type *> max element
721 #define priority_queue_max(q, type, field) ({ \
722 assert(pqueue_is_max_heap(q)); \
723 pqe_element(pqueue_unpack_root(q), type, field); \
727 * Macro: priority_queue_min
729 * Lookup the min element in a priority queue. It simply returns the root of the
732 * priority_queue_min(q, type, field)
733 * <struct priority_queue *> q
734 * <type> type of element in priority queue
735 * <field> chain field in (*<type>)
737 * <type *> min element
739 #define priority_queue_min(q, type, field) ({ \
740 assert(pqueue_is_min_heap(que)); \
741 priority_queue_entry_key(pqueue_unpack_root(q), type, field); \
745 * Macro: priority_queue_max_key
747 * Lookup the max key in a priority queue.
749 * priority_queue_max_key(q)
750 * <struct priority_queue *> q
754 #define priority_queue_max_key(q) ({ \
755 assert(pqueue_is_max_heap(q)); \
756 priority_queue_entry_key(q, pqueue_unpack_root(q)); \
760 * Macro: priority_queue_min_key
762 * Lookup the min key in a priority queue.
764 * priority_queue_min_key(q)
765 * <struct priority_queue *> q
769 #define priority_queue_min_key(q) ({ \
770 assert(pqueue_is_min_heap(q)); \
771 priority_queue_entry_key(pqueue_unpack_root(q)); \
775 * Macro: priority_queue_remove_max
777 * Remove the max element in a priority queue.
778 * Uses the priority_queue_remove() routine to actually do the removal.
780 * priority_queue_remove_max(q, type, field)
781 * <struct priority_queue *> q
782 * <type> type of element in priority queue
783 * <field> chain field in (*<type>)
785 * <type *> max element
787 #define priority_queue_remove_max(q, type, field, cmp_fn) ({ \
788 assert(pqueue_is_max_heap(q)); \
789 pqe_element(pqueue_remove_root(q, pqueue_unpack_root(q), cmp_fn), type, field); \
793 * Macro: priority_queue_remove_min
795 * Remove the min element in a priority queue.
796 * Uses the priority_queue_remove() routine to actually do the removal.
798 * priority_queue_remove_min(q, type, field)
799 * <struct priority_queue *> q
800 * <type> type of element in priority queue
801 * <field> chain field in (*<type>)
803 * <type *> min element
805 #define priority_queue_remove_min(q, type, field, cmp_fn) ({ \
806 assert(pqueue_is_min_heap(que)); \
807 pqe_element(pqueue_remove_root(q, pqueue_unpack_root(q), cmp_fn), type, field); \
811 * Macro: priority_queue_destroy
813 * Destroy a priority queue safely. This routine accepts a callback
814 * to handle any cleanup for elements in the priority queue. The queue does
815 * not maintain its invariants while getting destroyed. The priority queue and
816 * the linkage nodes need to be re-initialized before re-using them.
818 * priority_queue_destroy(q, type, field, callback)
819 * <struct priority_queue *> q
820 * <type> type of element in priority queue
821 * <field> chain field in (*<type>)
822 * <callback> callback for each element
827 #define priority_queue_destroy(q, type, field, callback, ...) \
828 pqueue_destroy(q, offsetof(type, field), callback, ##__VA_ARGS__)
832 #endif /* _KERN_PRIORITY_QUEUE_H_ */