feat: constant propagation state transitions

master
Sean McBride 5 years ago
parent 3bf9cc806a
commit b315844c46

@ -325,10 +325,10 @@ sandbox_print_perf(struct sandbox *sandbox)
void sandbox_set_as_initialized(struct sandbox *sandbox, struct sandbox_request *sandbox_request, void sandbox_set_as_initialized(struct sandbox *sandbox, struct sandbox_request *sandbox_request,
uint64_t allocation_timestamp); uint64_t allocation_timestamp);
void sandbox_set_as_runnable(struct sandbox *sandbox); void sandbox_set_as_runnable(struct sandbox *sandbox, sandbox_state_t last_state);
void sandbox_set_as_running(struct sandbox *sandbox); void sandbox_set_as_running(struct sandbox *sandbox, sandbox_state_t last_state);
void sandbox_set_as_blocked(struct sandbox *sandbox); void sandbox_set_as_blocked(struct sandbox *sandbox, sandbox_state_t last_state);
void sandbox_set_as_preempted(struct sandbox *sandbox); void sandbox_set_as_preempted(struct sandbox *sandbox, sandbox_state_t last_state);
void sandbox_set_as_returned(struct sandbox *sandbox); void sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state);
void sandbox_set_as_complete(struct sandbox *sandbox); void sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state);
void sandbox_set_as_error(struct sandbox *sandbox); void sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state);

@ -93,7 +93,8 @@ local_runqueue_minheap_get_next()
sandbox = sandbox_allocate(sandbox_request); sandbox = sandbox_allocate(sandbox_request);
if (!sandbox) goto sandbox_allocate_err; if (!sandbox) goto sandbox_allocate_err;
sandbox_set_as_runnable(sandbox); assert(sandbox->state == SANDBOX_INITIALIZED);
sandbox_set_as_runnable(sandbox, SANDBOX_INITIALIZED);
} else if (sandbox_rc == -2) { } else if (sandbox_rc == -2) {
/* Unable to take lock, so just return NULL and try later */ /* Unable to take lock, so just return NULL and try later */
@ -157,14 +158,18 @@ local_runqueue_minheap_preempt(ucontext_t *user_context)
if (!next_sandbox) goto err_sandbox_allocate; if (!next_sandbox) goto err_sandbox_allocate;
/* Set as runnable and add it to the runqueue */ /* Set as runnable and add it to the runqueue */
sandbox_set_as_runnable(next_sandbox); assert(next_sandbox->state == SANDBOX_INITIALIZED);
sandbox_set_as_runnable(next_sandbox, SANDBOX_INITIALIZED);
assert(current_sandbox->state == SANDBOX_RUNNING);
sandbox_set_as_preempted(current_sandbox, SANDBOX_RUNNING);
sandbox_set_as_preempted(current_sandbox);
/* Save the context of the currently executing sandbox before switching from it */ /* Save the context of the currently executing sandbox before switching from it */
arch_mcontext_save(&current_sandbox->ctxt, &user_context->uc_mcontext); arch_mcontext_save(&current_sandbox->ctxt, &user_context->uc_mcontext);
/* Update current_sandbox to the next sandbox */ /* Update current_sandbox to the next sandbox */
sandbox_set_as_running(next_sandbox); assert(next_sandbox->state == SANDBOX_RUNNABLE);
sandbox_set_as_running(next_sandbox, SANDBOX_RUNNABLE);
/* /*
* Restore the context of this new sandbox * Restore the context of this new sandbox

@ -325,7 +325,10 @@ current_sandbox_main(void)
sandbox->response_timestamp = __getcycles(); sandbox->response_timestamp = __getcycles();
software_interrupt_disable(); software_interrupt_disable();
sandbox_set_as_returned(sandbox);
assert(sandbox->state == SANDBOX_RUNNING);
sandbox_set_as_returned(sandbox, SANDBOX_RUNNING);
software_interrupt_enable(); software_interrupt_enable();
done: done:
@ -339,7 +342,8 @@ done:
assert(0); assert(0);
err: err:
fprintf(stderr, "%s", error_message); fprintf(stderr, "%s", error_message);
sandbox_set_as_error(sandbox); assert(sandbox->state == SANDBOX_RUNNING);
sandbox_set_as_error(sandbox, SANDBOX_RUNNING);
goto done; goto done;
} }
@ -451,7 +455,6 @@ sandbox_set_as_initialized(struct sandbox *sandbox, struct sandbox_request *sand
sandbox->request_arrival_timestamp = sandbox_request->request_arrival_timestamp; sandbox->request_arrival_timestamp = sandbox_request->request_arrival_timestamp;
sandbox->allocation_timestamp = allocation_timestamp; sandbox->allocation_timestamp = allocation_timestamp;
sandbox->last_state_change_timestamp = allocation_timestamp; sandbox->last_state_change_timestamp = allocation_timestamp;
sandbox_state_t last_state = sandbox->state;
sandbox->state = SANDBOX_SET_AS_INITIALIZED; sandbox->state = SANDBOX_SET_AS_INITIALIZED;
/* Initialize the sandbox's context, stack, and instruction pointer */ /* Initialize the sandbox's context, stack, and instruction pointer */
@ -481,17 +484,19 @@ sandbox_set_as_initialized(struct sandbox *sandbox, struct sandbox_request *sand
* - A sandbox in the SANDBOX_BLOCKED state completes what was blocking it and is ready to be run * - A sandbox in the SANDBOX_BLOCKED state completes what was blocking it and is ready to be run
* *
* @param sandbox * @param sandbox
* @param last_state the state the sandbox is transitioning from. This is expressed as a constant to
* enable the compiler to perform constant propagation optimizations.
*/ */
void void
sandbox_set_as_runnable(struct sandbox *sandbox) sandbox_set_as_runnable(struct sandbox *sandbox, sandbox_state_t last_state)
{ {
assert(sandbox); assert(sandbox);
assert(!software_interrupt_is_enabled()); assert(!software_interrupt_is_enabled());
uint64_t now = __getcycles(); uint64_t now = __getcycles();
uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp;
sandbox_state_t last_state = sandbox->state;
sandbox->state = SANDBOX_SET_AS_RUNNABLE; sandbox->state = SANDBOX_SET_AS_RUNNABLE;
debuglog("Sandbox %lu | %s => Runnable\n", sandbox->request_arrival_timestamp, debuglog("Sandbox %lu | %s => Runnable\n", sandbox->request_arrival_timestamp,
sandbox_state_stringify(last_state)); sandbox_state_stringify(last_state));
@ -525,16 +530,17 @@ sandbox_set_as_runnable(struct sandbox *sandbox)
* - A sandbox in the PREEMPTED state is now the highest priority work to execute * - A sandbox in the PREEMPTED state is now the highest priority work to execute
* *
* @param sandbox * @param sandbox
* @param last_state the state the sandbox is transitioning from. This is expressed as a constant to
* enable the compiler to perform constant propagation optimizations.
*/ */
void void
sandbox_set_as_running(struct sandbox *sandbox) sandbox_set_as_running(struct sandbox *sandbox, sandbox_state_t last_state)
{ {
assert(sandbox); assert(sandbox);
assert(!software_interrupt_is_enabled()); assert(!software_interrupt_is_enabled());
uint64_t now = __getcycles(); uint64_t now = __getcycles();
uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp;
sandbox_state_t last_state = sandbox->state;
sandbox->state = SANDBOX_SET_AS_RUNNING; sandbox->state = SANDBOX_SET_AS_RUNNING;
debuglog("Sandbox %lu | %s => Running\n", sandbox->request_arrival_timestamp, debuglog("Sandbox %lu | %s => Running\n", sandbox->request_arrival_timestamp,
@ -567,17 +573,19 @@ sandbox_set_as_running(struct sandbox *sandbox)
* and pulls a sandbox with an earlier absolute deadline from the global request scheduler. * and pulls a sandbox with an earlier absolute deadline from the global request scheduler.
* *
* @param sandbox the sandbox being preempted * @param sandbox the sandbox being preempted
* @param last_state the state the sandbox is transitioning from. This is expressed as a constant to
* enable the compiler to perform constant propagation optimizations.
*/ */
void void
sandbox_set_as_preempted(struct sandbox *sandbox) sandbox_set_as_preempted(struct sandbox *sandbox, sandbox_state_t last_state)
{ {
assert(sandbox); assert(sandbox);
assert(!software_interrupt_is_enabled()); assert(!software_interrupt_is_enabled());
uint64_t now = __getcycles(); uint64_t now = __getcycles();
uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp;
sandbox_state_t last_state = sandbox->state;
sandbox->state = SANDBOX_SET_AS_PREEMPTED; sandbox->state = SANDBOX_SET_AS_PREEMPTED;
debuglog("Sandbox %lu | %s => Preempted\n", sandbox->request_arrival_timestamp, debuglog("Sandbox %lu | %s => Preempted\n", sandbox->request_arrival_timestamp,
sandbox_state_stringify(last_state)); sandbox_state_stringify(last_state));
@ -601,17 +609,19 @@ sandbox_set_as_preempted(struct sandbox *sandbox)
* This occurs when a sandbox is executing and it makes a blocking API call of some kind. * This occurs when a sandbox is executing and it makes a blocking API call of some kind.
* Automatically removes the sandbox from the runqueue * Automatically removes the sandbox from the runqueue
* @param sandbox the blocking sandbox * @param sandbox the blocking sandbox
* @param last_state the state the sandbox is transitioning from. This is expressed as a constant to
* enable the compiler to perform constant propagation optimizations.
*/ */
void void
sandbox_set_as_blocked(struct sandbox *sandbox) sandbox_set_as_blocked(struct sandbox *sandbox, sandbox_state_t last_state)
{ {
assert(sandbox); assert(sandbox);
assert(!software_interrupt_is_enabled()); assert(!software_interrupt_is_enabled());
uint64_t now = __getcycles(); uint64_t now = __getcycles();
uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp;
sandbox_state_t last_state = sandbox->state;
sandbox->state = SANDBOX_SET_AS_BLOCKED; sandbox->state = SANDBOX_SET_AS_BLOCKED;
debuglog("Sandbox %lu | %s => Blocked\n", sandbox->request_arrival_timestamp, debuglog("Sandbox %lu | %s => Blocked\n", sandbox->request_arrival_timestamp,
sandbox_state_stringify(last_state)); sandbox_state_stringify(last_state));
@ -637,17 +647,19 @@ sandbox_set_as_blocked(struct sandbox *sandbox)
* Automatically removes the sandbox from the runqueue and unmaps linear memory. * Automatically removes the sandbox from the runqueue and unmaps linear memory.
* Because the stack is still in use, freeing the stack is deferred until later * Because the stack is still in use, freeing the stack is deferred until later
* @param sandbox the blocking sandbox * @param sandbox the blocking sandbox
* @param last_state the state the sandbox is transitioning from. This is expressed as a constant to
* enable the compiler to perform constant propagation optimizations.
*/ */
void void
sandbox_set_as_returned(struct sandbox *sandbox) sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state)
{ {
assert(sandbox); assert(sandbox);
assert(!software_interrupt_is_enabled()); assert(!software_interrupt_is_enabled());
uint64_t now = __getcycles(); uint64_t now = __getcycles();
uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp;
sandbox_state_t last_state = sandbox->state;
sandbox->state = SANDBOX_SET_AS_RETURNED; sandbox->state = SANDBOX_SET_AS_RETURNED;
debuglog("Sandbox %lu | %s => Returned\n", sandbox->request_arrival_timestamp, debuglog("Sandbox %lu | %s => Returned\n", sandbox->request_arrival_timestamp,
sandbox_state_stringify(last_state)); sandbox_state_stringify(last_state));
@ -679,15 +691,18 @@ sandbox_set_as_returned(struct sandbox *sandbox)
* TODO: Is the sandbox adding itself to the completion queue here? Is this a problem? * TODO: Is the sandbox adding itself to the completion queue here? Is this a problem?
* *
* @param sandbox the sandbox erroring out * @param sandbox the sandbox erroring out
* @param last_state the state the sandbox is transitioning from. This is expressed as a constant to
* enable the compiler to perform constant propagation optimizations.
*/ */
void void
sandbox_set_as_error(struct sandbox *sandbox) sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state)
{ {
assert(sandbox); assert(sandbox);
uint64_t now = __getcycles();
uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; uint64_t now = __getcycles();
sandbox_state_t last_state = sandbox->state; uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp;
sandbox->state = SANDBOX_SET_AS_ERROR;
sandbox->state = SANDBOX_SET_AS_ERROR;
debuglog("Sandbox %lu | %s => Error\n", sandbox->request_arrival_timestamp, debuglog("Sandbox %lu | %s => Error\n", sandbox->request_arrival_timestamp,
sandbox_state_stringify(last_state)); sandbox_state_stringify(last_state));
@ -708,6 +723,7 @@ sandbox_set_as_error(struct sandbox *sandbox)
} }
sandbox_free_linear_memory(sandbox); sandbox_free_linear_memory(sandbox);
sandbox->last_state_change_timestamp = now; sandbox->last_state_change_timestamp = now;
sandbox->state = SANDBOX_ERROR; sandbox->state = SANDBOX_ERROR;
@ -721,15 +737,17 @@ sandbox_set_as_error(struct sandbox *sandbox)
* Transitions a sandbox from the SANDBOX_RETURNED state to the SANDBOX_COMPLETE state. * Transitions a sandbox from the SANDBOX_RETURNED state to the SANDBOX_COMPLETE state.
* Adds the sandbox to the completion queue * Adds the sandbox to the completion queue
* @param sandbox * @param sandbox
* @param last_state the state the sandbox is transitioning from. This is expressed as a constant to
* enable the compiler to perform constant propagation optimizations.
*/ */
void void
sandbox_set_as_complete(struct sandbox *sandbox) sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state)
{ {
assert(sandbox); assert(sandbox);
uint64_t now = __getcycles(); uint64_t now = __getcycles();
uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp;
sandbox_state_t last_state = sandbox->state;
sandbox->state = SANDBOX_SET_AS_COMPLETE; sandbox->state = SANDBOX_SET_AS_COMPLETE;
debuglog("Sandbox %lu | %s => Complete\n", sandbox->request_arrival_timestamp, debuglog("Sandbox %lu | %s => Complete\n", sandbox->request_arrival_timestamp,
sandbox_state_stringify(last_state)); sandbox_state_stringify(last_state));
@ -802,7 +820,7 @@ err_stack_allocation_failed:
sandbox->state = SANDBOX_SET_AS_INITIALIZED; sandbox->state = SANDBOX_SET_AS_INITIALIZED;
sandbox->last_state_change_timestamp = now; sandbox->last_state_change_timestamp = now;
ps_list_init_d(sandbox); ps_list_init_d(sandbox);
sandbox_set_as_error(sandbox); sandbox_set_as_error(sandbox, SANDBOX_SET_AS_INITIALIZED);
err_memory_allocation_failed: err_memory_allocation_failed:
err: err:
perror(error_message); perror(error_message);

@ -48,7 +48,7 @@ worker_thread_transition_exiting_sandbox(struct sandbox *exiting_sandbox)
* We draw a distinction between RETURNED and COMPLETED because a sandbox cannot add itself to the * We draw a distinction between RETURNED and COMPLETED because a sandbox cannot add itself to the
* completion queue * completion queue
*/ */
sandbox_set_as_complete(exiting_sandbox); sandbox_set_as_complete(exiting_sandbox, SANDBOX_RETURNED);
break; break;
case SANDBOX_ERROR: case SANDBOX_ERROR:
/* Terminal State, so just break */ /* Terminal State, so just break */
@ -80,7 +80,7 @@ worker_thread_switch_to_sandbox(struct sandbox *next_sandbox)
if (current_sandbox == NULL) { if (current_sandbox == NULL) {
/* Switching from "Base Context" */ /* Switching from "Base Context" */
sandbox_set_as_running(next_sandbox); sandbox_set_as_running(next_sandbox, next_sandbox->state);
debuglog("Base Context (%s) > Sandbox %lu (%s)\n", debuglog("Base Context (%s) > Sandbox %lu (%s)\n",
arch_context_variant_print(worker_thread_base_context.variant), arch_context_variant_print(worker_thread_base_context.variant),
@ -93,7 +93,7 @@ worker_thread_switch_to_sandbox(struct sandbox *next_sandbox)
worker_thread_transition_exiting_sandbox(current_sandbox); worker_thread_transition_exiting_sandbox(current_sandbox);
sandbox_set_as_running(next_sandbox); sandbox_set_as_running(next_sandbox, next_sandbox->state);
struct arch_context *current_context = &current_sandbox->ctxt; struct arch_context *current_context = &current_sandbox->ctxt;
@ -145,7 +145,7 @@ worker_thread_wakeup_sandbox(struct sandbox *sandbox)
assert(sandbox->state == SANDBOX_BLOCKED); assert(sandbox->state == SANDBOX_BLOCKED);
software_interrupt_disable(); software_interrupt_disable();
sandbox_set_as_runnable(sandbox); sandbox_set_as_runnable(sandbox, SANDBOX_BLOCKED);
software_interrupt_enable(); software_interrupt_enable();
} }
@ -162,7 +162,10 @@ worker_thread_block_current_sandbox(void)
/* 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 */
struct sandbox *current_sandbox = current_sandbox_get(); struct sandbox *current_sandbox = current_sandbox_get();
sandbox_set_as_blocked(current_sandbox);
assert(current_sandbox->state == SANDBOX_RUNNING);
sandbox_set_as_blocked(current_sandbox, SANDBOX_RUNNING);
current_sandbox_set(NULL); current_sandbox_set(NULL);
/* Switch to the next sandbox */ /* Switch to the next sandbox */

Loading…
Cancel
Save