chore: general pq cleanup

main
Sean McBride 4 years ago
parent 6cb442d13d
commit f963828db7

@ -41,5 +41,6 @@ int priority_queue_dequeue(struct priority_queue *self, void **dequeued_ele
int priority_queue_length(struct priority_queue *self); int priority_queue_length(struct priority_queue *self);
uint64_t priority_queue_peek(struct priority_queue *self); uint64_t priority_queue_peek(struct priority_queue *self);
int priority_queue_delete(struct priority_queue *self, void *value); int priority_queue_delete(struct priority_queue *self, void *value);
int priority_queue_top(struct priority_queue *self, void **dequeued_element);
#endif /* PRIORITY_QUEUE_H */ #endif /* PRIORITY_QUEUE_H */

@ -52,7 +52,7 @@ global_request_scheduler_add(struct sandbox_request *sandbox_request)
/** /**
* Removes a sandbox request according to the scheduling policy of the variant * Removes a sandbox request according to the scheduling policy of the variant
* @param removed_sandbox where to write the adddress of the removed sandbox * @param removed_sandbox where to write the adddress of the removed sandbox
* @returns 0 if successful, -1 if empty, -2 if unable to take lock or perform atomic operation * @returns 0 if successfully returned a sandbox request, -ENOENT if empty, -EAGAIN if atomic operation unsuccessful
*/ */
int int
global_request_scheduler_remove(struct sandbox_request **removed_sandbox) global_request_scheduler_remove(struct sandbox_request **removed_sandbox)

@ -28,20 +28,12 @@ global_request_scheduler_deque_add(void *sandbox_request_raw)
* *
* Relevant Read: https://www.dre.vanderbilt.edu/~schmidt/PDF/work-stealing-dequeue.pdf * Relevant Read: https://www.dre.vanderbilt.edu/~schmidt/PDF/work-stealing-dequeue.pdf
* *
* @returns 0 if successfully returned a sandbox request, -1 if empty, -2 if atomic instruction unsuccessful * @returns 0 if successfully returned a sandbox request, -ENOENT if empty, -EAGAIN if atomic instruction unsuccessful
*/ */
static int static int
global_request_scheduler_deque_remove(struct sandbox_request **removed_sandbox_request) global_request_scheduler_deque_remove(struct sandbox_request **removed_sandbox_request)
{ {
int return_code; return deque_steal_sandbox(global_request_scheduler_deque, removed_sandbox_request);
return_code = deque_steal_sandbox(global_request_scheduler_deque, removed_sandbox_request);
/* The Deque uses different return codes other than 0, so map here */
if (return_code == -2) {
return_code = -1;
} else if (return_code == -11) {
return_code = -2;
}
return return_code;
} }
void void

@ -22,13 +22,13 @@ global_request_scheduler_minheap_add(void *sandbox_request)
int return_code = priority_queue_enqueue(&global_request_scheduler_minheap, sandbox_request); int return_code = priority_queue_enqueue(&global_request_scheduler_minheap, sandbox_request);
/* TODO: Propagate -1 to caller */ /* TODO: Propagate -1 to caller */
if (return_code == -1) panic("Request Queue is full\n"); if (return_code == -ENOSPC) panic("Request Queue is full\n");
return sandbox_request; return sandbox_request;
} }
/** /**
* @param pointer to the pointer that we want to set to the address of the removed sandbox request * @param pointer to the pointer that we want to set to the address of the removed sandbox request
* @returns 0 if successful, -1 if empty, -2 if unable to take lock or perform atomic operation * @returns 0 if successful, -ENOENT if empty, -EAGAIN if unable to take lock
*/ */
int int
global_request_scheduler_minheap_remove(struct sandbox_request **removed_sandbox_request) global_request_scheduler_minheap_remove(struct sandbox_request **removed_sandbox_request)

@ -9,7 +9,6 @@
#include "priority_queue.h" #include "priority_queue.h"
#include "software_interrupt.h" #include "software_interrupt.h"
__thread static struct priority_queue local_runqueue_minheap; __thread static struct priority_queue local_runqueue_minheap;
/** /**
@ -34,20 +33,22 @@ local_runqueue_minheap_add(struct sandbox *sandbox)
int return_code = priority_queue_enqueue(&local_runqueue_minheap, sandbox); int return_code = priority_queue_enqueue(&local_runqueue_minheap, sandbox);
/* TODO: propagate RC to caller */ /* TODO: propagate RC to caller */
if (return_code == -1) panic("Thread Runqueue is full!\n"); if (return_code == -ENOSPC) panic("Thread Runqueue is full!\n");
} }
/** /**
* Removes the highest priority sandbox from the run queue * Removes the highest priority sandbox from the run queue
* @param pointer to test to address of removed sandbox if successful * @param pointer to test to address of removed sandbox if successful
* @returns 0 if successful, -1 if empty, -2 if unable to take lock * @returns RC 0 if successfully set dequeued_element, -ENOENT if empty
*/ */
static int static int
local_runqueue_minheap_remove(struct sandbox **to_remove) local_runqueue_minheap_remove(struct sandbox **to_remove)
{ {
assert(!software_interrupt_is_enabled()); assert(!software_interrupt_is_enabled());
int rc = priority_queue_dequeue(&local_runqueue_minheap, (void **)to_remove);
if (rc == -EAGAIN) panic("Worker unexpectedly unable to take lock on own runqueue\n");
return priority_queue_dequeue(&local_runqueue_minheap, (void **)to_remove); return rc;
} }
/** /**
@ -82,18 +83,13 @@ local_runqueue_minheap_get_next()
struct sandbox * sandbox = NULL; struct sandbox * sandbox = NULL;
struct sandbox_request *sandbox_request; struct sandbox_request *sandbox_request;
int sandbox_rc = local_runqueue_minheap_remove(&sandbox); int sandbox_rc = priority_queue_top(&local_runqueue_minheap, (void **)&sandbox);
if (sandbox_rc == 0) {
/* Sandbox ready pulled from local runqueue */
/* TODO: We remove and immediately re-add sandboxes. This seems like extra work. Consider an API to get if (sandbox_rc == -EAGAIN) {
* the min without removing it panic("Worker unexpectedly unable to take lock on own runqueue\n");
*/ } else if (sandbox_rc == -ENOENT) {
local_runqueue_minheap_add(sandbox); /* local runqueue empty, try to pull a sandbox request */
} else if (sandbox_rc == -1) { if (global_request_scheduler_remove(&sandbox_request) < 0) goto done;
/* local runqueue was empty, try to pull a sandbox request and return NULL if we're unable to get one */
if (global_request_scheduler_remove(&sandbox_request) < 0) goto err;
/* Try to allocate a sandbox, returning the request on failure */ /* Try to allocate a sandbox, returning the request on failure */
sandbox = sandbox_allocate(sandbox_request); sandbox = sandbox_allocate(sandbox_request);
@ -101,11 +97,8 @@ local_runqueue_minheap_get_next()
assert(sandbox->state == SANDBOX_INITIALIZED); assert(sandbox->state == SANDBOX_INITIALIZED);
sandbox_set_as_runnable(sandbox, SANDBOX_INITIALIZED); sandbox_set_as_runnable(sandbox, SANDBOX_INITIALIZED);
} else if (sandbox_rc == -2) {
/* Unable to take lock, so just return NULL and try later */
assert(sandbox == NULL);
} }
done: done:
return sandbox; return sandbox;
sandbox_allocate_err: sandbox_allocate_err:

@ -1,4 +1,5 @@
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -15,7 +16,7 @@
* Adds a value to the end of the binary heap * Adds a value to the end of the binary heap
* @param self the priority queue * @param self the priority queue
* @param new_item the value we are adding * @param new_item the value we are adding
* @return 0 on success. -1 when priority queue is full * @return 0 on success. -ENOSPC when priority queue is full
*/ */
static inline int static inline int
priority_queue_append(struct priority_queue *self, void *new_item) priority_queue_append(struct priority_queue *self, void *new_item)
@ -23,7 +24,7 @@ priority_queue_append(struct priority_queue *self, void *new_item)
assert(self != NULL); assert(self != NULL);
assert(ck_spinlock_fas_locked(&self->lock)); assert(ck_spinlock_fas_locked(&self->lock));
if (self->first_free >= MAX) return -1; if (self->first_free >= MAX) return -ENOSPC;
self->items[self->first_free++] = new_item; self->items[self->first_free++] = new_item;
return 0; return 0;
@ -165,7 +166,7 @@ priority_queue_length(struct priority_queue *self)
/** /**
* @param self - the priority queue we want to add to * @param self - the priority queue we want to add to
* @param value - the value we want to add * @param value - the value we want to add
* @returns 0 on success. -1 on full. * @returns 0 on success. -ENOSPC on full.
*/ */
int int
priority_queue_enqueue(struct priority_queue *self, void *value) priority_queue_enqueue(struct priority_queue *self, void *value)
@ -173,7 +174,7 @@ priority_queue_enqueue(struct priority_queue *self, void *value)
assert(self != NULL); assert(self != NULL);
ck_spinlock_fas_lock(&self->lock); ck_spinlock_fas_lock(&self->lock);
if (priority_queue_append(self, value) == -1) return -1; if (priority_queue_append(self, value) == -ENOSPC) return -ENOSPC;
/* If this is the first element we add, update the highest priority */ /* If this is the first element we add, update the highest priority */
if (self->first_free == 2) { if (self->first_free == 2) {
@ -213,7 +214,7 @@ priority_queue_delete(struct priority_queue *self, void *value)
/** /**
* @param self - the priority queue we want to add to * @param self - the priority queue we want to add to
* @param dequeued_element a pointer to set to the dequeued element * @param dequeued_element a pointer to set to the dequeued element
* @returns RC 0 if successfully set dequeued_element, -1 if empty, -2 if unable to take lock * @returns RC 0 if successfully set dequeued_element, -ENOENT if empty, -EAGAIN if unable to take lock
*/ */
int int
priority_queue_dequeue(struct priority_queue *self, void **dequeued_element) priority_queue_dequeue(struct priority_queue *self, void **dequeued_element)
@ -225,12 +226,12 @@ priority_queue_dequeue(struct priority_queue *self, void **dequeued_element)
int return_code; int return_code;
if (ck_spinlock_fas_trylock(&self->lock) == false) { if (ck_spinlock_fas_trylock(&self->lock) == false) {
return_code = -2; return_code = -EAGAIN;
goto done; goto done;
}; };
if (priority_queue_is_empty_locked(self)) { if (priority_queue_is_empty_locked(self)) {
return_code = -1; return_code = -ENOENT;
goto release_lock; goto release_lock;
} }
@ -254,6 +255,40 @@ done:
return return_code; return return_code;
} }
/**
* 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, -EAGAIN if unable to take lock
*/
int
priority_queue_top(struct priority_queue *self, void **dequeued_element)
{
assert(self != NULL);
assert(dequeued_element != NULL);
assert(self->get_priority_fn != NULL);
int return_code;
if (ck_spinlock_fas_trylock(&self->lock) == false) {
return_code = -EAGAIN;
goto done;
};
if (priority_queue_is_empty_locked(self)) {
return_code = -ENOENT;
goto release_lock;
}
*dequeued_element = self->items[1];
return_code = 0;
release_lock:
ck_spinlock_fas_unlock(&self->lock);
done:
return return_code;
}
/** /**
* Peek at the priority of the highest priority task without having to take the lock * 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 * Because this is a min-heap PQ, the highest priority is the lowest 64-bit integer

Loading…
Cancel
Save