|
|
@ -30,7 +30,7 @@ __thread struct arch_context worker_thread_base_context;
|
|
|
|
__thread uv_loop_t worker_thread_uvio_handle;
|
|
|
|
__thread uv_loop_t worker_thread_uvio_handle;
|
|
|
|
|
|
|
|
|
|
|
|
/* Flag to signify if the thread is currently running callbacks in the libuv event loop */
|
|
|
|
/* Flag to signify if the thread is currently running callbacks in the libuv event loop */
|
|
|
|
static __thread bool worker_thread_is_in_callback;
|
|
|
|
static __thread bool worker_thread_is_in_libuv_event_loop = false;
|
|
|
|
|
|
|
|
|
|
|
|
/***********************
|
|
|
|
/***********************
|
|
|
|
* Worker Thread Logic *
|
|
|
|
* Worker Thread Logic *
|
|
|
@ -84,8 +84,10 @@ worker_thread_switch_to_sandbox(struct sandbox *next_sandbox)
|
|
|
|
void
|
|
|
|
void
|
|
|
|
worker_thread_wakeup_sandbox(struct sandbox *sandbox)
|
|
|
|
worker_thread_wakeup_sandbox(struct sandbox *sandbox)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
assert(sandbox != NULL);
|
|
|
|
|
|
|
|
assert(sandbox->state == SANDBOX_BLOCKED);
|
|
|
|
|
|
|
|
|
|
|
|
software_interrupt_disable();
|
|
|
|
software_interrupt_disable();
|
|
|
|
if (sandbox->state != SANDBOX_BLOCKED) goto done;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sandbox->state = SANDBOX_RUNNABLE;
|
|
|
|
sandbox->state = SANDBOX_RUNNABLE;
|
|
|
|
debuglog("Marking blocked sandbox as runnable\n");
|
|
|
|
debuglog("Marking blocked sandbox as runnable\n");
|
|
|
@ -103,7 +105,7 @@ done:
|
|
|
|
void
|
|
|
|
void
|
|
|
|
worker_thread_block_current_sandbox(void)
|
|
|
|
worker_thread_block_current_sandbox(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(worker_thread_is_in_callback == false);
|
|
|
|
assert(worker_thread_is_in_libuv_event_loop == false);
|
|
|
|
software_interrupt_disable();
|
|
|
|
software_interrupt_disable();
|
|
|
|
|
|
|
|
|
|
|
|
/* Remove the sandbox we were just executing from the runqueue and mark as blocked */
|
|
|
|
/* Remove the sandbox we were just executing from the runqueue and mark as blocked */
|
|
|
@ -145,13 +147,12 @@ worker_thread_process_io(void)
|
|
|
|
* sigreturn. To get to sigreturn, we need to send ourselves a signal, then update the registers we should return to,
|
|
|
|
* sigreturn. To get to sigreturn, we need to send ourselves a signal, then update the registers we should return to,
|
|
|
|
* then sigreturn (by returning from the handler).
|
|
|
|
* then sigreturn (by returning from the handler).
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
void __attribute__((noinline)) __attribute__((noreturn)) worker_thread_sandbox_switch_preempt(void)
|
|
|
|
void __attribute__((noinline)) __attribute__((noreturn)) worker_thread_mcontext_restore(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
debuglog("Thread %lu | Signaling SIGUSR1 on self to initiate mcontext restore...\n", pthread_self());
|
|
|
|
pthread_kill(pthread_self(), SIGUSR1);
|
|
|
|
pthread_kill(pthread_self(), SIGUSR1);
|
|
|
|
|
|
|
|
|
|
|
|
assert(false); /* should not get here.. */
|
|
|
|
assert(false); /* should not get here.. */
|
|
|
|
while (true)
|
|
|
|
|
|
|
|
;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -160,13 +161,13 @@ void __attribute__((noinline)) __attribute__((noreturn)) worker_thread_sandbox_s
|
|
|
|
void
|
|
|
|
void
|
|
|
|
worker_thread_execute_libuv_event_loop(void)
|
|
|
|
worker_thread_execute_libuv_event_loop(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
worker_thread_is_in_callback = true;
|
|
|
|
worker_thread_is_in_libuv_event_loop = true;
|
|
|
|
int n = uv_run(worker_thread_get_libuv_handle(), UV_RUN_NOWAIT), i = 0;
|
|
|
|
int n = uv_run(worker_thread_get_libuv_handle(), UV_RUN_NOWAIT), i = 0;
|
|
|
|
while (n > 0) {
|
|
|
|
while (n > 0) {
|
|
|
|
n--;
|
|
|
|
n--;
|
|
|
|
uv_run(worker_thread_get_libuv_handle(), UV_RUN_NOWAIT);
|
|
|
|
uv_run(worker_thread_get_libuv_handle(), UV_RUN_NOWAIT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
worker_thread_is_in_callback = false;
|
|
|
|
worker_thread_is_in_libuv_event_loop = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -177,27 +178,40 @@ worker_thread_execute_libuv_event_loop(void)
|
|
|
|
void *
|
|
|
|
void *
|
|
|
|
worker_thread_main(void *return_code)
|
|
|
|
worker_thread_main(void *return_code)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* Initialize Worker Infrastructure */
|
|
|
|
/* Initialize Base Context */
|
|
|
|
arch_context_init(&worker_thread_base_context, 0, 0);
|
|
|
|
arch_context_init(&worker_thread_base_context, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialize Runqueue Variant */
|
|
|
|
// local_runqueue_list_initialize();
|
|
|
|
// local_runqueue_list_initialize();
|
|
|
|
local_runqueue_minheap_initialize();
|
|
|
|
local_runqueue_minheap_initialize();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialize Completion Queue */
|
|
|
|
local_completion_queue_initialize();
|
|
|
|
local_completion_queue_initialize();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialize Flags */
|
|
|
|
software_interrupt_is_disabled = false;
|
|
|
|
software_interrupt_is_disabled = false;
|
|
|
|
|
|
|
|
worker_thread_is_in_libuv_event_loop = false;
|
|
|
|
worker_thread_next_context = NULL;
|
|
|
|
worker_thread_next_context = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Unmask signals */
|
|
|
|
#ifndef PREEMPT_DISABLE
|
|
|
|
#ifndef PREEMPT_DISABLE
|
|
|
|
software_interrupt_unmask_signal(SIGALRM);
|
|
|
|
software_interrupt_unmask_signal(SIGALRM);
|
|
|
|
software_interrupt_unmask_signal(SIGUSR1);
|
|
|
|
software_interrupt_unmask_signal(SIGUSR1);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialize libuv event loop handle */
|
|
|
|
uv_loop_init(&worker_thread_uvio_handle);
|
|
|
|
uv_loop_init(&worker_thread_uvio_handle);
|
|
|
|
worker_thread_is_in_callback = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Begin Worker Execution Loop */
|
|
|
|
/* Begin Worker Execution Loop */
|
|
|
|
struct sandbox *next_sandbox;
|
|
|
|
struct sandbox *next_sandbox;
|
|
|
|
while (true) {
|
|
|
|
while (true) {
|
|
|
|
|
|
|
|
/* Assumption: current_sandbox should be unset at start of loop */
|
|
|
|
assert(current_sandbox_get() == NULL);
|
|
|
|
assert(current_sandbox_get() == NULL);
|
|
|
|
/* If "in a callback", the libuv event loop is triggering this, so we don't need to start it */
|
|
|
|
|
|
|
|
if (!worker_thread_is_in_callback) worker_thread_execute_libuv_event_loop();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Execute libuv event loop */
|
|
|
|
|
|
|
|
if (!worker_thread_is_in_libuv_event_loop) worker_thread_execute_libuv_event_loop();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Switch to a sandbox if one is ready to run */
|
|
|
|
software_interrupt_disable();
|
|
|
|
software_interrupt_disable();
|
|
|
|
next_sandbox = local_runqueue_get_next();
|
|
|
|
next_sandbox = local_runqueue_get_next();
|
|
|
|
if (next_sandbox != NULL) {
|
|
|
|
if (next_sandbox != NULL) {
|
|
|
@ -206,6 +220,7 @@ worker_thread_main(void *return_code)
|
|
|
|
software_interrupt_enable();
|
|
|
|
software_interrupt_enable();
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Clear the completion queue */
|
|
|
|
local_completion_queue_free();
|
|
|
|
local_completion_queue_free();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -215,10 +230,10 @@ worker_thread_main(void *return_code)
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Called when the function in the sandbox exits
|
|
|
|
* Called when the function in the sandbox exits
|
|
|
|
* Removes the standbox from the thread-local runqueue, sets its state to SANDBOX_RETURNED,
|
|
|
|
* Removes the standbox from the thread-local runqueue, sets its state to SANDBOX_RETURNED,
|
|
|
|
* releases the linear memory, and then switches to the sandbox at the head of the runqueue
|
|
|
|
* releases the linear memory, and then returns to the base context
|
|
|
|
* TODO: Consider moving this to a future current_sandbox file. This has thus far proven difficult to move
|
|
|
|
* TODO: Consider moving this to a future current_sandbox file. This has thus far proven difficult to move
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
__attribute__((noreturn)) void
|
|
|
|
worker_thread_on_sandbox_exit(struct sandbox *exiting_sandbox)
|
|
|
|
worker_thread_on_sandbox_exit(struct sandbox *exiting_sandbox)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(exiting_sandbox);
|
|
|
|
assert(exiting_sandbox);
|
|
|
@ -237,4 +252,6 @@ worker_thread_on_sandbox_exit(struct sandbox *exiting_sandbox)
|
|
|
|
|
|
|
|
|
|
|
|
/* This should force return to main event loop */
|
|
|
|
/* This should force return to main event loop */
|
|
|
|
worker_thread_switch_to_sandbox(NULL);
|
|
|
|
worker_thread_switch_to_sandbox(NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|