]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/priority_queue.h
xnu-4903.221.2.tar.gz
[apple/xnu.git] / osfmk / kern / priority_queue.h
1 /*
2 * Copyright (c) 2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #ifndef _KERN_PRIORITY_QUEUE_H_
30 #define _KERN_PRIORITY_QUEUE_H_
31
32 #include <mach/mach_types.h>
33 #include <kern/macro_help.h>
34 #include <kern/assert.h>
35
36 #include <sys/cdefs.h>
37
38 __BEGIN_DECLS
39
40 /*
41 * A generic priorty ordered queue implementation based on pairing heaps.
42 *
43 * Reference Papers:
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)
46 *
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.
49 *
50 * The implementation supports two types of key storage:
51 *
52 * Type 1: PRIORITY_QUEUE_GENERIC_KEY
53 *
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
57 * initialization.
58 *
59 * Sample Initialization:
60 *
61 * {
62 * static struct priority_queue pq;
63 * priority_queue_init(pq, PRIORITY_QUEUE_MAX_HEAP | PRIORITY_QUEUE_GENERIC_KEY);
64 * }
65 *
66 * For this type, all insertions, priority_increase, priority_decrease must pass PRIORITY_QUEUE_KEY_NONE
67 * as the priority key field.
68 *
69 * Type 2: PRIORITY_QUEUE_BUILTIN_KEY
70 *
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.
73 *
74 * Sample Initialization:
75 * {
76 * static struct priority_queue pq;
77 * priority_queue_init(pq, PRIORITY_QUEUE_MAX_HEAP | PRIORITY_QUEUE_BUILTIN_KEY);
78 * }
79 *
80 *
81 * Min / Max Heap:
82 *
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.
85 *
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.
89 *
90 *
91 * Element Linkage:
92 *
93 * Both types use a common queue head and linkage pattern.
94 * The head of a priority queue is declared as:
95 *
96 * struct priority_queue pq_head;
97 *
98 * Elements in this queue are linked together using struct priority_queue_entry objects embedded within a structure:
99 * struct some_data {
100 * int field1;
101 * int field2;
102 * ...
103 * struct priority_queue_entry link;
104 * ...
105 * int last_field;
106 * };
107 * struct some_data is referred to as the queue "element"
108 *
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.
114 */
115
116
117 /*
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.
120 */
121 #define PRIORITY_QUEUE_KEY_NONE 0
122 typedef uint8_t priority_queue_key_t;
123
124 /*
125 * Flags passed to priority_queue_init()
126 *
127 * One key type must be picked (default is BUILTIN_KEY)
128 * Min or Max heap must be picked (default is MAX_HEAP)
129 */
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;
137
138 #ifdef __LP64__
139
140 /*
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.
146 */
147 #define PRIORITY_QUEUE_ENTRY_CHILD_BITS 56
148 #define PRIORITY_QUEUE_ENTRY_KEY_BITS 8
149
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;
156
157 #else /* __LP64__ */
158
159 /*
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.
163 */
164 typedef struct priority_queue_entry {
165 struct priority_queue_entry *next;
166 struct priority_queue_entry *prev;
167 long child;
168 priority_queue_key_t key;
169 } *priority_queue_entry_t;
170
171 #endif /* __LP64__ */
172
173 /*
174 * Comparator block prototype
175 * Args:
176 * - elements to compare
177 * Return:
178 * comparision result to indicate relative ordering of elements according to the heap type
179 */
180 typedef int (^priority_queue_compare_fn_t)(struct priority_queue_entry *e1,
181 struct priority_queue_entry *e2);
182
183 /*
184 * Standard comparision routines for max and min heap.
185 * Must be used with PRIORITY_QUEUE_BUILTIN_KEY only.
186 */
187 static inline int
188 priority_queue_element_builtin_key_compare(priority_queue_entry_t e1, priority_queue_entry_t e2)
189 {
190 return (int)e2->key - (int)e1->key;
191 }
192
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); \
197 __VA_ARGS__; \
198 })
199
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); \
203 })
204
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); \
208 })
209
210 /*
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.
215 * */
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))
218
219 /*
220 * Priority queue head structure.
221 * Stores the comparision function using pointer packing. The remaining bit is used
222 * for type of the queue.
223 */
224 struct priority_queue {
225 /*
226 * we pack priority_queue_flags_t in the least significant two bits
227 * of the root pointer.
228 */
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;
232 };
233
234 /*
235 * Macro: pqe_element_fast
236 * Function:
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
240 *
241 * The fast variant assumes that `qe` is not NULL
242 * Header:
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>)
247 * Returns:
248 * <type *> containing qe
249 */
250 #define pqe_element_fast(qe, type, field) __container_of(qe, type, field)
251
252 /*
253 * Macro: pqe_element
254 * Function:
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
258 *
259 * The non fast variant handles NULL `qe`
260 * Header:
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>)
265 * Returns:
266 * <type *> containing qe
267 */
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); \
271 })
272
273 #define pqueue_has_generic_keys(p) \
274 (((p)->pq_root_packed & PRIORITY_QUEUE_GENERIC_KEY) != 0)
275
276 #define pqueue_has_builtin_keys(p) \
277 (((p)->pq_root_packed & PRIORITY_QUEUE_GENERIC_KEY) == 0)
278
279 #define pqueue_is_min_heap(p) \
280 (((p)->pq_root_packed & PRIORITY_QUEUE_MIN_HEAP) != 0)
281
282 #define pqueue_is_max_heap(p) \
283 (((p)->pq_root_packed & PRIORITY_QUEUE_MIN_HEAP) == 0)
284
285 /*
286 * Macro: pqueue_pack_root
287 * Function:
288 * Pack the root pointer of the head.
289 * Header:
290 * pqueue_pack_root(q, root_ptr)
291 * <struct priority_queue *> q
292 * <priority_queue_entry_t> root_ptr
293 */
294 #define pqueue_pack_root(q, root_ptr) \
295 MACRO_BEGIN \
296 uintptr_t __flags = (q)->pq_root_packed & PRIORITY_QUEUE_ROOT_FLAGS_MASK; \
297 (q)->pq_root_packed = (uintptr_t)(root_ptr) | __flags; \
298 MACRO_END
299
300 /*
301 * Macro: pqueue_unpack_root
302 * Function:
303 * Unpack the root pointer from the head of the priority queue.
304 * Header:
305 * pqueue_unpack_root(q)
306 * <struct priority_queue *> q
307 * Returns:
308 * <priority_queue_entry_t>
309 */
310 #define pqueue_unpack_root(q) \
311 ((priority_queue_entry_t)((q)->pq_root_packed & PRIORITY_QUEUE_ROOT_POINTER_MASK))
312
313 /*
314 * Macro: pqueue_list_remove
315 * Function:
316 * Helper routine to remove an element from the list at its level
317 * Header:
318 * pqueue_list_remove(elt)
319 * <priority_queue_entry_t> elt
320 * Returns:
321 * None
322 */
323 static inline void
324 pqueue_list_remove(priority_queue_entry_t elt)
325 {
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);
332 } else {
333 elt->prev->next = elt->next;
334 }
335 /* Update prev for next element in list */
336 if (elt->next != NULL)
337 elt->next->prev = elt->prev;
338 }
339
340 /*
341 * Macro: pqueue_merge
342 * Function:
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.
346 * Header:
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
351 * Returns:
352 * <priority_queue_entry_t> pointing to root of the merged tree
353 */
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)
357 {
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;
363 } else {
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) {
367 parent = subtree_b;
368 child = subtree_a;
369 }
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);
377 parent->next = NULL;
378 parent->prev = NULL;
379 merge_result = parent;
380 }
381 return merge_result;
382 }
383
384 /*
385 * Macro: pqueue_pair_meld
386 * Function:
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.
389 *
390 * The caller must check the element is non NULL.
391 *
392 * Header:
393 * pqueue_pair_meld(elt, cmp_fn)
394 * <priority_queue_entry_t> elt
395 * <cmp_fn> comparator function
396 * Returns:
397 * <priority_queue_entry_t> pointing to root of the melded tree
398 */
399 priority_queue_entry_t
400 pqueue_pair_meld(priority_queue_entry_t e, priority_queue_compare_fn_t cmp_fn);
401
402 /*
403 * Macro: pqueue_update_key
404 * Function:
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.
408 * Header:
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
413 * Returns:
414 * None
415 */
416 static inline void
417 pqueue_update_key(struct priority_queue *que, priority_queue_entry_t elt,
418 priority_queue_key_t new_key)
419 {
420 if (pqueue_has_builtin_keys(que)) {
421 assert(new_key <= UINT8_MAX);
422 elt->key = new_key;
423 } else {
424 assert(new_key == PRIORITY_QUEUE_KEY_NONE);
425 }
426 }
427
428 /*
429 * Macro: pqueue_remove_root
430 * Function:
431 * Helper routine to remove the root element in a priority queue.
432 * Header:
433 * pqueue_remove_root(que, cmp_fn)
434 * <struct priority_queue *> que
435 * <priority_queue_entry_t> old_root
436 * <cmp_fn> comparator function
437 * Returns:
438 * old_root
439 */
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)
443 {
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);
447 return old_root;
448 }
449
450 /*
451 * Macro: pqueue_remove_non_root
452 * Function:
453 * Helper routine to remove a non root element in a priority queue.
454 * Header:
455 * pqueue_remove_non_root(que, cmp_fn)
456 * <struct priority_queue *> que
457 * <priority_queue_entry_t> elt
458 * <cmp_fn> comparator function
459 * Returns:
460 * elt
461 */
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)
465 {
466 priority_queue_entry_t child, new_root;
467
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);
474
475 child = pqueue_entry_unpack_child(elt);
476 if (child) {
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);
480 }
481
482 return elt;
483 }
484
485 /*
486 * Macro: pqueue_destroy
487 * Function:
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.
492 *
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.
496 * Header:
497 * pqueue_destroy(q, offset, callback)
498 * <struct priority_queue *> q
499 * <size_t> offset
500 * <callback> callback for each element
501 *
502 * Returns:
503 * None
504 */
505 void
506 pqueue_destroy(struct priority_queue *q, size_t offset,
507 void (^callback)(void *e));
508
509 /*
510 * Priority Queue functionality routines
511 */
512
513 /*
514 * Macro: priority_queue_empty
515 * Function:
516 * Tests whether a priority queue is empty.
517 * Header:
518 * boolean_t priority_queue_empty(q)
519 * <struct priority_queue *> q
520 */
521 #define priority_queue_empty(q) (pqueue_unpack_root((q)) == NULL)
522
523 /*
524 * Macro: priority_queue_entry_key
525 * Function:
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.
528 * Header:
529 * priority_queue_key_t priority_queue_entry_key(q, elt)
530 * <struct priority_queue *> q
531 * <struct priority_queue_entry *> elt
532 */
533 #define priority_queue_entry_key(q, elt) ({ \
534 assert(pqueue_has_builtin_keys(q)); \
535 (priority_queue_key_t)((elt)->key); \
536 })
537
538 /*
539 * Macro: priority_queue_init
540 * Function:
541 * Initialze a <struct priority_queue *> by setting the flags
542 * Valid flags are:
543 * - PRIORITY_QUEUE_BUILTIN_KEY or PRIORITY_QUEUE_GENERIC_KEY
544 * - PRIORITY_QUEUE_MAX_HEAP or PRIORITY_QUEUE_MIN_HEAP
545 * Header:
546 * priority_queue_init(q, cmp_fn, queue_type)
547 * <struct priority_queue *> q
548 * <priority_queue_flags_t> queue_flags
549 * Returns:
550 * None
551 */
552 #define priority_queue_init(q, flags) \
553 MACRO_BEGIN \
554 pqueue_pack_root((q), NULL); \
555 (q)->pq_root_packed = (flags); \
556 MACRO_END
557
558 /*
559 * Macro: priority_queue_entry_init
560 * Function:
561 * Initialze a priority_queue_entry_t
562 * Header:
563 * priority_queue_entry_init(qe)
564 * <priority_queue_entry_t> qe
565 * Returns:
566 * None
567 */
568 #define priority_queue_entry_init(qe) \
569 MACRO_BEGIN \
570 (qe)->next = NULL; \
571 (qe)->prev = NULL; \
572 pqueue_entry_pack_child((qe), NULL); \
573 (qe)->key = PRIORITY_QUEUE_KEY_NONE; \
574 MACRO_END
575
576 /*
577 * Macro: priority_queue_insert
578 * Function:
579 * Insert an element into the priority queue
580 * Header:
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
586 * Returns:
587 * Whether the inserted element became the new root
588 */
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)
592 {
593 priority_queue_entry_t new_root;
594
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;
599 }
600
601 /*
602 * Macro: priority_queue_remove
603 * Function:
604 * Removes an element from the priority queue
605 * Header:
606 * priority_queue_remove(que, elt, cmp_fn)
607 * <struct priority_queue *> que
608 * <priority_queue_entry_t> elt
609 * <cmp_fn> comparator function
610 * Returns:
611 * Whether the removed element was the root
612 */
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)
616 {
617 if (elt == pqueue_unpack_root(que)) {
618 pqueue_remove_root(que, elt, cmp_fn);
619 priority_queue_entry_init(elt);
620 return TRUE;
621 } else {
622 pqueue_remove_non_root(que, elt, cmp_fn);
623 priority_queue_entry_init(elt);
624 return FALSE;
625 }
626 }
627
628 /*
629 * Macro: priority_queue_entry_decrease
630 *
631 * WARNING:
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.
634 *
635 * Function:
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.
639 *
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.
643 * Header:
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
649 * Returns:
650 * Whether the update caused the root or its key to change.
651 */
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)
655 {
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);
659 return was_root;
660 }
661
662 /*
663 * Macro: priority_queue_entry_increase
664 *
665 * WARNING:
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.
668 *
669 * Function:
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
672 * re-merge it.
673 *
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.
677 * Header:
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
683 * Returns:
684 * Whether the update caused the root or its key to change.
685 */
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)
689 {
690 if (elt == pqueue_unpack_root(que)) {
691 pqueue_update_key(que, elt, new_key);
692 return TRUE;
693 }
694
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);
699 }
700
701 /*
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.
706 */
707
708 /*
709 * Macro: priority_queue_max
710 * Function:
711 * Lookup the max element in a priority queue. It simply returns the root of the
712 * priority queue.
713 * Header:
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>)
718 * Returns:
719 * <type *> max element
720 */
721 #define priority_queue_max(q, type, field) ({ \
722 assert(pqueue_is_max_heap(q)); \
723 pqe_element(pqueue_unpack_root(q), type, field); \
724 })
725
726 /*
727 * Macro: priority_queue_min
728 * Function:
729 * Lookup the min element in a priority queue. It simply returns the root of the
730 * priority queue.
731 * Header:
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>)
736 * Returns:
737 * <type *> min element
738 */
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); \
742 })
743
744 /*
745 * Macro: priority_queue_max_key
746 * Function:
747 * Lookup the max key in a priority queue.
748 * Header:
749 * priority_queue_max_key(q)
750 * <struct priority_queue *> q
751 * Returns:
752 * <type *> max key
753 */
754 #define priority_queue_max_key(q) ({ \
755 assert(pqueue_is_max_heap(q)); \
756 priority_queue_entry_key(q, pqueue_unpack_root(q)); \
757 })
758
759 /*
760 * Macro: priority_queue_min_key
761 * Function:
762 * Lookup the min key in a priority queue.
763 * Header:
764 * priority_queue_min_key(q)
765 * <struct priority_queue *> q
766 * Returns:
767 * <type *> min key
768 */
769 #define priority_queue_min_key(q) ({ \
770 assert(pqueue_is_min_heap(q)); \
771 priority_queue_entry_key(pqueue_unpack_root(q)); \
772 })
773
774 /*
775 * Macro: priority_queue_remove_max
776 * Function:
777 * Remove the max element in a priority queue.
778 * Uses the priority_queue_remove() routine to actually do the removal.
779 * Header:
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>)
784 * Returns:
785 * <type *> max element
786 */
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); \
790 })
791
792 /*
793 * Macro: priority_queue_remove_min
794 * Function:
795 * Remove the min element in a priority queue.
796 * Uses the priority_queue_remove() routine to actually do the removal.
797 * Header:
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>)
802 * Returns:
803 * <type *> min element
804 */
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); \
808 })
809
810 /*
811 * Macro: priority_queue_destroy
812 * Function:
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.
817 * Header:
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
823 *
824 * Returns:
825 * None
826 */
827 #define priority_queue_destroy(q, type, field, callback, ...) \
828 pqueue_destroy(q, offsetof(type, field), callback, ##__VA_ARGS__)
829
830 __END_DECLS
831
832 #endif /* _KERN_PRIORITY_QUEUE_H_ */