|
|
|
@ -23,14 +23,13 @@ priority_queue_append(struct priority_queue *self, void *new_item)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(new_item != NULL);
|
|
|
|
|
|
|
|
|
|
assert(LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (self->first_free >= MAX) goto err_enospc;
|
|
|
|
|
|
|
|
|
|
self->items[self->first_free++] = new_item;
|
|
|
|
|
/* Add one and prefix because we use 1-based indices in our backing array */
|
|
|
|
|
if (self->size + 1 == self->capacity) goto err_enospc;
|
|
|
|
|
self->items[++self->size] = new_item;
|
|
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
done:
|
|
|
|
@ -40,6 +39,21 @@ err_enospc:
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks if a priority queue is empty
|
|
|
|
|
* @param self the priority queue to check
|
|
|
|
|
* @returns true if empty, else otherwise
|
|
|
|
|
*/
|
|
|
|
|
static inline bool
|
|
|
|
|
priority_queue_is_empty(struct priority_queue *self)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
assert(!runtime_is_worker() || !software_interrupt_is_enabled());
|
|
|
|
|
|
|
|
|
|
return self->size == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Shifts an appended value upwards to restore heap structure property
|
|
|
|
|
* @param self the priority queue
|
|
|
|
@ -49,9 +63,15 @@ priority_queue_percolate_up(struct priority_queue *self)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(self->get_priority_fn != NULL);
|
|
|
|
|
assert(LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
|
|
|
|
|
for (int i = self->first_free - 1;
|
|
|
|
|
/* If there's only one element, set memoized lookup and early out */
|
|
|
|
|
if (self->size == 1) {
|
|
|
|
|
self->highest_priority = self->get_priority_fn(self->items[1]);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = self->size;
|
|
|
|
|
i / 2 != 0 && self->get_priority_fn(self->items[i]) < self->get_priority_fn(self->items[i / 2]); i /= 2) {
|
|
|
|
|
assert(self->get_priority_fn(self->items[i]) != ULONG_MAX);
|
|
|
|
|
void *temp = self->items[i / 2];
|
|
|
|
@ -72,9 +92,9 @@ static inline int
|
|
|
|
|
priority_queue_find_smallest_child(struct priority_queue *self, int parent_index)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(parent_index >= 1 && parent_index < self->first_free);
|
|
|
|
|
assert(parent_index >= 1 && parent_index <= self->size);
|
|
|
|
|
assert(self->get_priority_fn != NULL);
|
|
|
|
|
assert(LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
|
|
|
|
|
int left_child_index = 2 * parent_index;
|
|
|
|
|
int right_child_index = 2 * parent_index + 1;
|
|
|
|
@ -83,7 +103,7 @@ priority_queue_find_smallest_child(struct priority_queue *self, int parent_index
|
|
|
|
|
int smallest_child_idx;
|
|
|
|
|
|
|
|
|
|
/* If we don't have a right child or the left child is smaller, return it */
|
|
|
|
|
if (right_child_index == self->first_free) {
|
|
|
|
|
if (right_child_index > self->size) {
|
|
|
|
|
smallest_child_idx = left_child_index;
|
|
|
|
|
} else if (self->get_priority_fn(self->items[left_child_index])
|
|
|
|
|
< self->get_priority_fn(self->items[right_child_index])) {
|
|
|
|
@ -106,12 +126,12 @@ priority_queue_percolate_down(struct priority_queue *self, int parent_index)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(self->get_priority_fn != NULL);
|
|
|
|
|
assert(LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
assert(runtime_is_worker());
|
|
|
|
|
assert(!software_interrupt_is_enabled());
|
|
|
|
|
|
|
|
|
|
int left_child_index = 2 * parent_index;
|
|
|
|
|
while (left_child_index >= 2 && left_child_index < self->first_free) {
|
|
|
|
|
while (left_child_index >= 2 && left_child_index <= self->size) {
|
|
|
|
|
int smallest_child_index = priority_queue_find_smallest_child(self, parent_index);
|
|
|
|
|
/* Once the parent is equal to or less than its smallest child, break; */
|
|
|
|
|
if (self->get_priority_fn(self->items[parent_index])
|
|
|
|
@ -125,21 +145,15 @@ priority_queue_percolate_down(struct priority_queue *self, int parent_index)
|
|
|
|
|
parent_index = smallest_child_index;
|
|
|
|
|
left_child_index = 2 * parent_index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks if a priority queue is empty
|
|
|
|
|
* @param self the priority queue to check
|
|
|
|
|
* @returns true if empty, else otherwise
|
|
|
|
|
*/
|
|
|
|
|
static inline bool
|
|
|
|
|
priority_queue_is_empty_locked(struct priority_queue *self)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
assert(!runtime_is_worker() || !software_interrupt_is_enabled());
|
|
|
|
|
|
|
|
|
|
return self->first_free == 1;
|
|
|
|
|
/* Update memoized value if we touched the head */
|
|
|
|
|
if (parent_index == 1) {
|
|
|
|
|
if (!priority_queue_is_empty(self)) {
|
|
|
|
|
self->highest_priority = self->get_priority_fn(self->items[1]);
|
|
|
|
|
} else {
|
|
|
|
|
self->highest_priority = ULONG_MAX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*********************
|
|
|
|
@ -148,24 +162,44 @@ priority_queue_is_empty_locked(struct priority_queue *self)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialized the Priority Queue Data structure
|
|
|
|
|
* @param self the priority_queue to initialize
|
|
|
|
|
* @param capacity the number of elements to store in the data structure
|
|
|
|
|
* @param use_lock indicates that we want a concurrent data structure
|
|
|
|
|
* @param get_priority_fn pointer to a function that returns the priority of an element
|
|
|
|
|
* @return priority queue
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
priority_queue_initialize(struct priority_queue *self, priority_queue_get_priority_fn_t get_priority_fn)
|
|
|
|
|
struct priority_queue *
|
|
|
|
|
priority_queue_initialize(size_t capacity, bool use_lock, priority_queue_get_priority_fn_t get_priority_fn)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(get_priority_fn != NULL);
|
|
|
|
|
assert(!runtime_is_worker() || !software_interrupt_is_enabled());
|
|
|
|
|
|
|
|
|
|
memset(self->items, 0, sizeof(void *) * MAX);
|
|
|
|
|
/* Add one to capacity because this data structure ignores the element at 0 */
|
|
|
|
|
struct priority_queue *self = calloc(sizeof(struct priority_queue) + sizeof(void *) * (capacity + 1), 1);
|
|
|
|
|
|
|
|
|
|
LOCK_INIT(&self->lock);
|
|
|
|
|
self->first_free = 1;
|
|
|
|
|
self->get_priority_fn = get_priority_fn;
|
|
|
|
|
|
|
|
|
|
/* We're assuming a min-heap implementation, so set to larget possible value */
|
|
|
|
|
self->highest_priority = ULONG_MAX;
|
|
|
|
|
self->size = 0;
|
|
|
|
|
self->capacity = capacity;
|
|
|
|
|
self->get_priority_fn = get_priority_fn;
|
|
|
|
|
self->use_lock = use_lock;
|
|
|
|
|
|
|
|
|
|
if (use_lock) LOCK_INIT(&self->lock);
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Free the Priority Queue Data structure
|
|
|
|
|
* @param self the priority_queue to initialize
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
priority_queue_free(struct priority_queue *self)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(!runtime_is_worker() || !software_interrupt_is_enabled());
|
|
|
|
|
|
|
|
|
|
free(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -173,16 +207,27 @@ priority_queue_initialize(struct priority_queue *self, priority_queue_get_priori
|
|
|
|
|
* @returns the number of elements in the priority queue
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_length(struct priority_queue *self)
|
|
|
|
|
priority_queue_length_nolock(struct priority_queue *self)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(runtime_is_worker());
|
|
|
|
|
assert(!software_interrupt_is_enabled());
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
|
|
|
|
|
return self->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param self the priority_queue
|
|
|
|
|
* @returns the number of elements in the priority queue
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_length(struct priority_queue *self)
|
|
|
|
|
{
|
|
|
|
|
LOCK_LOCK(&self->lock);
|
|
|
|
|
int length = self->first_free - 1;
|
|
|
|
|
int size = priority_queue_length_nolock(self);
|
|
|
|
|
LOCK_UNLOCK(&self->lock);
|
|
|
|
|
return length;
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -191,33 +236,42 @@ priority_queue_length(struct priority_queue *self)
|
|
|
|
|
* @returns 0 on success. -ENOSPC on full.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_enqueue(struct priority_queue *self, void *value)
|
|
|
|
|
priority_queue_enqueue_nolock(struct priority_queue *self, void *value)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(value != NULL);
|
|
|
|
|
assert(!runtime_is_worker() || !software_interrupt_is_enabled());
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
LOCK_LOCK(&self->lock);
|
|
|
|
|
|
|
|
|
|
if (priority_queue_append(self, value) == -ENOSPC) goto err_enospc;
|
|
|
|
|
|
|
|
|
|
/* If this is the first element we add, update the highest priority */
|
|
|
|
|
if (self->first_free == 2) {
|
|
|
|
|
self->highest_priority = self->get_priority_fn(value);
|
|
|
|
|
} else {
|
|
|
|
|
priority_queue_percolate_up(self);
|
|
|
|
|
}
|
|
|
|
|
priority_queue_percolate_up(self);
|
|
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
release_lock:
|
|
|
|
|
LOCK_UNLOCK(&self->lock);
|
|
|
|
|
done:
|
|
|
|
|
return rc;
|
|
|
|
|
err_enospc:
|
|
|
|
|
rc = -ENOSPC;
|
|
|
|
|
goto release_lock;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param self - the priority queue we want to add to
|
|
|
|
|
* @param value - the value we want to add
|
|
|
|
|
* @returns 0 on success. -ENOSPC on full.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_enqueue(struct priority_queue *self, void *value)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
LOCK_LOCK(&self->lock);
|
|
|
|
|
rc = priority_queue_enqueue_nolock(self, value);
|
|
|
|
|
LOCK_UNLOCK(&self->lock);
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -226,29 +280,41 @@ err_enospc:
|
|
|
|
|
* @returns 0 on success. -1 on not found
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_delete(struct priority_queue *self, void *value)
|
|
|
|
|
priority_queue_delete_nolock(struct priority_queue *self, void *value)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(value != NULL);
|
|
|
|
|
assert(runtime_is_worker());
|
|
|
|
|
assert(!software_interrupt_is_enabled());
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
|
|
|
|
|
LOCK_LOCK(&self->lock);
|
|
|
|
|
|
|
|
|
|
bool did_delete = false;
|
|
|
|
|
for (int i = 1; i < self->first_free; i++) {
|
|
|
|
|
for (int i = 1; i <= self->size; i++) {
|
|
|
|
|
if (self->items[i] == value) {
|
|
|
|
|
self->items[i] = self->items[--self->first_free];
|
|
|
|
|
self->items[self->first_free] = NULL;
|
|
|
|
|
self->items[i] = self->items[self->size];
|
|
|
|
|
self->items[self->size--] = NULL;
|
|
|
|
|
priority_queue_percolate_down(self, i);
|
|
|
|
|
did_delete = true;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param self - the priority queue we want to delete from
|
|
|
|
|
* @param value - the value we want to delete
|
|
|
|
|
* @returns 0 on success. -1 on not found
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_delete(struct priority_queue *self, void *value)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
LOCK_LOCK(&self->lock);
|
|
|
|
|
rc = priority_queue_delete_nolock(self, value);
|
|
|
|
|
LOCK_UNLOCK(&self->lock);
|
|
|
|
|
|
|
|
|
|
if (!did_delete) return -1;
|
|
|
|
|
return 0;
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -262,6 +328,17 @@ priority_queue_dequeue(struct priority_queue *self, void **dequeued_element)
|
|
|
|
|
return priority_queue_dequeue_if_earlier(self, dequeued_element, UINT64_MAX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param self - the priority queue we want to add to
|
|
|
|
|
* @param dequeued_element a pointer to set to the dequeued element
|
|
|
|
|
* @returns RC 0 if successfully set dequeued_element, -ENOENT if empty
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_dequeue_nolock(struct priority_queue *self, void **dequeued_element)
|
|
|
|
|
{
|
|
|
|
|
return priority_queue_dequeue_if_earlier_nolock(self, dequeued_element, UINT64_MAX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param self - the priority queue we want to add to
|
|
|
|
|
* @param dequeued_element a pointer to set to the dequeued element
|
|
|
|
@ -269,42 +346,57 @@ priority_queue_dequeue(struct priority_queue *self, void **dequeued_element)
|
|
|
|
|
* @returns RC 0 if successfully set dequeued_element, -ENOENT if empty or if none meet target_deadline
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_dequeue_if_earlier(struct priority_queue *self, void **dequeued_element, uint64_t target_deadline)
|
|
|
|
|
priority_queue_dequeue_if_earlier_nolock(struct priority_queue *self, void **dequeued_element, uint64_t target_deadline)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(dequeued_element != NULL);
|
|
|
|
|
assert(self->get_priority_fn != NULL);
|
|
|
|
|
assert(runtime_is_worker());
|
|
|
|
|
assert(!software_interrupt_is_enabled());
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
|
|
|
|
|
int return_code;
|
|
|
|
|
|
|
|
|
|
LOCK_LOCK(&self->lock);
|
|
|
|
|
|
|
|
|
|
/* If the dequeue is not higher priority (earlier timestamp) than targed_deadline, return immediately */
|
|
|
|
|
if (priority_queue_is_empty_locked(self) || self->highest_priority >= target_deadline) goto err_enoent;
|
|
|
|
|
if (priority_queue_is_empty(self) || self->highest_priority >= target_deadline) goto err_enoent;
|
|
|
|
|
|
|
|
|
|
*dequeued_element = self->items[1];
|
|
|
|
|
self->items[1] = self->items[self->size];
|
|
|
|
|
self->items[self->size--] = NULL;
|
|
|
|
|
|
|
|
|
|
*dequeued_element = self->items[1];
|
|
|
|
|
self->items[1] = self->items[--self->first_free];
|
|
|
|
|
self->items[self->first_free] = NULL;
|
|
|
|
|
/* Because of 1-based indices, first_free is 2 when there is only one element */
|
|
|
|
|
if (self->first_free > 2) priority_queue_percolate_down(self, 1);
|
|
|
|
|
if (self->size > 1) priority_queue_percolate_down(self, 1);
|
|
|
|
|
|
|
|
|
|
/* Update the highest priority */
|
|
|
|
|
if (!priority_queue_is_empty_locked(self)) {
|
|
|
|
|
if (!priority_queue_is_empty(self)) {
|
|
|
|
|
self->highest_priority = self->get_priority_fn(self->items[1]);
|
|
|
|
|
} else {
|
|
|
|
|
self->highest_priority = ULONG_MAX;
|
|
|
|
|
}
|
|
|
|
|
return_code = 0;
|
|
|
|
|
|
|
|
|
|
release_lock:
|
|
|
|
|
LOCK_UNLOCK(&self->lock);
|
|
|
|
|
done:
|
|
|
|
|
return return_code;
|
|
|
|
|
err_enoent:
|
|
|
|
|
return_code = -ENOENT;
|
|
|
|
|
goto release_lock;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param self - the priority queue we want to add to
|
|
|
|
|
* @param dequeued_element a pointer to set to the dequeued element
|
|
|
|
|
* @param target_deadline the deadline that the request must be earlier than in order to dequeue
|
|
|
|
|
* @returns RC 0 if successfully set dequeued_element, -ENOENT if empty or if none meet target_deadline
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_dequeue_if_earlier(struct priority_queue *self, void **dequeued_element, uint64_t target_deadline)
|
|
|
|
|
{
|
|
|
|
|
int return_code;
|
|
|
|
|
|
|
|
|
|
LOCK_LOCK(&self->lock);
|
|
|
|
|
return_code = priority_queue_dequeue_if_earlier_nolock(self, dequeued_element, target_deadline);
|
|
|
|
|
LOCK_UNLOCK(&self->lock);
|
|
|
|
|
|
|
|
|
|
return return_code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -314,40 +406,43 @@ err_enoent:
|
|
|
|
|
* @returns RC 0 if successfully set dequeued_element, -ENOENT if empty
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
priority_queue_top(struct priority_queue *self, void **dequeued_element)
|
|
|
|
|
priority_queue_top_nolock(struct priority_queue *self, void **dequeued_element)
|
|
|
|
|
{
|
|
|
|
|
assert(self != NULL);
|
|
|
|
|
assert(dequeued_element != NULL);
|
|
|
|
|
assert(self->get_priority_fn != NULL);
|
|
|
|
|
assert(runtime_is_worker());
|
|
|
|
|
assert(!software_interrupt_is_enabled());
|
|
|
|
|
assert(!self->use_lock || LOCK_IS_LOCKED(&self->lock));
|
|
|
|
|
|
|
|
|
|
int return_code;
|
|
|
|
|
|
|
|
|
|
LOCK_LOCK(&self->lock);
|
|
|
|
|
|
|
|
|
|
if (priority_queue_is_empty_locked(self)) goto err_enoent;
|
|
|
|
|
if (priority_queue_is_empty(self)) goto err_enoent;
|
|
|
|
|
|
|
|
|
|
*dequeued_element = self->items[1];
|
|
|
|
|
return_code = 0;
|
|
|
|
|
|
|
|
|
|
release_lock:
|
|
|
|
|
LOCK_UNLOCK(&self->lock);
|
|
|
|
|
done:
|
|
|
|
|
return return_code;
|
|
|
|
|
err_enoent:
|
|
|
|
|
return_code = -ENOENT;
|
|
|
|
|
goto release_lock;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Peek at the priority of the highest priority task without having to take the lock
|
|
|
|
|
* Because this is a min-heap PQ, the highest priority is the lowest 64-bit integer
|
|
|
|
|
* This is used to store an absolute deadline
|
|
|
|
|
* @returns value of highest priority value in queue or ULONG_MAX if empty
|
|
|
|
|
* Returns the top of the priority queue without removing it
|
|
|
|
|
* @param self - the priority queue we want to add to
|
|
|
|
|
* @param dequeued_element a pointer to set to the top element
|
|
|
|
|
* @returns RC 0 if successfully set dequeued_element, -ENOENT if empty
|
|
|
|
|
*/
|
|
|
|
|
uint64_t
|
|
|
|
|
priority_queue_peek(struct priority_queue *self)
|
|
|
|
|
int
|
|
|
|
|
priority_queue_top(struct priority_queue *self, void **dequeued_element)
|
|
|
|
|
{
|
|
|
|
|
return self->highest_priority;
|
|
|
|
|
int return_code;
|
|
|
|
|
|
|
|
|
|
LOCK_LOCK(&self->lock);
|
|
|
|
|
return_code = priority_queue_top_nolock(self, dequeued_element);
|
|
|
|
|
LOCK_UNLOCK(&self->lock);
|
|
|
|
|
|
|
|
|
|
return return_code;
|
|
|
|
|
}
|
|
|
|
|