|
|
|
#include "client_socket.h"
|
|
|
|
#include "local_runqueue_list.h"
|
|
|
|
#include "local_runqueue.h"
|
|
|
|
#include "global_request_scheduler.h"
|
|
|
|
|
|
|
|
__thread static struct ps_list_head local_runqueue_list;
|
|
|
|
|
|
|
|
bool
|
|
|
|
local_runqueue_list_is_empty()
|
|
|
|
{
|
|
|
|
return ps_list_head_empty(&local_runqueue_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the sandbox at the head of the thread local runqueue */
|
|
|
|
struct sandbox *
|
|
|
|
local_runqueue_list_get_head()
|
|
|
|
{
|
|
|
|
return ps_list_head_first_d(&local_runqueue_list, struct sandbox);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes the thread from the thread-local runqueue
|
|
|
|
* @param sandbox sandbox
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
local_runqueue_list_remove(struct sandbox *sandbox_to_remove)
|
|
|
|
{
|
|
|
|
ps_list_rem_d(sandbox_to_remove);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sandbox *
|
|
|
|
local_runqueue_list_remove_and_return()
|
|
|
|
{
|
|
|
|
struct sandbox *sandbox_to_remove = ps_list_head_first_d(&local_runqueue_list, struct sandbox);
|
|
|
|
ps_list_rem_d(sandbox_to_remove);
|
|
|
|
return sandbox_to_remove;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute the sandbox at the head of the thread local runqueue
|
|
|
|
* If the runqueue is empty, pull a fresh batch of sandbox requests, instantiate them, and then execute the new head
|
|
|
|
* @return the sandbox to execute or NULL if none are available
|
|
|
|
*/
|
|
|
|
struct sandbox *
|
|
|
|
local_runqueue_list_get_next()
|
|
|
|
{
|
|
|
|
struct sandbox_request *sandbox_request;
|
|
|
|
|
|
|
|
// If our local runqueue is empty, try to pull and allocate a sandbox request from the global request scheduler
|
|
|
|
if (local_runqueue_is_empty()) {
|
|
|
|
if (global_request_scheduler_remove(&sandbox_request) < 0) goto err;
|
|
|
|
|
|
|
|
struct sandbox *sandbox = sandbox_allocate(sandbox_request);
|
|
|
|
if (!sandbox) goto err_allocate;
|
|
|
|
|
|
|
|
sandbox->state = SANDBOX_RUNNABLE;
|
|
|
|
local_runqueue_add(sandbox);
|
|
|
|
|
|
|
|
done:
|
|
|
|
return sandbox;
|
|
|
|
err_allocate:
|
|
|
|
client_socket_send(sandbox_request->socket_descriptor, 503);
|
|
|
|
client_socket_close(sandbox_request->socket_descriptor);
|
|
|
|
free(sandbox_request);
|
|
|
|
err:
|
|
|
|
sandbox = NULL;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Execute Round Robin Scheduling Logic */
|
|
|
|
struct sandbox *next_sandbox = local_runqueue_list_remove_and_return();
|
|
|
|
assert(next_sandbox->state != SANDBOX_RETURNED);
|
|
|
|
local_runqueue_add(next_sandbox);
|
|
|
|
|
|
|
|
return next_sandbox;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Append a sandbox to the runqueue
|
|
|
|
* @returns the appended sandbox
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
local_runqueue_list_append(struct sandbox *sandbox_to_append)
|
|
|
|
{
|
|
|
|
assert(ps_list_singleton_d(sandbox_to_append));
|
|
|
|
ps_list_head_append_d(&local_runqueue_list, sandbox_to_append);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Conditionally checks to see if current sandbox should be preempted.
|
|
|
|
* FIFO doesn't preempt, so just return.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
local_runqueue_list_preempt(ucontext_t *user_context)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
local_runqueue_list_initialize()
|
|
|
|
{
|
|
|
|
ps_list_head_init(&local_runqueue_list);
|
|
|
|
|
|
|
|
/* Register Function Pointers for Abstract Scheduling API */
|
|
|
|
struct local_runqueue_config config = { .add_fn = local_runqueue_list_append,
|
|
|
|
.is_empty_fn = local_runqueue_list_is_empty,
|
|
|
|
.delete_fn = local_runqueue_list_remove,
|
|
|
|
.get_next_fn = local_runqueue_list_get_next,
|
|
|
|
.preempt_fn = local_runqueue_list_preempt };
|
|
|
|
local_runqueue_initialize(&config);
|
|
|
|
};
|