diff --git a/runtime/include/sandbox.h b/runtime/include/sandbox.h index 512366f..bd133dc 100644 --- a/runtime/include/sandbox.h +++ b/runtime/include/sandbox.h @@ -325,10 +325,10 @@ sandbox_print_perf(struct sandbox *sandbox) void sandbox_set_as_initialized(struct sandbox *sandbox, struct sandbox_request *sandbox_request, uint64_t allocation_timestamp); -void sandbox_set_as_runnable(struct sandbox *sandbox); -void sandbox_set_as_running(struct sandbox *sandbox); -void sandbox_set_as_blocked(struct sandbox *sandbox); -void sandbox_set_as_preempted(struct sandbox *sandbox); -void sandbox_set_as_returned(struct sandbox *sandbox); -void sandbox_set_as_complete(struct sandbox *sandbox); -void sandbox_set_as_error(struct sandbox *sandbox); +void sandbox_set_as_runnable(struct sandbox *sandbox, sandbox_state_t last_state); +void sandbox_set_as_running(struct sandbox *sandbox, sandbox_state_t last_state); +void sandbox_set_as_blocked(struct sandbox *sandbox, sandbox_state_t last_state); +void sandbox_set_as_preempted(struct sandbox *sandbox, sandbox_state_t last_state); +void sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state); +void sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state); +void sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state); diff --git a/runtime/src/local_runqueue_minheap.c b/runtime/src/local_runqueue_minheap.c index fbba67b..93cdb8c 100644 --- a/runtime/src/local_runqueue_minheap.c +++ b/runtime/src/local_runqueue_minheap.c @@ -93,7 +93,8 @@ local_runqueue_minheap_get_next() sandbox = sandbox_allocate(sandbox_request); 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) { /* 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; /* 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 */ arch_mcontext_save(¤t_sandbox->ctxt, &user_context->uc_mcontext); /* 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 diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 8de18e0..5f6d0d6 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -325,7 +325,10 @@ current_sandbox_main(void) sandbox->response_timestamp = __getcycles(); software_interrupt_disable(); - sandbox_set_as_returned(sandbox); + + assert(sandbox->state == SANDBOX_RUNNING); + sandbox_set_as_returned(sandbox, SANDBOX_RUNNING); + software_interrupt_enable(); done: @@ -339,7 +342,8 @@ done: assert(0); err: fprintf(stderr, "%s", error_message); - sandbox_set_as_error(sandbox); + assert(sandbox->state == SANDBOX_RUNNING); + sandbox_set_as_error(sandbox, SANDBOX_RUNNING); 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->allocation_timestamp = allocation_timestamp; sandbox->last_state_change_timestamp = allocation_timestamp; - sandbox_state_t last_state = sandbox->state; sandbox->state = SANDBOX_SET_AS_INITIALIZED; /* 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 * * @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 -sandbox_set_as_runnable(struct sandbox *sandbox) +sandbox_set_as_runnable(struct sandbox *sandbox, sandbox_state_t last_state) { assert(sandbox); assert(!software_interrupt_is_enabled()); - uint64_t now = __getcycles(); - 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; + uint64_t now = __getcycles(); + uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; + + sandbox->state = SANDBOX_SET_AS_RUNNABLE; debuglog("Sandbox %lu | %s => Runnable\n", sandbox->request_arrival_timestamp, 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 * * @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 -sandbox_set_as_running(struct sandbox *sandbox) +sandbox_set_as_running(struct sandbox *sandbox, sandbox_state_t last_state) { assert(sandbox); assert(!software_interrupt_is_enabled()); - uint64_t now = __getcycles(); - uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; - sandbox_state_t last_state = sandbox->state; + uint64_t now = __getcycles(); + uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; sandbox->state = SANDBOX_SET_AS_RUNNING; 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. * * @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 -sandbox_set_as_preempted(struct sandbox *sandbox) +sandbox_set_as_preempted(struct sandbox *sandbox, sandbox_state_t last_state) { assert(sandbox); assert(!software_interrupt_is_enabled()); - uint64_t now = __getcycles(); - 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; + uint64_t now = __getcycles(); + uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; + + sandbox->state = SANDBOX_SET_AS_PREEMPTED; debuglog("Sandbox %lu | %s => Preempted\n", sandbox->request_arrival_timestamp, 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. * Automatically removes the sandbox from the runqueue * @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 -sandbox_set_as_blocked(struct sandbox *sandbox) +sandbox_set_as_blocked(struct sandbox *sandbox, sandbox_state_t last_state) { assert(sandbox); assert(!software_interrupt_is_enabled()); - uint64_t now = __getcycles(); - 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; + uint64_t now = __getcycles(); + uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; + + sandbox->state = SANDBOX_SET_AS_BLOCKED; debuglog("Sandbox %lu | %s => Blocked\n", sandbox->request_arrival_timestamp, 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. * Because the stack is still in use, freeing the stack is deferred until later * @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 -sandbox_set_as_returned(struct sandbox *sandbox) +sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state) { assert(sandbox); assert(!software_interrupt_is_enabled()); - uint64_t now = __getcycles(); - 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; + uint64_t now = __getcycles(); + uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; + + sandbox->state = SANDBOX_SET_AS_RETURNED; debuglog("Sandbox %lu | %s => Returned\n", sandbox->request_arrival_timestamp, 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? * * @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 -sandbox_set_as_error(struct sandbox *sandbox) +sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state) { assert(sandbox); - uint64_t now = __getcycles(); - uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; - sandbox_state_t last_state = sandbox->state; - sandbox->state = SANDBOX_SET_AS_ERROR; + + uint64_t now = __getcycles(); + uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; + + sandbox->state = SANDBOX_SET_AS_ERROR; debuglog("Sandbox %lu | %s => Error\n", sandbox->request_arrival_timestamp, sandbox_state_stringify(last_state)); @@ -708,6 +723,7 @@ sandbox_set_as_error(struct sandbox *sandbox) } sandbox_free_linear_memory(sandbox); + sandbox->last_state_change_timestamp = now; 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. * Adds the sandbox to the completion queue * @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 -sandbox_set_as_complete(struct sandbox *sandbox) +sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state) { assert(sandbox); - uint64_t now = __getcycles(); - 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; + uint64_t now = __getcycles(); + uint64_t duration_of_last_state = now - sandbox->last_state_change_timestamp; + + sandbox->state = SANDBOX_SET_AS_COMPLETE; debuglog("Sandbox %lu | %s => Complete\n", sandbox->request_arrival_timestamp, sandbox_state_stringify(last_state)); @@ -802,7 +820,7 @@ err_stack_allocation_failed: sandbox->state = SANDBOX_SET_AS_INITIALIZED; sandbox->last_state_change_timestamp = now; ps_list_init_d(sandbox); - sandbox_set_as_error(sandbox); + sandbox_set_as_error(sandbox, SANDBOX_SET_AS_INITIALIZED); err_memory_allocation_failed: err: perror(error_message); diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index 7d08e67..50bd5c2 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -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 * completion queue */ - sandbox_set_as_complete(exiting_sandbox); + sandbox_set_as_complete(exiting_sandbox, SANDBOX_RETURNED); break; case SANDBOX_ERROR: /* Terminal State, so just break */ @@ -80,7 +80,7 @@ worker_thread_switch_to_sandbox(struct sandbox *next_sandbox) if (current_sandbox == NULL) { /* 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", 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); - sandbox_set_as_running(next_sandbox); + sandbox_set_as_running(next_sandbox, next_sandbox->state); struct arch_context *current_context = ¤t_sandbox->ctxt; @@ -145,7 +145,7 @@ worker_thread_wakeup_sandbox(struct sandbox *sandbox) assert(sandbox->state == SANDBOX_BLOCKED); software_interrupt_disable(); - sandbox_set_as_runnable(sandbox); + sandbox_set_as_runnable(sandbox, SANDBOX_BLOCKED); 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 */ 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); /* Switch to the next sandbox */