You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sledge-serverless-framework/runtime/src/current_sandbox.c

233 lines
6.6 KiB

#include <threads.h>
#include <setjmp.h>
#include <threads.h>
#include "current_sandbox.h"
#include "sandbox_functions.h"
#include "sandbox_set_as_asleep.h"
#include "sandbox_set_as_error.h"
#include "sandbox_set_as_returned.h"
#include "sandbox_set_as_complete.h"
#include "sandbox_set_as_running_user.h"
#include "sandbox_set_as_running_sys.h"
#include "scheduler.h"
#include "http_session.h"
#include "software_interrupt.h"
#include "wasi.h"
extern struct http_session *g_session;
extern struct tenant *g_tenant;
extern int g_client_socket;
extern struct sockaddr *g_client_address;
thread_local struct sandbox *worker_thread_current_sandbox = NULL;
/**
* @brief Switches from an executing sandbox to the worker thread base context
*
* This places the current sandbox on the completion queue if in RETURNED state
*/
void
current_sandbox_sleep()
{
struct sandbox *sleeping_sandbox = current_sandbox_get();
assert(sleeping_sandbox != NULL);
switch (sleeping_sandbox->state) {
case SANDBOX_RUNNING_SYS: {
sandbox_sleep(sleeping_sandbox);
break;
}
default:
panic("Cooperatively switching from a sandbox in a non-terminal %s state\n",
sandbox_state_stringify(sleeping_sandbox->state));
}
scheduler_cooperative_sched(false);
}
/**
* @brief Switches from an executing sandbox to the worker thread base context
*
* This places the current sandbox on the cleanup queue if in RETURNED or RUNNING_SYS state
*/
void
current_sandbox_exit()
{
struct sandbox *exiting_sandbox = current_sandbox_get();
assert(exiting_sandbox != NULL);
switch (exiting_sandbox->state) {
case SANDBOX_RETURNED:
sandbox_exit_success(exiting_sandbox);
break;
case SANDBOX_RUNNING_SYS:
sandbox_exit_error(exiting_sandbox);
break;
default:
panic("Cooperatively switching from a sandbox in a non-terminal %s state\n",
sandbox_state_stringify(exiting_sandbox->state));
}
/* generate a new request and enqueue it to the global queue */
assert(g_tenant != NULL);
struct tenant *tenant = g_tenant;
uint64_t request_arrival_timestamp = __getcycles();
http_total_increment_request();
/* Allocate http session */
//struct http_session *session = http_session_alloc(g_client_socket, (const struct sockaddr *)&g_client_address, tenant, request_arrival_timestamp);
//assert(session != NULL);
//http_session_copy(session, g_session);
struct http_session *session = g_session;
assert(session->route != NULL);
struct sandbox *sandbox = sandbox_alloc(session->route->module, session, session->route, session->tenant, 1);
if (unlikely(sandbox == NULL)) {
printf("Failed to allocate sandbox\n");
exit(-1);
}
/* If the global request scheduler is full, return a 429 to the client */
if (unlikely(global_request_scheduler_add(sandbox) == NULL)) {
printf("Failed to add sandbox to global queue\n");
exit(-1);
}
/****************************end**************************/
scheduler_cooperative_sched(true);
/* The scheduler should never switch back to completed sandboxes */
assert(0);
}
void
current_sandbox_wasm_trap_handler(int trapno)
{
char *error_message = NULL;
struct sandbox *sandbox = current_sandbox_get();
sandbox_syscall(sandbox);
switch (trapno) {
case WASM_TRAP_INVALID_INDEX:
error_message = "WebAssembly Trap: Invalid Index\n";
break;
case WASM_TRAP_MISMATCHED_TYPE:
error_message = "WebAssembly Trap: Mismatched Type\n";
break;
case WASM_TRAP_PROTECTED_CALL_STACK_OVERFLOW:
error_message = "WebAssembly Trap: Protected Call Stack Overflow\n";
break;
case WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY:
error_message = "WebAssembly Trap: Out of Bounds Linear Memory Access\n";
break;
case WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION:
error_message = "WebAssembly Trap: Illegal Arithmetic Operation\n";
break;
case WASM_TRAP_UNREACHABLE:
error_message = "WebAssembly Trap: Unreachable Instruction\n";
break;
default:
error_message = "WebAssembly Trap: Unknown Trapno\n";
break;
}
debuglog("%s", error_message);
current_sandbox_exit();
assert(0);
}
static inline struct sandbox *
current_sandbox_init()
{
struct sandbox *sandbox = current_sandbox_get();
assert(sandbox != NULL);
assert(sandbox->state == SANDBOX_RUNNING_SYS);
int rc = 0;
char *error_message = NULL;
/* Initialize sandbox memory */
struct module *current_module = sandbox_get_module(sandbox);
module_initialize_memory(current_module);
/* Initialize WASI */
wasi_options_t options;
wasi_options_init(&options);
/* Initialize Arguments. First arg is the module name. Subsequent args are query parameters */
char *args[HTTP_MAX_QUERY_PARAM_COUNT + 1];
args[0] = sandbox->module->path;
for (int i = 0; i < sandbox->http->http_request.query_params_count; i++)
args[i + 1] = (char *)sandbox->http->http_request.query_params[i].value;
options.argc = sandbox->http->http_request.query_params_count + 1;
options.argv = (const char **)&args;
sandbox->wasi_context = wasi_context_init(&options);
sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context;
assert(sandbox->wasi_context != NULL);
sandbox_return(sandbox);
/* Initialize sandbox globals. Needs to run in user state */
module_initialize_globals(current_module);
return sandbox;
err:
debuglog("%s", error_message);
current_sandbox_exit();
return NULL;
}
extern noreturn void
current_sandbox_fini()
{
struct sandbox *sandbox = current_sandbox_get();
assert(sandbox != NULL);
char *error_message = "";
sandbox_syscall(sandbox);
sandbox->timestamp_of.completion = __getcycles();
sandbox->total_time = sandbox->timestamp_of.completion - sandbox->timestamp_of.allocation;
assert(sandbox->state == SANDBOX_RUNNING_SYS);
done:
sandbox_set_as_returned(sandbox, SANDBOX_RUNNING_SYS);
/* Cleanup connection and exit sandbox */
current_sandbox_exit();
assert(0);
err:
debuglog("%s", error_message);
assert(sandbox->state == SANDBOX_RUNNING_SYS);
goto done;
}
/**
* Sandbox execution logic
* Handles setup, request parsing, WebAssembly initialization, function execution, response building and
* sending, and cleanup
*/
void
current_sandbox_start(void)
{
struct sandbox *sandbox = current_sandbox_init();
int rc = sigsetjmp(sandbox->ctxt.start_buf, 1);
if (rc == 0) {
struct module *current_module = sandbox_get_module(sandbox);
sandbox->return_value = module_entrypoint(current_module);
} else {
current_sandbox_wasm_trap_handler(rc);
}
current_sandbox_fini();
}