Loading...
libkern/c++/priority_queue.cpp xnu-12377.61.12 /dev/null
--- xnu/xnu-12377.61.12/libkern/c++/priority_queue.cpp
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright (c) 2018 Apple Inc. All rights reserved.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * unlawful or unlicensed copies of an Apple operating system, or to
- * circumvent, violate, or enable the circumvention or violation of, any
- * terms of an Apple operating system software license agreement.
- *
- * Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
- */
-
-#if KERNEL
-#include <kern/priority_queue.h>
-#include <mach/vm_param.h>
-#include <vm/vm_memtag.h>
-
-#ifdef __LP64__
-static_assert(PRIORITY_QUEUE_ENTRY_CHILD_BITS >= VM_KERNEL_POINTER_SIGNIFICANT_BITS,
-    "Priority Queue child pointer packing failed");
-#endif
-#endif // KERNEL
-
-#pragma mark priority queue helpers
-
-/*
- * These traits allow to parametrize `struct pqueue` below.
- */
-
-template <typename queue_t, typename entry_t>
-struct pqueue_entry_traits {
-	/*
-	 * Explain how to compare two elements in the natural order.
-	 */
-	static inline int
-	compare(queue_t que, entry_t a, entry_t b);
-};
-
-template <typename queue_t>
-struct pqueue_entry_traits<queue_t, priority_queue_entry_t> {
-	static inline int
-	compare(queue_t que, priority_queue_entry_t e1, priority_queue_entry_t e2)
-	{
-		return que->pq_cmp_fn(e1, e2);
-	}
-};
-
-template <typename queue_t>
-struct pqueue_entry_traits<queue_t, priority_queue_entry_deadline_t> {
-	static inline int
-	compare(queue_t que __unused,
-	    priority_queue_entry_deadline_t e1, priority_queue_entry_deadline_t e2)
-	{
-		return priority_heap_compare_ints(e1->deadline, e2->deadline);
-	}
-};
-
-template <typename queue_t>
-struct pqueue_entry_traits<queue_t, priority_queue_entry_sched_t> {
-	static inline int
-	compare(queue_t que __unused,
-	    priority_queue_entry_sched_t e1, priority_queue_entry_sched_t e2)
-	{
-		return (int)e2->key - (int)e1->key;
-	}
-};
-
-template <typename queue_t>
-struct pqueue_entry_traits<queue_t, priority_queue_entry_stable_t> {
-	static inline int
-	compare(queue_t que __unused,
-	    priority_queue_entry_stable_t e1, priority_queue_entry_stable_t e2)
-	{
-		/*
-		 * the key is (2 * pri + preempted) so preempted entries
-		 * sort "higher" than non preempted entries at the same priority.
-		 */
-		if (e1->key != e2->key) {
-			return (int)e2->key - (int)e1->key;
-		}
-		if (e1->stamp != e2->stamp) {
-			/*
-			 * preempted entries:     younger (bigger timestamp)  is "higher"
-			 * non preempted entries: older   (smaller timestamp) is "higher"
-			 */
-			if (e1->key & PRIORITY_QUEUE_ENTRY_PREEMPTED) {
-				return e1->stamp < e2->stamp ? 1 : -1;
-			} else {
-				return e1->stamp > e2->stamp ? 1 : -1;
-			}
-		}
-		return 0;
-	}
-};
-
-#pragma mark main template
-
-/*
- * Template for our priority queue.
- *
- * It is parametrized with:
- * - `queue_t`: the queue type
- * - `entry_t`: the element type
- *
- * It will use:
- * - priority_queue_is_min_heap() to determine if it is a min/max heap
- * - pqueue_entry_traits<queue_t, entry_t>::compare for the ordering
- */
-template <typename queue_t, typename entry_t>
-struct pqueue {
-	using entry_traits = pqueue_entry_traits<queue_t, entry_t>;
-
-	static inline void
-	pack_child(entry_t e, const entry_t child)
-	{
-#if CONFIG_KERNEL_TAGGING
-		e->tag = vm_memtag_extract_tag((vm_offset_t)child);
-#endif /* CONFIG_KERNEL_TAGGING */
-		e->child = (long)child;
-	}
-
-	static inline entry_t
-	unpack_child(entry_t e)
-	{
-#if CONFIG_KERNEL_TAGGING
-		return (entry_t)(vm_memtag_insert_tag(e->child, e->tag));
-#endif /* CONFIG_KERNEL_TAGGING */
-		return (entry_t)e->child;
-	}
-
-private:
-	static inline bool
-	merge_parent_is_subtree_b(queue_t que, entry_t subtree_a, entry_t subtree_b)
-	{
-		if (priority_queue_is_max_heap((queue_t)nullptr)) {
-			return entry_traits::compare(que, subtree_a, subtree_b) > 0;
-		}
-		return entry_traits::compare(que, subtree_a, subtree_b) < 0;
-	}
-
-	static inline entry_t
-	merge_pair_inline(queue_t que, entry_t subtree_a, entry_t subtree_b)
-	{
-		entry_t merge_result = NULL;
-		if (subtree_a == NULL) {
-			merge_result = subtree_b;
-		} else if (subtree_b == NULL || (subtree_a == subtree_b)) {
-			merge_result = subtree_a;
-		} else {
-			entry_t parent = subtree_a;
-			entry_t child = subtree_b;
-			if (merge_parent_is_subtree_b(que, subtree_a, subtree_b)) {
-				parent = subtree_b;
-				child = subtree_a;
-			}
-			/* Insert the child as the first element in the parent's child list */
-			child->next = unpack_child(parent);
-			child->prev = parent;
-			if (unpack_child(parent) != NULL) {
-				unpack_child(parent)->prev = child;
-			}
-			/* Create the parent child relationship */
-			pack_child(parent, child);
-			parent->next = NULL;
-			parent->prev = NULL;
-			merge_result = parent;
-		}
-		return merge_result;
-	}
-
-	OS_NOINLINE
-	static entry_t
-	merge_pair(queue_t que, entry_t subtree_a, entry_t subtree_b)
-	{
-		return merge_pair_inline(que, subtree_a, subtree_b);
-	}
-
-	OS_NOINLINE
-	static entry_t
-	meld_pair(queue_t que, entry_t elt)
-	{
-		entry_t pq_meld_result = NULL;
-		entry_t pair_list = NULL;
-
-		assert(elt); // caller needs to check this.
-
-		/* Phase 1: */
-		/* Split the list into a set of pairs going front to back. */
-		/* Hook these pairs onto an intermediary list in reverse order of traversal.*/
-
-		do {
-			/* Consider two elements at a time for pairing */
-			entry_t pair_item_a = elt;
-			entry_t pair_item_b = elt->next;
-			if (pair_item_b == NULL) {
-				/* Odd number of elements in the list; link the odd element */
-				/* as it is on the intermediate list. */
-				pair_item_a->prev = pair_list;
-				pair_list = pair_item_a;
-				break;
-			}
-			/* Found two elements to pair up */
-			elt = pair_item_b->next;
-			entry_t pair = merge_pair_inline(que, pair_item_a, pair_item_b);
-			/* Link the pair onto the intermediary list */
-			pair->prev = pair_list;
-			pair_list = pair;
-		} while (elt != NULL);
-
-		/* Phase 2: Merge all the pairs in the pair_list */
-		do {
-			elt = pair_list->prev;
-			pq_meld_result = merge_pair_inline(que, pq_meld_result, pair_list);
-			pair_list = elt;
-		} while (pair_list != NULL);
-
-		return pq_meld_result;
-	}
-
-	static inline void
-	list_clear(entry_t e)
-	{
-		e->next = e->prev = NULL;
-	}
-
-	static inline void
-	list_remove(entry_t elt)
-	{
-		assert(elt->prev != NULL);
-		/* Check if elt is head of list at its level;        */
-		/* If yes, make the next node the head at that level */
-		/* Else, remove elt from the list at that level      */
-		if (unpack_child(elt->prev) == elt) {
-			pack_child(elt->prev, elt->next);
-		} else {
-			elt->prev->next = elt->next;
-		}
-		/* Update prev for next element in list */
-		if (elt->next != NULL) {
-			elt->next->prev = elt->prev;
-		}
-		list_clear(elt);
-	}
-
-	static inline bool
-	sift_down(queue_t que, entry_t elt)
-	{
-		bool was_root = (que->pq_root == elt);
-
-		if (!was_root) {
-			remove_non_root(que, elt);
-			insert(que, elt, false);
-		} else if (unpack_child(elt)) {
-			remove_root(que, elt);
-			insert(que, elt, false);
-		} else {
-			/*
-			 * If the queue is reduced to a single element,
-			 * we have nothing to do.
-			 *
-			 * It is important not to, so that pq_root remains
-			 * non null at all times during priority changes,
-			 * so that unsynchronized peeking at the "emptiness"
-			 * of the priority queue works as expected.
-			 */
-		}
-		return was_root;
-	}
-
-	static inline bool
-	sift_up(queue_t que, entry_t elt)
-	{
-		if (elt == que->pq_root) {
-			return true;
-		}
-
-		/* Remove the element from its current level list */
-		list_remove(elt);
-		/* Re-insert the element into the heap with a merge */
-		return insert(que, elt, false);
-	}
-
-	static inline entry_t
-	remove_non_root(queue_t que, entry_t elt)
-	{
-		entry_t child, new_root;
-
-		/* To remove a non-root element with children levels, */
-		/* - Remove element from its current level list */
-		/* - Pairwise split all the elements in the child level list */
-		/* - Meld all these splits (right-to-left) to form new subtree */
-		/* - Merge the root subtree with the newly formed subtree */
-		list_remove(elt);
-
-		child = unpack_child(elt);
-		if (child) {
-			child = meld_pair(que, child);
-			new_root = merge_pair(que, que->pq_root, child);
-			que->pq_root = new_root;
-			pack_child(elt, nullptr);
-		}
-
-		return elt;
-	}
-
-public:
-
-	/*
-	 * exposed interfaces
-	 */
-
-	OS_NOINLINE
-	static void
-	destroy(queue_t que, uintptr_t offset, void (^callback)(void *e))
-	{
-		assert(callback != NULL);
-		entry_t head = que->pq_root;
-		entry_t tail = head;
-
-		while (head != NULL) {
-			entry_t child_list = unpack_child(head);
-			if (child_list) {
-				tail->next = child_list;
-				while (tail->next) {
-					tail = tail->next;
-				}
-			}
-
-			entry_t elt = head;
-			head = head->next;
-			callback((void *)((char *)elt - offset));
-		}
-
-		/* poison the queue now that it's destroyed */
-		que->pq_root = (entry_t)(~0ul);
-	}
-
-	static inline bool
-	insert(queue_t que, entry_t elt, bool clear = true)
-	{
-		if (clear) {
-			list_clear(elt);
-			pack_child(elt, nullptr);
-		}
-		return (que->pq_root = merge_pair(que, que->pq_root, elt)) == elt;
-	}
-
-	static inline entry_t
-	remove_root(queue_t que, entry_t old_root)
-	{
-		entry_t new_root = unpack_child(old_root);
-
-		if (new_root) {
-			que->pq_root = meld_pair(que, new_root);
-			pack_child(old_root, nullptr);
-		} else {
-			que->pq_root = NULL;
-		}
-		return old_root;
-	}
-
-	static inline bool
-	remove(queue_t que, entry_t elt)
-	{
-		if (elt == que->pq_root) {
-			remove_root(que, elt);
-			return true;
-		} else {
-			remove_non_root(que, elt);
-			return false;
-		}
-	}
-
-	static inline bool
-	entry_increased(queue_t que, entry_t elt)
-	{
-		if (priority_queue_is_max_heap(que)) {
-			return sift_up(que, elt);
-		} else {
-			return sift_down(que, elt);
-		}
-	}
-
-	static inline bool
-	entry_decreased(queue_t que, entry_t elt)
-	{
-		if (priority_queue_is_min_heap(que)) {
-			return sift_up(que, elt);
-		} else {
-			return sift_down(que, elt);
-		}
-	}
-};
-
-#pragma mark instantiation
-
-#define PRIORITY_QUEUE_MAKE_IMPL(pqueue_t, queue_t, entry_t)                    \
-                                                                                \
-using pqueue_t = pqueue<queue_t, entry_t>;                                      \
-                                                                                \
-extern "C" {                                                                    \
-                                                                                \
-__pqueue_overloadable void                                                      \
-_priority_queue_destroy(queue_t que, uintptr_t offset, void (^cb)(void *e))     \
-{                                                                               \
-	pqueue_t::destroy(que, offset, cb);                                     \
-}                                                                               \
-                                                                                \
-__pqueue_overloadable extern bool                                               \
-priority_queue_insert(queue_t que, entry_t elt)                                 \
-{                                                                               \
-	return pqueue_t::insert(que, elt);                                      \
-}                                                                               \
-                                                                                \
-__pqueue_overloadable extern entry_t                                            \
-_priority_queue_remove_root(queue_t que)                                        \
-{                                                                               \
-	return pqueue_t::remove_root(que, que->pq_root);                        \
-}                                                                               \
-                                                                                \
-__pqueue_overloadable extern bool                                               \
-priority_queue_remove(queue_t que, entry_t elt)                                 \
-{                                                                               \
-	return pqueue_t::remove(que, elt);                                      \
-}                                                                               \
-                                                                                \
-__pqueue_overloadable extern bool                                               \
-priority_queue_entry_decreased(queue_t que, entry_t elt)                        \
-{                                                                               \
-	return pqueue_t::entry_decreased(que, elt);                             \
-}                                                                               \
-                                                                                \
-__pqueue_overloadable extern bool                                               \
-priority_queue_entry_increased(queue_t que, entry_t elt)                        \
-{                                                                               \
-	return pqueue_t::entry_increased(que, elt);                             \
-}                                                                               \
-                                                                                \
-}
-
-PRIORITY_QUEUE_MAKE_IMPL(pqueue_min_t,
-    struct priority_queue_min *, priority_queue_entry_t);
-PRIORITY_QUEUE_MAKE_IMPL(pqueue_max_t,
-    struct priority_queue_max *, priority_queue_entry_t);
-
-PRIORITY_QUEUE_MAKE_IMPL(pqueue_sched_min_t,
-    struct priority_queue_sched_min *, priority_queue_entry_sched_t);
-PRIORITY_QUEUE_MAKE_IMPL(pqueue_sched_max_t,
-    struct priority_queue_sched_max *, priority_queue_entry_sched_t);
-
-PRIORITY_QUEUE_MAKE_IMPL(pqueue_deadline_min_t,
-    struct priority_queue_deadline_min *, priority_queue_entry_deadline_t);
-PRIORITY_QUEUE_MAKE_IMPL(pqueue_deadline_max_t,
-    struct priority_queue_deadline_max *, priority_queue_entry_deadline_t);
-
-PRIORITY_QUEUE_MAKE_IMPL(pqueue_sched_stable_min_t,
-    struct priority_queue_sched_stable_min *, priority_queue_entry_stable_t);
-PRIORITY_QUEUE_MAKE_IMPL(pqueue_sched_stable_max_t,
-    struct priority_queue_sched_stable_max *, priority_queue_entry_stable_t);