]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/priority_queue.h
dcb7d76a8258c6ce1b02fa1cf785639dcc0fb92c
[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 /*
342 * Macro: pqueue_merge
343 * Function:
344 * Helper routine to merge two subtrees of the heap to form a single tree and
345 * maintain the parent > child invariant. If the two keys are equal, the current
346 * implementation makes the first subtree the parent and the second one the child.
347 * Header:
348 * pqueue_merge(subtree_a, subtree_b, cmp_fn)
349 * <priority_queue_entry_t> subtree_a
350 * <priority_queue_entry_t> subtree_b
351 * <cmp_fn> comparator function
352 * Returns:
353 * <priority_queue_entry_t> pointing to root of the merged tree
354 */
355 static inline priority_queue_entry_t
356 pqueue_merge(priority_queue_entry_t subtree_a, priority_queue_entry_t subtree_b,
357 priority_queue_compare_fn_t cmp_fn)
358 {
359 priority_queue_entry_t merge_result = NULL;
360 if (subtree_a == NULL) {
361 merge_result = subtree_b;
362 } else if (subtree_b == NULL || (subtree_a == subtree_b)) {
363 merge_result = subtree_a;
364 } else {
365 priority_queue_entry_t parent = subtree_a;
366 priority_queue_entry_t child = subtree_b;
367 if (cmp_fn(subtree_a, subtree_b) < 0) {
368 parent = subtree_b;
369 child = subtree_a;
370 }
371 /* Insert the child as the first element in the parent's child list */
372 child->next = pqueue_entry_unpack_child(parent);
373 child->prev = parent;
374 if (pqueue_entry_unpack_child(parent) != NULL) {
375 pqueue_entry_unpack_child(parent)->prev = child;
376 }
377 /* Create the parent child relationship */
378 pqueue_entry_pack_child(parent, child);
379 parent->next = NULL;
380 parent->prev = NULL;
381 merge_result = parent;
382 }
383 return merge_result;
384 }
385
386 /*
387 * Macro: pqueue_pair_meld
388 * Function:
389 * Helper routine to splitwise pair a set of subtrees on a list at a given level and then
390 * meld them together to form a new tree while maintaining the invariant parent > child.
391 *
392 * The caller must check the element is non NULL.
393 *
394 * Header:
395 * pqueue_pair_meld(elt, cmp_fn)
396 * <priority_queue_entry_t> elt
397 * <cmp_fn> comparator function
398 * Returns:
399 * <priority_queue_entry_t> pointing to root of the melded tree
400 */
401 priority_queue_entry_t
402 pqueue_pair_meld(priority_queue_entry_t e, priority_queue_compare_fn_t cmp_fn);
403
404 /*
405 * Macro: pqueue_update_key
406 * Function:
407 * Helper routine to update the key for a node in the heap. Note that the priority keys are only
408 * maintained for the PRIORITY_QUEUE_BUILTIN_KEY type of priority queue. For PRIORITY_QUEUE_GENERIC_KEY,
409 * this routine does nothing.
410 * Header:
411 * pqueue_update_key(que, elt, new_key)
412 * <struct priority_queue *> que
413 * <priority_queue_entry_t> elt
414 * <priority_queue_key_t> new_key
415 * Returns:
416 * None
417 */
418 static inline void
419 pqueue_update_key(struct priority_queue *que, priority_queue_entry_t elt,
420 priority_queue_key_t new_key)
421 {
422 if (pqueue_has_builtin_keys(que)) {
423 assert(new_key <= UINT8_MAX);
424 elt->key = new_key;
425 } else {
426 assert(new_key == PRIORITY_QUEUE_KEY_NONE);
427 }
428 }
429
430 /*
431 * Macro: pqueue_remove_root
432 * Function:
433 * Helper routine to remove the root element in a priority queue.
434 * Header:
435 * pqueue_remove_root(que, cmp_fn)
436 * <struct priority_queue *> que
437 * <priority_queue_entry_t> old_root
438 * <cmp_fn> comparator function
439 * Returns:
440 * old_root
441 */
442 static inline priority_queue_entry_t
443 pqueue_remove_root(struct priority_queue *que, priority_queue_entry_t old_root,
444 priority_queue_compare_fn_t cmp_fn)
445 {
446 priority_queue_entry_t new_root = pqueue_entry_unpack_child(old_root);
447 if (new_root) {
448 new_root = pqueue_pair_meld(new_root, cmp_fn);
449 }
450 pqueue_pack_root(que, new_root);
451 return old_root;
452 }
453
454 /*
455 * Macro: pqueue_remove_non_root
456 * Function:
457 * Helper routine to remove a non root element in a priority queue.
458 * Header:
459 * pqueue_remove_non_root(que, cmp_fn)
460 * <struct priority_queue *> que
461 * <priority_queue_entry_t> elt
462 * <cmp_fn> comparator function
463 * Returns:
464 * elt
465 */
466 static inline priority_queue_entry_t
467 pqueue_remove_non_root(struct priority_queue *que, priority_queue_entry_t elt,
468 priority_queue_compare_fn_t cmp_fn)
469 {
470 priority_queue_entry_t child, new_root;
471
472 /* To remove a non-root element with children levels, */
473 /* - Remove element from its current level iist */
474 /* - Pairwise split all the elements in the child level list */
475 /* - Meld all these splits (right-to-left) to form new subtree */
476 /* - Merge the root subtree with the newly formed subtree */
477 pqueue_list_remove(elt);
478
479 child = pqueue_entry_unpack_child(elt);
480 if (child) {
481 child = pqueue_pair_meld(child, cmp_fn);
482 new_root = pqueue_merge(pqueue_unpack_root(que), child, cmp_fn);
483 pqueue_pack_root(que, new_root);
484 }
485
486 return elt;
487 }
488
489 /*
490 * Macro: pqueue_destroy
491 * Function:
492 * Destroy a priority queue safely. This routine accepts a callback
493 * to handle any cleanup for elements in the priority queue. The queue does
494 * not maintain its invariants while getting destroyed. The priority queue and
495 * the linkage nodes need to be re-initialized before re-using them.
496 *
497 * Note: the offset is the offset to the linkage inside the elements
498 * That are linked inside the priority heap, because pqueue_destroy
499 * can't use pqe_element.
500 * Header:
501 * pqueue_destroy(q, offset, callback)
502 * <struct priority_queue *> q
503 * <size_t> offset
504 * <callback> callback for each element
505 *
506 * Returns:
507 * None
508 */
509 void
510 pqueue_destroy(struct priority_queue *q, size_t offset,
511 void (^callback)(void *e));
512
513 /*
514 * Priority Queue functionality routines
515 */
516
517 /*
518 * Macro: priority_queue_empty
519 * Function:
520 * Tests whether a priority queue is empty.
521 * Header:
522 * boolean_t priority_queue_empty(q)
523 * <struct priority_queue *> q
524 */
525 #define priority_queue_empty(q) (pqueue_unpack_root((q)) == NULL)
526
527 /*
528 * Macro: priority_queue_entry_key
529 * Function:
530 * Returns the priority queue entry key for an element on a PRIORITY_QUEUE_BUILTIN_KEY
531 * queue. It should not be called for an element on a PRIORITY_QUEUE_GENERIC_KEY queue.
532 * Header:
533 * priority_queue_key_t priority_queue_entry_key(q, elt)
534 * <struct priority_queue *> q
535 * <struct priority_queue_entry *> elt
536 */
537 #define priority_queue_entry_key(q, elt) ({ \
538 assert(pqueue_has_builtin_keys(q)); \
539 (priority_queue_key_t)((elt)->key); \
540 })
541
542 /*
543 * Macro: priority_queue_init
544 * Function:
545 * Initialze a <struct priority_queue *> by setting the flags
546 * Valid flags are:
547 * - PRIORITY_QUEUE_BUILTIN_KEY or PRIORITY_QUEUE_GENERIC_KEY
548 * - PRIORITY_QUEUE_MAX_HEAP or PRIORITY_QUEUE_MIN_HEAP
549 * Header:
550 * priority_queue_init(q, cmp_fn, queue_type)
551 * <struct priority_queue *> q
552 * <priority_queue_flags_t> queue_flags
553 * Returns:
554 * None
555 */
556 #define priority_queue_init(q, flags) \
557 MACRO_BEGIN \
558 pqueue_pack_root((q), NULL); \
559 (q)->pq_root_packed = (flags); \
560 MACRO_END
561
562 /*
563 * Macro: priority_queue_entry_init
564 * Function:
565 * Initialze a priority_queue_entry_t
566 * Header:
567 * priority_queue_entry_init(qe)
568 * <priority_queue_entry_t> qe
569 * Returns:
570 * None
571 */
572 #define priority_queue_entry_init(qe) \
573 MACRO_BEGIN \
574 (qe)->next = NULL; \
575 (qe)->prev = NULL; \
576 pqueue_entry_pack_child((qe), NULL); \
577 (qe)->key = PRIORITY_QUEUE_KEY_NONE; \
578 MACRO_END
579
580 /*
581 * Macro: priority_queue_insert
582 * Function:
583 * Insert an element into the priority queue
584 * Header:
585 * priority_queue_insert(que, elt, new_key, cmp_fn)
586 * <struct priority_queue *> que
587 * <priority_queue_entry_t> elt
588 * <priority_queue_key_t> new_key
589 * <cmp_fn> comparator function
590 * Returns:
591 * Whether the inserted element became the new root
592 */
593 static inline boolean_t
594 priority_queue_insert(struct priority_queue *que, priority_queue_entry_t elt,
595 priority_queue_key_t new_key, priority_queue_compare_fn_t cmp_fn)
596 {
597 priority_queue_entry_t new_root;
598
599 pqueue_update_key(que, elt, new_key);
600 new_root = pqueue_merge(pqueue_unpack_root(que), elt, cmp_fn);
601 pqueue_pack_root(que, new_root);
602 return new_root == elt;
603 }
604
605 /*
606 * Macro: priority_queue_remove
607 * Function:
608 * Removes an element from the priority queue
609 * Header:
610 * priority_queue_remove(que, elt, cmp_fn)
611 * <struct priority_queue *> que
612 * <priority_queue_entry_t> elt
613 * <cmp_fn> comparator function
614 * Returns:
615 * Whether the removed element was the root
616 */
617 static inline boolean_t
618 priority_queue_remove(struct priority_queue *que, priority_queue_entry_t elt,
619 priority_queue_compare_fn_t cmp_fn)
620 {
621 if (elt == pqueue_unpack_root(que)) {
622 pqueue_remove_root(que, elt, cmp_fn);
623 priority_queue_entry_init(elt);
624 return TRUE;
625 } else {
626 pqueue_remove_non_root(que, elt, cmp_fn);
627 priority_queue_entry_init(elt);
628 return FALSE;
629 }
630 }
631
632 /*
633 * Macro: priority_queue_entry_decrease
634 *
635 * WARNING:
636 * This function is badly named for a min-heap, as it means the element
637 * moves toward the root, which happens if the key value became smaller.
638 *
639 * Function:
640 * Decrease the priority of an element in the priority queue. Since the heap invariant is to always
641 * have the maximum element at the root, the most efficient way to implement this is to remove
642 * the element and re-insert it into the heap.
643 *
644 * For PRIORITY_QUEUE_BUILTIN_KEY, the new_key is passed into this routine since the priority is
645 * maintained by the data structure. For PRIORITY_QUEUE_GENERIC_KEY, the caller must update the priority
646 * in the element and then call this routine. For the new_key field, it must pass PRIORITY_QUEUE_KEY_NONE.
647 * Header:
648 * priority_queue_entry_decrease(que, elt, new_key, cmp_fn)
649 * <struct priority_queue *> que
650 * <priority_queue_entry_t> elt
651 * <priority_queue_key_t> new_key
652 * <cmp_fn> comparator function
653 * Returns:
654 * Whether the update caused the root or its key to change.
655 */
656 static inline boolean_t
657 priority_queue_entry_decrease(struct priority_queue *que, priority_queue_entry_t elt,
658 priority_queue_key_t new_key, priority_queue_compare_fn_t cmp_fn)
659 {
660 boolean_t was_root = priority_queue_remove(que, elt, cmp_fn);
661 /* Insert it back in the heap; insertion also causes the priority update in the element */
662 priority_queue_insert(que, elt, new_key, cmp_fn);
663 return was_root;
664 }
665
666 /*
667 * Macro: priority_queue_entry_increase
668 *
669 * WARNING:
670 * This function is badly named for a min-heap, as it means the element
671 * moves away from the root, which happens if the key value became larger.
672 *
673 * Function:
674 * Increase the priority of an element in the priority queue. If the root is being increased, no change
675 * to the data structure is needed. For elements at any other level, unhook it from that level and
676 * re-merge it.
677 *
678 * For PRIORITY_QUEUE_BUILTIN_KEY, the new_key is passed into this routine since the priority is
679 * maintained by the data structure. For PRIORITY_QUEUE_GENERIC_KEY, the caller must update the priority
680 * in the element and then call this routine. For the new_key field, it must pass PRIORITY_QUEUE_KEY_NONE.
681 * Header:
682 * priority_queue_entry_increase(que, elt, new_key, cmp_fn)
683 * <struct priority_queue *> que
684 * <priority_queue_entry_t> elt
685 * <priority_queue_key_t> new_key
686 * <cmp_fn> comparator function
687 * Returns:
688 * Whether the update caused the root or its key to change.
689 */
690 static inline boolean_t
691 priority_queue_entry_increase(struct priority_queue *que, priority_queue_entry_t elt,
692 priority_queue_key_t new_key, priority_queue_compare_fn_t cmp_fn)
693 {
694 if (elt == pqueue_unpack_root(que)) {
695 pqueue_update_key(que, elt, new_key);
696 return TRUE;
697 }
698
699 /* Remove the element from its current level list */
700 pqueue_list_remove(elt);
701 /* Re-insert the element into the heap with a merge */
702 return priority_queue_insert(que, elt, new_key, cmp_fn);
703 }
704
705 /*
706 * Min/Max nodes lookup and removal routines
707 * Since the data structure is unaware of the type of heap being constructed, it provides both the min
708 * and max variants of the lookup and removal routines. Both variants do the exact same operation and
709 * it is up to the callers to call the right variant which makes semantic sense for the type of heap.
710 */
711
712 /*
713 * Macro: priority_queue_max
714 * Function:
715 * Lookup the max element in a priority queue. It simply returns the root of the
716 * priority queue.
717 * Header:
718 * priority_queue_max(q, type, field)
719 * <struct priority_queue *> q
720 * <type> type of element in priority queue
721 * <field> chain field in (*<type>)
722 * Returns:
723 * <type *> max element
724 */
725 #define priority_queue_max(q, type, field) ({ \
726 assert(pqueue_is_max_heap(q)); \
727 pqe_element(pqueue_unpack_root(q), type, field); \
728 })
729
730 /*
731 * Macro: priority_queue_min
732 * Function:
733 * Lookup the min element in a priority queue. It simply returns the root of the
734 * priority queue.
735 * Header:
736 * priority_queue_min(q, type, field)
737 * <struct priority_queue *> q
738 * <type> type of element in priority queue
739 * <field> chain field in (*<type>)
740 * Returns:
741 * <type *> min element
742 */
743 #define priority_queue_min(q, type, field) ({ \
744 assert(pqueue_is_min_heap(que)); \
745 priority_queue_entry_key(pqueue_unpack_root(q), type, field); \
746 })
747
748 /*
749 * Macro: priority_queue_max_key
750 * Function:
751 * Lookup the max key in a priority queue.
752 * Header:
753 * priority_queue_max_key(q)
754 * <struct priority_queue *> q
755 * Returns:
756 * <type *> max key
757 */
758 #define priority_queue_max_key(q) ({ \
759 assert(pqueue_is_max_heap(q)); \
760 priority_queue_entry_key(q, pqueue_unpack_root(q)); \
761 })
762
763 /*
764 * Macro: priority_queue_min_key
765 * Function:
766 * Lookup the min key in a priority queue.
767 * Header:
768 * priority_queue_min_key(q)
769 * <struct priority_queue *> q
770 * Returns:
771 * <type *> min key
772 */
773 #define priority_queue_min_key(q) ({ \
774 assert(pqueue_is_min_heap(q)); \
775 priority_queue_entry_key(pqueue_unpack_root(q)); \
776 })
777
778 /*
779 * Macro: priority_queue_remove_max
780 * Function:
781 * Remove the max element in a priority queue.
782 * Uses the priority_queue_remove() routine to actually do the removal.
783 * Header:
784 * priority_queue_remove_max(q, type, field)
785 * <struct priority_queue *> q
786 * <type> type of element in priority queue
787 * <field> chain field in (*<type>)
788 * Returns:
789 * <type *> max element
790 */
791 #define priority_queue_remove_max(q, type, field, cmp_fn) ({ \
792 assert(pqueue_is_max_heap(q)); \
793 pqe_element(pqueue_remove_root(q, pqueue_unpack_root(q), cmp_fn), type, field); \
794 })
795
796 /*
797 * Macro: priority_queue_remove_min
798 * Function:
799 * Remove the min element in a priority queue.
800 * Uses the priority_queue_remove() routine to actually do the removal.
801 * Header:
802 * priority_queue_remove_min(q, type, field)
803 * <struct priority_queue *> q
804 * <type> type of element in priority queue
805 * <field> chain field in (*<type>)
806 * Returns:
807 * <type *> min element
808 */
809 #define priority_queue_remove_min(q, type, field, cmp_fn) ({ \
810 assert(pqueue_is_min_heap(que)); \
811 pqe_element(pqueue_remove_root(q, pqueue_unpack_root(q), cmp_fn), type, field); \
812 })
813
814 /*
815 * Macro: priority_queue_destroy
816 * Function:
817 * Destroy a priority queue safely. This routine accepts a callback
818 * to handle any cleanup for elements in the priority queue. The queue does
819 * not maintain its invariants while getting destroyed. The priority queue and
820 * the linkage nodes need to be re-initialized before re-using them.
821 * Header:
822 * priority_queue_destroy(q, type, field, callback)
823 * <struct priority_queue *> q
824 * <type> type of element in priority queue
825 * <field> chain field in (*<type>)
826 * <callback> callback for each element
827 *
828 * Returns:
829 * None
830 */
831 #define priority_queue_destroy(q, type, field, callback, ...) \
832 pqueue_destroy(q, offsetof(type, field), callback, ##__VA_ARGS__)
833
834 __END_DECLS
835
836 #endif /* _KERN_PRIORITY_QUEUE_H_ */