Loading...
libkern/c++/priority_queue.cpp xnu-8020.121.3 xnu-8792.61.2
--- xnu/xnu-8020.121.3/libkern/c++/priority_queue.cpp
+++ xnu/xnu-8792.61.2/libkern/c++/priority_queue.cpp
@@ -236,6 +236,12 @@
 	}
 
 	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);
@@ -251,13 +257,31 @@
 		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 = remove(que, elt);
-		insert(que, 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;
 	}
 
@@ -271,7 +295,7 @@
 		/* 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);
+		return insert(que, elt, false);
 	}
 
 	static inline entry_t
@@ -291,6 +315,7 @@
 			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;
@@ -329,8 +354,12 @@
 	}
 
 	static inline bool
-	insert(queue_t que, entry_t elt)
-	{
+	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;
 	}
 
@@ -338,7 +367,13 @@
 	remove_root(queue_t que, entry_t old_root)
 	{
 		entry_t new_root = unpack_child(old_root);
-		que->pq_root = new_root ? meld_pair(que, new_root) : NULL;
+
+		if (new_root) {
+			que->pq_root = meld_pair(que, new_root);
+			pack_child(old_root, nullptr);
+		} else {
+			que->pq_root = NULL;
+		}
 		return old_root;
 	}
 
@@ -347,19 +382,9 @@
 	{
 		if (elt == que->pq_root) {
 			remove_root(que, elt);
-			elt->next = elt->prev = NULL;
-			elt->child = 0;
-#if CONFIG_KERNEL_TBI && KASAN_TBI
-			elt->tag = 0;
-#endif /* CONFIG_KERNEL_TBI && KASAN_TBI */
 			return true;
 		} else {
 			remove_non_root(que, elt);
-			elt->next = elt->prev = NULL;
-			elt->child = 0;
-#if CONFIG_KERNEL_TBI && KASAN_TBI
-			elt->tag = 0;
-#endif
 			return false;
 		}
 	}