diff options
author | Andrew Clayton <a.clayton@nginx.com> | 2023-10-10 20:54:39 +0100 |
---|---|---|
committer | Andrew Clayton <a.clayton@nginx.com> | 2023-10-10 20:54:39 +0100 |
commit | 8f6449f4e0152d9644b807cf2208e3734a0f8b4d (patch) | |
tree | 266081fadb3ca5131e22452e315f6a6dd544d32e | |
parent | 01d185cb52af8879aeeab04765eff439feec664c (diff) | |
download | unit-wasm.tar.gz unit-wasm.tar.bz2 |
[WIP] Wasm: Add a WAMR based language modulewasm
Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
-rw-r--r-- | auto/modules/wasm | 21 | ||||
-rw-r--r-- | src/wasm/nxt_rt_wamr.c | 338 | ||||
-rw-r--r-- | src/wasm/nxt_wasm.c | 1 | ||||
-rw-r--r-- | src/wasm/nxt_wasm.h | 9 |
4 files changed, 366 insertions, 3 deletions
diff --git a/auto/modules/wasm b/auto/modules/wasm index 1f388de6..17648b5f 100644 --- a/auto/modules/wasm +++ b/auto/modules/wasm @@ -62,6 +62,8 @@ NXT_WASM_LIB_PATH=${NXT_WASM_LIB_PATH=} NXT_WASM_LDFLAGS= if [ "$NXT_WASM_RUNTIME" = "wasmtime" ]; then NXT_WASM_LDFLAGS=-lwasmtime +elif [ "$NXT_WASM_RUNTIME" = "wamr" ]; then + NXT_WASM_LDFLAGS="-lvmlib -lm" fi NXT_WASM_ADDITIONAL_FLAGS="-fno-strict-aliasing \ -Wno-missing-field-initializers \ @@ -111,10 +113,25 @@ if [ "$NXT_WASM_RUNTIME" = "wasmtime" ]; then return 0; }" +elif [ "$NXT_WASM_RUNTIME" = "wamr" ]; then + nxt_feature="wamr" + nxt_feature_name="" + nxt_feature_run=no + nxt_feature_incs="-I${NXT_WASM_INCLUDE_PATH}" + nxt_feature_libs="-L${NXT_WASM_LIB_PATH} $NXT_WASM_LDFLAGS" + nxt_feature_test=" + #include <wasm_export.h> - . auto/feature + int main(void) { + if (!wasm_runtime_init()) + return 1; + + return 0; + }" fi +. auto/feature + if [ $nxt_found = no ]; then $echo $echo $0: error: no $NXT_WASM_RUNTIME found. @@ -143,6 +160,8 @@ NXT_WASM_MODULE_SRCS=" \ if [ "$NXT_WASM_RUNTIME" = "wasmtime" ]; then NXT_WASM_MODULE_SRCS="$NXT_WASM_MODULE_SRCS src/wasm/nxt_rt_wasmtime.c" +elif [ "$NXT_WASM_RUNTIME" = "wamr" ]; then + NXT_WASM_MODULE_SRCS="$NXT_WASM_MODULE_SRCS src/wasm/nxt_rt_wamr.c" fi diff --git a/src/wasm/nxt_rt_wamr.c b/src/wasm/nxt_rt_wamr.c new file mode 100644 index 00000000..d33965ba --- /dev/null +++ b/src/wasm/nxt_rt_wamr.c @@ -0,0 +1,338 @@ +/* + * Copyright (C) Andrew Clayton + * Copyright (C) F5, Inc. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <stdbool.h> +#include <stdarg.h> +#include <unistd.h> +#include <time.h> + +#include <wasm_export.h> + +#include "nxt_wasm.h" + + +typedef struct nxt_wamr_ctx_s nxt_wamr_ctx_t; + +struct nxt_wamr_ctx_s { + uint8_t *mod_buf; + wasm_module_t module; + wasm_module_inst_t module_inst; + wasm_exec_env_t exec_env; +}; + +static nxt_wamr_ctx_t nxt_wamr_ctx; + + +static void +nxt_wamr_err_msg(const char *fmt, ...) +{ + char dstr[20]; + time_t t; + va_list args; + struct tm *tmp; + + t = time(NULL); + tmp = localtime(&t); + if (tmp == NULL) { + return; + } + + strftime(dstr, sizeof(dstr), "%Y/%m/%d %T", tmp); + + fprintf(stderr, "%s [WAMR ERROR] %d ", dstr, getpid()); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); +} + + +static uint32_t +nxt_wasm_get_init_mem_size(wasm_exec_env_t exec_env) +{ + return NXT_WASM_MEM_SIZE; +} + + +static void +nxt_wasm_response_end(wasm_exec_env_t exec_env) +{ + nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env); + + nxt_wasm_do_response_end(ctx); +} + + +static void +nxt_wasm_send_response(wasm_exec_env_t exec_env, uint32_t offset) +{ + nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env); + + nxt_wasm_do_send_response(ctx, offset); +} + + +static void +nxt_wasm_send_headers(wasm_exec_env_t exec_env, uint32_t offset) +{ + nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env); + + nxt_wasm_do_send_headers(ctx, offset); +} + + +static void +nxt_wasm_set_resp_status(wasm_exec_env_t exec_env, uint16_t status) +{ + nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env); + + ctx->status = status; +} + + +static void +nxt_wamr_execute_hook(const nxt_wasm_ctx_t *ctx, nxt_wasm_fh_t hook) +{ + bool ok; + const char *name = ctx->fh[hook].func_name; + nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; + const nxt_wasm_func_t *func = ctx->fh[hook].func; + + if (name == NULL) { + return; + } + + ok = wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func, + 0, NULL, 0, NULL); + if (!ok) { + nxt_wamr_err_msg("failed to call hook function [%s]. (%s)", name, + wasm_runtime_get_exception(rt_ctx->module_inst)); + } +} + + +static int +nxt_wamr_execute_request(const nxt_wasm_ctx_t *ctx) +{ + bool ok; + uint32_t i = 0; + wasm_val_t args[1] = { }; + wasm_val_t results[1] = { }; + nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; + const nxt_wasm_func_t *func = ctx->fh[NXT_WASM_FH_REQUEST].func; + + args[i].kind = WASM_I32; + args[i++].of.i32 = ctx->baddr_off; + + ok = wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func, + 1, results, i, args); + if (!ok) { + nxt_wamr_err_msg("Failed to call function [->wasm_request_handler]. " + "(%s)", + wasm_runtime_get_exception(rt_ctx->module_inst)); + return -1; + } + + return results[0].of.i32; +} + + +static bool +nxt_wamr_set_function_imports(void) +{ + int nr_funcs; + bool ok; + + static NativeSymbol import_functions[] = { + EXPORT_WASM_API_WITH_SIG(nxt_wasm_get_init_mem_size, "()i"), + EXPORT_WASM_API_WITH_SIG(nxt_wasm_response_end, "()"), + EXPORT_WASM_API_WITH_SIG(nxt_wasm_send_response, "(i)"), + EXPORT_WASM_API_WITH_SIG(nxt_wasm_send_headers, "(i)"), + EXPORT_WASM_API_WITH_SIG(nxt_wasm_set_resp_status, "(i)"), + }; + + nr_funcs = sizeof(import_functions) / sizeof(NativeSymbol); + + ok = wasm_runtime_register_natives("env", import_functions, nr_funcs); + if (!ok) { + return false; + } + + return true; +} + + +static int +nxt_wamr_get_function_exports(nxt_wasm_ctx_t *ctx) +{ + int i; + nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; + + for (i = 0; i < NXT_WASM_FH_NR; i++) { + if (ctx->fh[i].func_name == NULL) { + continue; + } + + ctx->fh[i].func = wasm_runtime_lookup_function(rt_ctx->module_inst, + ctx->fh[i].func_name, + NULL); + if (ctx->fh[i].func == NULL) { + return -1; + } + } + + return 0; +} + + +static void +nxt_wamr_wasi_init(const nxt_wasm_ctx_t *ctx) +{ + nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; + + wasm_runtime_set_wasi_args(rt_ctx->module, + (const char **)ctx->dirs, ctx->nr_dirs, + NULL, 0, NULL, 0, NULL, 0); +} + + +static int +nxt_wamr_init_memory(nxt_wasm_ctx_t *ctx) +{ + bool ok; + uint32_t i = 0; + wasm_val_t args[1] = { }; + wasm_val_t results[1] = { }; + nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; + const nxt_wasm_func_t *func = ctx->fh[NXT_WASM_FH_MALLOC].func; + + args[i].kind = WASM_I32; + args[i++].of.i32 = NXT_WASM_MEM_SIZE + NXT_WASM_PAGE_SIZE; + + ok = wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func, + 1, results, i, args); + if (!ok) { + return -1; + } + + ctx->baddr_off = results[0].of.i32; + ctx->baddr = wasm_runtime_addr_app_to_native(rt_ctx->module_inst, + ctx->baddr_off); + + return 0; +} + + +static int +nxt_wamr_init(nxt_wasm_ctx_t *ctx) +{ + int err; + bool ok; + char error_buf[128]; + FILE *fp; + size_t file_size; + uint32_t stack_size = 16384, heap_size = 16384; + nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; + + ok = wasm_runtime_init(); + if (!ok) { + nxt_wamr_err_msg("wasm_runtime_init() failed"); + return -1; + } + + ok = nxt_wamr_set_function_imports(); + if (!ok) { + nxt_wamr_err_msg("nxt_wamr_set_function_imports() failed"); + return -1; + } + + fp = fopen(ctx->module_path, "r"); + if (!fp) { + nxt_wamr_err_msg("fopen(\"%s\") failed", ctx->module_path); + return -1; + } + + fseek(fp, 0L, SEEK_END); + file_size = ftell(fp); + rt_ctx->mod_buf = malloc(file_size); + fseek(fp, 0L, SEEK_SET); + if (fread(rt_ctx->mod_buf, file_size, 1, fp) != 1) { + nxt_wamr_err_msg("fread(\"%s\") failed", ctx->module_path); + return -1; + } + fclose(fp); + + rt_ctx->module = wasm_runtime_load(rt_ctx->mod_buf, file_size, error_buf, + sizeof(error_buf)); + if (rt_ctx->module == NULL) { + nxt_wamr_err_msg("wasm_runtime_load() failed"); + return -1; + } + + nxt_wamr_wasi_init(ctx); + + rt_ctx->module_inst = wasm_runtime_instantiate(rt_ctx->module, stack_size, + heap_size, error_buf, + sizeof(error_buf)); + if (rt_ctx->module_inst == NULL) { + nxt_wamr_err_msg("wasm_runtime_instantiate() failed"); + return -1; + } + + rt_ctx->exec_env = wasm_runtime_create_exec_env(rt_ctx->module_inst, + stack_size); + if (rt_ctx->exec_env == NULL) { + nxt_wamr_err_msg("wasm_runtime_create_exec_env() failed"); + return -1; + } + wasm_runtime_set_user_data(rt_ctx->exec_env, ctx); + + err = nxt_wamr_get_function_exports(ctx); + if (err) { + nxt_wamr_err_msg("nxt_wamr_get_function_exports() failed"); + return -1; + } + + err = nxt_wamr_init_memory(ctx); + if (err) { + nxt_wamr_err_msg("nxt_wamr_init_memory() failed"); + return -1; + } + + return 0; +} + + +static void +nxt_wamr_destroy(const nxt_wasm_ctx_t *ctx) +{ + uint32_t i = 0; + wasm_val_t args[1] = { }; + nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; + const nxt_wasm_func_t *func = ctx->fh[NXT_WASM_FH_FREE].func; + + args[i].kind = WASM_I32; + args[i++].of.i32 = ctx->baddr_off; + + wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func, + 0, NULL, i, args); + + wasm_runtime_destroy_exec_env(rt_ctx->exec_env); + wasm_runtime_deinstantiate(rt_ctx->module_inst); + wasm_runtime_unload(rt_ctx->module); + free(rt_ctx->mod_buf); + wasm_runtime_destroy(); +} + + +const nxt_wasm_operations_t nxt_wasm_ops = { + .init = nxt_wamr_init, + .destroy = nxt_wamr_destroy, + .exec_request = nxt_wamr_execute_request, + .exec_hook = nxt_wamr_execute_hook, +}; diff --git a/src/wasm/nxt_wasm.c b/src/wasm/nxt_wasm.c index 92ed57ab..b2827bd6 100644 --- a/src/wasm/nxt_wasm.c +++ b/src/wasm/nxt_wasm.c @@ -292,6 +292,7 @@ nxt_wasm_setup(nxt_task_t *task, nxt_process_t *process, nxt_wasm_ctx.dirs[i] = nxt_zalloc(str.length + 1); memcpy(nxt_wasm_ctx.dirs[i], str.start, str.length); } + nxt_wasm_ctx.nr_dirs = n; out_init: err = nxt_wops->init(&nxt_wasm_ctx); diff --git a/src/wasm/nxt_wasm.h b/src/wasm/nxt_wasm.h index 6bc3ae35..90e91b2b 100644 --- a/src/wasm/nxt_wasm.h +++ b/src/wasm/nxt_wasm.h @@ -11,9 +11,11 @@ #include <nxt_unit.h> -#include <wasm.h> #if defined(NXT_HAVE_WASM_WASMTIME) +#include <wasm.h> #include <wasmtime.h> +#elif defined(NXT_HAVE_WASM_WAMR) +#include <wasm_export.h> #endif @@ -21,7 +23,9 @@ #define NXT_WASM_MEM_SIZE (32UL * 1024 * 1024) #if defined(NXT_HAVE_WASM_WASMTIME) -typedef wasmtime_func_t nxt_wasm_func_t; +typedef wasmtime_func_t nxt_wasm_func_t; +#elif defined(NXT_HAVE_WASM_WAMR) +typedef wasm_function_inst_t nxt_wasm_func_t; #endif @@ -113,6 +117,7 @@ struct nxt_wasm_ctx_s { nxt_wasm_func_handler_t fh[NXT_WASM_FH_NR]; char **dirs; + size_t nr_dirs; nxt_unit_request_info_t *req; |