liupeidong0620 opened issue #10333:
question
- I created multiple wasm_wasmtime_plugin_t
- Each thread runs a wasm_wasmtime_plugin_t
- Is this thread safe?
- The wasmtime_func_call function calls the malloc function exported by wasm. Is this thread safe?
typedef struct { // Load the same wasm program and create multiple wasm_wasmtime_plugin_t instances wasm_engine_t *vm_engine; wasmtime_module_t *module; wasmtime_store_t *store; wasmtime_context_t *context; wasmtime_linker_t *linker; wasmtime_instance_t instance; wasmtime_memory_t memory; } wasm_wasmtime_plugin_t; int main() { .... wasm_wasmtime_plugin_t plugins[6]; // Load the same wasm program and create multiple wasm_wasmtime_plugin_t instances for (int i = 0; i < 6; i ++) { std::thread t([plugin_num = i] { // Is it thread safe? error = wasmtime_func_call(plugins[plugin_num]->context, &func.of.func, params, param_num, results, has_result ? 1 : 0, &trap); }); } // wait thread ok .... }
code (wasm_wasmtime_plugin_t initialization process, specific code)
// wasmtime_vm.h #pragma once #include <wasi.h> #include <wasm.h> #include <wasmtime.h> #include "wasm_base.h" #include "wasm_api.h" #include <string> typedef struct { wasm_engine_t *vm_engine; wasmtime_module_t *module; wasmtime_store_t *store; wasmtime_context_t *context; wasmtime_linker_t *linker; wasmtime_instance_t instance; wasmtime_memory_t memory; } wasm_wasmtime_plugin_t; typedef struct { std::string name; wasmtime_func_callback_t cb; int8_t param_num; wasm_valkind_t param_type[MAX_WASM_API_ARG]; } wasm_wasmtime_host_api_t; class WasmtimeVM : public WasmBaseVM { public: WasmtimeVM() {} virtual int load(std::string& wasm_file, std::string& wasm_name); // load wasm and init virtual int32_t wasm_call(std::string func_name, bool has_result, int param_type, ...); // call wasm func virtual int32_t wasm_memory_alloc(int32_t size); virtual char* wasm_get_memory(int32_t addr, int32_t size); virtual ~WasmtimeVM(); virtual void setCtxId(int32_t wasm_ctx_id) { wasm_ctx_id_ = wasm_ctx_id; } virtual int32_t getCtxId() { return wasm_ctx_id_; } virtual std::string& get_wasm_name() { return wasm_name_; } virtual int32_t get_wasm_id() { return id_; } virtual void set_wasm_id(int32_t id) { id_ = id; } private: wasm_functype_t *wasmtime_host_api_func(const wasm_wasmtime_host_api_t *api); void wasmtime_report_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); bool wasm_wasmtime_has(std::string& name); wasm_wasmtime_plugin_t* plugin; int32_t wasm_ctx_id_ = 0; std::string wasm_name_; int32_t id_; }; // wasmtime_vm.cc #include "wasmtime_vm.h" #include <iostream> #define DEFINE_WASM_API(NAME, ARG_CHECK) \ static wasm_trap_t* wasmtime_##NAME( \ void *env, \ wasmtime_caller_t *caller, \ const wasmtime_val_t *args, \ size_t nargs, \ wasmtime_val_t *results, \ size_t nresults \ ) { \ ARG_CHECK \ results[0].kind = WASMTIME_I32; \ results[0].of.i32 = res; \ return NULL; \ } #define DEFINE_WASM_NAME(NAME, ARG) \ {#NAME, wasmtime_##NAME, ARG}, #define DEFINE_WASM_NAME_ARG_VOID \ 0, {} #define DEFINE_WASM_API_ARG_CHECK_VOID(NAME) \ int32_t res = NAME(); #define DEFINE_WASM_NAME_ARG_I32_1 \ 1, { \ WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_1(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t res = NAME(p0); #define DEFINE_WASM_NAME_ARG_I32_2 \ 2, { \ WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_2(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t res = NAME(p0, p1); #define DEFINE_WASM_NAME_ARG_I32_3 \ 3, { \ WASM_I32, WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_3(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t res = NAME(p0, p1, p2); #define DEFINE_WASM_NAME_ARG_I32_4 \ 4, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_4(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t res = NAME(p0, p1, p2, p3); #define DEFINE_WASM_NAME_ARG_I32_5 \ 5, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, \ } #define DEFINE_WASM_API_ARG_CHECK_I32_5(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t p4 = args[4].of.i32; \ int32_t res = NAME(p0, p1, p2, p3, p4); #define DEFINE_WASM_NAME_ARG_I32_6 \ 6, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, \ WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_6(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t p4 = args[4].of.i32; \ int32_t p5 = args[5].of.i32; \ int32_t res = NAME(p0, p1, p2, p3, p4, p5); #define DEFINE_WASM_NAME_ARG_I32_7 \ 7, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, \ WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_7(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t p4 = args[4].of.i32; \ int32_t p5 = args[5].of.i32; \ int32_t p6 = args[6].of.i32; \ int32_t res = NAME(p0, p1, p2, p3, p4, p5, p6); DEFINE_WASM_API(tendis_get_buffer_bytes, DEFINE_WASM_API_ARG_CHECK_I32_4(tendis_get_buffer_bytes)) DEFINE_WASM_API(tendis_set_buffer_bytes, DEFINE_WASM_API_ARG_CHECK_I32_4(tendis_set_buffer_bytes)) static wasm_wasmtime_host_api_t host_apis[] = { DEFINE_WASM_NAME(tendis_get_buffer_bytes, DEFINE_WASM_NAME_ARG_I32_4) DEFINE_WASM_NAME(tendis_set_buffer_bytes, DEFINE_WASM_NAME_ARG_I32_4) { "", NULL, 0, {} } }; static wasmtime_val_t param_int32[1] = {{ .kind = WASMTIME_I32 }}; static wasmtime_val_t param_int32_int32[2] = {{ .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }}; static wasmtime_val_t param_int32_int32_int32[3] = { { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, }; static wasmtime_val_t param_int32_int32_int32_int32[4] = { { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, }; static wasmtime_val_t param_int32_int32_int32_int32_int32[5] = { { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, }; wasm_functype_t * WasmtimeVM::wasmtime_host_api_func(const wasm_wasmtime_host_api_t *api) { int i; wasm_valtype_vec_t param_vec, result_vec; wasm_valtype_t *param[MAX_WASM_API_ARG]; wasm_valtype_t *result[1]; wasm_functype_t *f; for (i = 0; i < api->param_num; i++) { param[i] = wasm_valtype_new(api->param_type[i]); } result[0] = wasm_valtype_new(WASM_I32); wasm_valtype_vec_new(¶m_vec, api->param_num, param); wasm_valtype_vec_new(&result_vec, 1, result); f = wasm_functype_new(¶m_vec, &result_vec); return f; } void WasmtimeVM::wasmtime_report_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { wasm_byte_vec_t error_message; if (error != NULL) { wasmtime_error_message(error, &error_message); wasmtime_error_delete(error); } else { wasm_trap_message(trap, &error_message); wasm_trap_delete(trap); } std::cout << message << std::endl; std::cout.write(error_message.data, error_message.size); std::cout << std::endl; wasm_byte_vec_delete(&error_message); } int WasmtimeVM::load(std::string& bytecode, std::string& wasm_name) { size_t i; bool ok; wasm_engine_t *vm_engine; wasm_trap_t *trap = NULL; wasmtime_module_t *module; wasmtime_store_t *store; wasmtime_context_t *context; wasmtime_linker_t *linker; wasi_config_t *wasi_config; wasmtime_error_t *error; wasmtime_extern_t item; plugin = new wasm_wasmtime_plugin_t; wasm_name_ = wasm_name; vm_engine = wasm_engine_new(); if (vm_engine == NULL) { std::cout << "failed to new engine" << std::endl; return -1; } //wasmtime_module_deserialize(); error = wasmtime_module_new(vm_engine, (const uint8_t*) bytecode.c_str(), bytecode.size(), &module); //error = wasmtime_module_deserialize(vm_engine, (const uint8_t*) bytecode.c_str(), bytecode.size(), &module); if (error != NULL) { wasmtime_report_error("failed to new module: ", error, NULL); return -2; } store = wasmtime_store_new(vm_engine, NULL, NULL); if (store == NULL) { return -3; } context = wasmtime_store_context(store); wasi_config = wasi_config_new(); if (wasi_config == NULL) { return -4; } wasi_config_inherit_env(wasi_config); wasi_config_inherit_stdin(wasi_config); wasi_config_inherit_stdout(wasi_config); wasi_config_inherit_stderr(wasi_config); error = wasmtime_context_set_wasi(context, wasi_config); if (error != NULL) { wasmtime_report_error("failed to init [message truncated]
liupeidong0620 edited issue #10333:
question
- I created multiple wasm_wasmtime_plugin_t
- Each thread runs a wasm_wasmtime_plugin_t
- Is this thread safe?
- The wasmtime_func_call function calls the malloc function exported by wasm. Is this thread safe?
typedef struct { // Load the same wasm program and create multiple wasm_wasmtime_plugin_t instances wasm_engine_t *vm_engine; wasmtime_module_t *module; wasmtime_store_t *store; wasmtime_context_t *context; wasmtime_linker_t *linker; wasmtime_instance_t instance; wasmtime_memory_t memory; } wasm_wasmtime_plugin_t; int main() { .... wasm_wasmtime_plugin_t plugins[6]; // Load the same wasm program and create multiple wasm_wasmtime_plugin_t instances for (int i = 0; i < 6; i ++) { std::thread t([plugin_num = i] { // Is it thread safe? error = wasmtime_func_call(plugins[plugin_num]->context, &func.of.func, params, param_num, results, has_result ? 1 : 0, &trap); }); } // wait thread ok .... }
code (wasm_wasmtime_plugin_t initialization process, specific code)
// wasmtime_vm.h #pragma once #include <wasi.h> #include <wasm.h> #include <wasmtime.h> #include "wasm_base.h" #include "wasm_api.h" #include <string> typedef struct { wasm_engine_t *vm_engine; wasmtime_module_t *module; wasmtime_store_t *store; wasmtime_context_t *context; wasmtime_linker_t *linker; wasmtime_instance_t instance; wasmtime_memory_t memory; } wasm_wasmtime_plugin_t; typedef struct { std::string name; wasmtime_func_callback_t cb; int8_t param_num; wasm_valkind_t param_type[MAX_WASM_API_ARG]; } wasm_wasmtime_host_api_t; class WasmtimeVM : public WasmBaseVM { public: WasmtimeVM() {} virtual int load(std::string& wasm_file, std::string& wasm_name); // load wasm and init virtual int32_t wasm_call(std::string func_name, bool has_result, int param_type, ...); // call wasm func virtual int32_t wasm_memory_alloc(int32_t size); virtual char* wasm_get_memory(int32_t addr, int32_t size); virtual ~WasmtimeVM(); virtual void setCtxId(int32_t wasm_ctx_id) { wasm_ctx_id_ = wasm_ctx_id; } virtual int32_t getCtxId() { return wasm_ctx_id_; } virtual std::string& get_wasm_name() { return wasm_name_; } virtual int32_t get_wasm_id() { return id_; } virtual void set_wasm_id(int32_t id) { id_ = id; } private: wasm_functype_t *wasmtime_host_api_func(const wasm_wasmtime_host_api_t *api); void wasmtime_report_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); bool wasm_wasmtime_has(std::string& name); wasm_wasmtime_plugin_t* plugin; int32_t wasm_ctx_id_ = 0; std::string wasm_name_; int32_t id_; wasmtime_val_t param_int32[1] = {{ .kind = WASMTIME_I32 }}; wasmtime_val_t param_int32_int32[2] = {{ .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }}; wasmtime_val_t param_int32_int32_int32[3] = { { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, }; wasmtime_val_t param_int32_int32_int32_int32[4] = { { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, }; wasmtime_val_t param_int32_int32_int32_int32_int32[5] = { { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, }; }; // wasmtime_vm.cc #include "wasmtime_vm.h" #include <iostream> #define DEFINE_WASM_API(NAME, ARG_CHECK) \ static wasm_trap_t* wasmtime_##NAME( \ void *env, \ wasmtime_caller_t *caller, \ const wasmtime_val_t *args, \ size_t nargs, \ wasmtime_val_t *results, \ size_t nresults \ ) { \ ARG_CHECK \ results[0].kind = WASMTIME_I32; \ results[0].of.i32 = res; \ return NULL; \ } #define DEFINE_WASM_NAME(NAME, ARG) \ {#NAME, wasmtime_##NAME, ARG}, #define DEFINE_WASM_NAME_ARG_VOID \ 0, {} #define DEFINE_WASM_API_ARG_CHECK_VOID(NAME) \ int32_t res = NAME(); #define DEFINE_WASM_NAME_ARG_I32_1 \ 1, { \ WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_1(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t res = NAME(p0); #define DEFINE_WASM_NAME_ARG_I32_2 \ 2, { \ WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_2(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t res = NAME(p0, p1); #define DEFINE_WASM_NAME_ARG_I32_3 \ 3, { \ WASM_I32, WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_3(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t res = NAME(p0, p1, p2); #define DEFINE_WASM_NAME_ARG_I32_4 \ 4, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_4(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t res = NAME(p0, p1, p2, p3); #define DEFINE_WASM_NAME_ARG_I32_5 \ 5, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, \ } #define DEFINE_WASM_API_ARG_CHECK_I32_5(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t p4 = args[4].of.i32; \ int32_t res = NAME(p0, p1, p2, p3, p4); #define DEFINE_WASM_NAME_ARG_I32_6 \ 6, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, \ WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_6(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t p4 = args[4].of.i32; \ int32_t p5 = args[5].of.i32; \ int32_t res = NAME(p0, p1, p2, p3, p4, p5); #define DEFINE_WASM_NAME_ARG_I32_7 \ 7, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, \ WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_7(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t p4 = args[4].of.i32; \ int32_t p5 = args[5].of.i32; \ int32_t p6 = args[6].of.i32; \ int32_t res = NAME(p0, p1, p2, p3, p4, p5, p6); DEFINE_WASM_API(tendis_get_buffer_bytes, DEFINE_WASM_API_ARG_CHECK_I32_4(tendis_get_buffer_bytes)) DEFINE_WASM_API(tendis_set_buffer_bytes, DEFINE_WASM_API_ARG_CHECK_I32_4(tendis_set_buffer_bytes)) static wasm_wasmtime_host_api_t host_apis[] = { DEFINE_WASM_NAME(tendis_get_buffer_bytes, DEFINE_WASM_NAME_ARG_I32_4) DEFINE_WASM_NAME(tendis_set_buffer_bytes, DEFINE_WASM_NAME_ARG_I32_4) { "", NULL, 0, {} } }; wasm_functype_t * WasmtimeVM::wasmtime_host_api_func(const wasm_wasmtime_host_api_t *api) { int i; wasm_valtype_vec_t param_vec, result_vec; wasm_valtype_t *param[MAX_WASM_API_ARG]; wasm_valtype_t *result[1]; wasm_functype_t *f; for (i = 0; i < api->param_num; i++) { param[i] = wasm_valtype_new(api->param_type[i]); } result[0] = wasm_valtype_new(WASM_I32); wasm_valtype_vec_new(¶m_vec, api->param_num, param); wasm_valtype_vec_new(&result_vec, 1, result); f = wasm_functype_new(¶m_vec, &result_vec); return f; } void WasmtimeVM::wasmtime_report_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { wasm_byte_vec_t error_message; if (error != NULL) { wasmtime_error_message(error, &error_message); wasmtime_error_delete(error); } else { wasm_trap_message(trap, &error_message); wasm_trap_delete(trap); } std::cout << message << std::endl; std::cout.write(error_message.data, error_message.size); std::cout << std::endl; wasm_byte_vec_delete(&error_message); } int WasmtimeVM::load(std::string& bytecode, std::string& wasm_name) { size_t i; bool ok; wasm_engine_t *vm_engine; wasm_trap_t *trap = NULL; wasmtime_module_t *module; wasmtime_store_t *store; wasmtime_context_t *context; wasmtime_linker_t *linker; wasi_config_t *wasi_config; wasmtime_error_t *error; wasmtime_extern_t item; plugin = new wasm_wasmtime_plugin_t; wasm_name_ = wasm_name; vm_engine = wasm_engine_new(); if (vm_engine == NULL) { std::cout << "failed to new engine" << std::endl; return -1; } //wasmtime_module_deserialize(); error = wasmtime_module_new(vm_engine, (const uint8_t*) bytecode.c_str(), bytecode.size(), &module); //error = wasmtime_module_deserialize(vm_engine, (const uint8_t*) bytecode.c_str(), bytecode.size(), &module); if (error != NULL) { wasmtime_report_error("failed to new module: ", error, NULL); return -2; } store = wasmtime_store_new(vm_engine, NULL, NULL); if (store == NULL) { return -3; } context = wasmtime_store_context(store); wasi_config = wasi_config_new(); if (wasi_config == NULL) { return -4; } wasi_config_inherit_env(wasi_config); wasi_config_inherit_stdin(wasi_config); wasi_config_inherit_stdout(wasi_config); wasi_config_inherit_stderr(wasi_config); error = wasmtime_context_set_wasi(context, wasi_config); if (error != NULL) { wasmtime_report_error("failed to init WASI: ", err [message truncated]
alexcrichton commented on issue #10333:
When it comes to thread safety and the C/C++ API (and/or C/C++ in general) you're sort of in the wild west where you'll have to start from basics and build everything up yourself. There is basic documentation of thread safety in the C API and you can also browse the Rust API documentation to better understand thread safety.
tl;dr; "engine" is threadsafe, "store", and everything that refers to it, must only be used in one thread at a time. Your example at the top is only safe so long as nothing else on the main thread uses the store while it's in use by a child thread.
liupeidong0620 closed issue #10333:
question
- I created multiple wasm_wasmtime_plugin_t
- Each thread runs a wasm_wasmtime_plugin_t
- Is this thread safe?
- The wasmtime_func_call function calls the malloc function exported by wasm. Is this thread safe?
typedef struct { // Load the same wasm program and create multiple wasm_wasmtime_plugin_t instances wasm_engine_t *vm_engine; wasmtime_module_t *module; wasmtime_store_t *store; wasmtime_context_t *context; wasmtime_linker_t *linker; wasmtime_instance_t instance; wasmtime_memory_t memory; } wasm_wasmtime_plugin_t; int main() { .... wasm_wasmtime_plugin_t plugins[6]; // Load the same wasm program and create multiple wasm_wasmtime_plugin_t instances for (int i = 0; i < 6; i ++) { std::thread t([plugin_num = i] { // Is it thread safe? error = wasmtime_func_call(plugins[plugin_num]->context, &func.of.func, params, param_num, results, has_result ? 1 : 0, &trap); }); } // wait thread ok .... }
code (wasm_wasmtime_plugin_t initialization process, specific code)
// wasmtime_vm.h #pragma once #include <wasi.h> #include <wasm.h> #include <wasmtime.h> #include "wasm_base.h" #include "wasm_api.h" #include <string> typedef struct { wasm_engine_t *vm_engine; wasmtime_module_t *module; wasmtime_store_t *store; wasmtime_context_t *context; wasmtime_linker_t *linker; wasmtime_instance_t instance; wasmtime_memory_t memory; } wasm_wasmtime_plugin_t; typedef struct { std::string name; wasmtime_func_callback_t cb; int8_t param_num; wasm_valkind_t param_type[MAX_WASM_API_ARG]; } wasm_wasmtime_host_api_t; class WasmtimeVM : public WasmBaseVM { public: WasmtimeVM() {} virtual int load(std::string& wasm_file, std::string& wasm_name); // load wasm and init virtual int32_t wasm_call(std::string func_name, bool has_result, int param_type, ...); // call wasm func virtual int32_t wasm_memory_alloc(int32_t size); virtual char* wasm_get_memory(int32_t addr, int32_t size); virtual ~WasmtimeVM(); virtual void setCtxId(int32_t wasm_ctx_id) { wasm_ctx_id_ = wasm_ctx_id; } virtual int32_t getCtxId() { return wasm_ctx_id_; } virtual std::string& get_wasm_name() { return wasm_name_; } virtual int32_t get_wasm_id() { return id_; } virtual void set_wasm_id(int32_t id) { id_ = id; } private: wasm_functype_t *wasmtime_host_api_func(const wasm_wasmtime_host_api_t *api); void wasmtime_report_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); bool wasm_wasmtime_has(std::string& name); wasm_wasmtime_plugin_t* plugin; int32_t wasm_ctx_id_ = 0; std::string wasm_name_; int32_t id_; wasmtime_val_t param_int32[1] = {{ .kind = WASMTIME_I32 }}; wasmtime_val_t param_int32_int32[2] = {{ .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }}; wasmtime_val_t param_int32_int32_int32[3] = { { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, }; wasmtime_val_t param_int32_int32_int32_int32[4] = { { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, }; wasmtime_val_t param_int32_int32_int32_int32_int32[5] = { { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, { .kind = WASMTIME_I32 }, }; }; // wasmtime_vm.cc #include "wasmtime_vm.h" #include <iostream> #define DEFINE_WASM_API(NAME, ARG_CHECK) \ static wasm_trap_t* wasmtime_##NAME( \ void *env, \ wasmtime_caller_t *caller, \ const wasmtime_val_t *args, \ size_t nargs, \ wasmtime_val_t *results, \ size_t nresults \ ) { \ ARG_CHECK \ results[0].kind = WASMTIME_I32; \ results[0].of.i32 = res; \ return NULL; \ } #define DEFINE_WASM_NAME(NAME, ARG) \ {#NAME, wasmtime_##NAME, ARG}, #define DEFINE_WASM_NAME_ARG_VOID \ 0, {} #define DEFINE_WASM_API_ARG_CHECK_VOID(NAME) \ int32_t res = NAME(); #define DEFINE_WASM_NAME_ARG_I32_1 \ 1, { \ WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_1(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t res = NAME(p0); #define DEFINE_WASM_NAME_ARG_I32_2 \ 2, { \ WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_2(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t res = NAME(p0, p1); #define DEFINE_WASM_NAME_ARG_I32_3 \ 3, { \ WASM_I32, WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_3(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t res = NAME(p0, p1, p2); #define DEFINE_WASM_NAME_ARG_I32_4 \ 4, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_4(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t res = NAME(p0, p1, p2, p3); #define DEFINE_WASM_NAME_ARG_I32_5 \ 5, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, \ } #define DEFINE_WASM_API_ARG_CHECK_I32_5(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t p4 = args[4].of.i32; \ int32_t res = NAME(p0, p1, p2, p3, p4); #define DEFINE_WASM_NAME_ARG_I32_6 \ 6, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, \ WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_6(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t p4 = args[4].of.i32; \ int32_t p5 = args[5].of.i32; \ int32_t res = NAME(p0, p1, p2, p3, p4, p5); #define DEFINE_WASM_NAME_ARG_I32_7 \ 7, { \ WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, \ WASM_I32, WASM_I32, } #define DEFINE_WASM_API_ARG_CHECK_I32_7(NAME) \ int32_t p0 = args[0].of.i32; \ int32_t p1 = args[1].of.i32; \ int32_t p2 = args[2].of.i32; \ int32_t p3 = args[3].of.i32; \ int32_t p4 = args[4].of.i32; \ int32_t p5 = args[5].of.i32; \ int32_t p6 = args[6].of.i32; \ int32_t res = NAME(p0, p1, p2, p3, p4, p5, p6); DEFINE_WASM_API(tendis_get_buffer_bytes, DEFINE_WASM_API_ARG_CHECK_I32_4(tendis_get_buffer_bytes)) DEFINE_WASM_API(tendis_set_buffer_bytes, DEFINE_WASM_API_ARG_CHECK_I32_4(tendis_set_buffer_bytes)) static wasm_wasmtime_host_api_t host_apis[] = { DEFINE_WASM_NAME(tendis_get_buffer_bytes, DEFINE_WASM_NAME_ARG_I32_4) DEFINE_WASM_NAME(tendis_set_buffer_bytes, DEFINE_WASM_NAME_ARG_I32_4) { "", NULL, 0, {} } }; wasm_functype_t * WasmtimeVM::wasmtime_host_api_func(const wasm_wasmtime_host_api_t *api) { int i; wasm_valtype_vec_t param_vec, result_vec; wasm_valtype_t *param[MAX_WASM_API_ARG]; wasm_valtype_t *result[1]; wasm_functype_t *f; for (i = 0; i < api->param_num; i++) { param[i] = wasm_valtype_new(api->param_type[i]); } result[0] = wasm_valtype_new(WASM_I32); wasm_valtype_vec_new(¶m_vec, api->param_num, param); wasm_valtype_vec_new(&result_vec, 1, result); f = wasm_functype_new(¶m_vec, &result_vec); return f; } void WasmtimeVM::wasmtime_report_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { wasm_byte_vec_t error_message; if (error != NULL) { wasmtime_error_message(error, &error_message); wasmtime_error_delete(error); } else { wasm_trap_message(trap, &error_message); wasm_trap_delete(trap); } std::cout << message << std::endl; std::cout.write(error_message.data, error_message.size); std::cout << std::endl; wasm_byte_vec_delete(&error_message); } int WasmtimeVM::load(std::string& bytecode, std::string& wasm_name) { size_t i; bool ok; wasm_engine_t *vm_engine; wasm_trap_t *trap = NULL; wasmtime_module_t *module; wasmtime_store_t *store; wasmtime_context_t *context; wasmtime_linker_t *linker; wasi_config_t *wasi_config; wasmtime_error_t *error; wasmtime_extern_t item; plugin = new wasm_wasmtime_plugin_t; wasm_name_ = wasm_name; vm_engine = wasm_engine_new(); if (vm_engine == NULL) { std::cout << "failed to new engine" << std::endl; return -1; } //wasmtime_module_deserialize(); error = wasmtime_module_new(vm_engine, (const uint8_t*) bytecode.c_str(), bytecode.size(), &module); //error = wasmtime_module_deserialize(vm_engine, (const uint8_t*) bytecode.c_str(), bytecode.size(), &module); if (error != NULL) { wasmtime_report_error("failed to new module: ", error, NULL); return -2; } store = wasmtime_store_new(vm_engine, NULL, NULL); if (store == NULL) { return -3; } context = wasmtime_store_context(store); wasi_config = wasi_config_new(); if (wasi_config == NULL) { return -4; } wasi_config_inherit_env(wasi_config); wasi_config_inherit_stdin(wasi_config); wasi_config_inherit_stdout(wasi_config); wasi_config_inherit_stderr(wasi_config); error = wasmtime_context_set_wasi(context, wasi_config); if (error != NULL) { wasmtime_report_error("failed to init WASI: ", err [message truncated]
liupeidong0620 commented on issue #10333:
Thanks
Last updated: Apr 17 2025 at 08:04 UTC