diff options
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.c')
-rw-r--r-- | fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.c | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.c new file mode 100644 index 00000000..da83b379 --- /dev/null +++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.c @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "wasm_c_api.h" + +#define WORKER_NUMBER 10 + +/******************************* VM *******************************/ +/* Use wasm_vm_t and vm_xxx to simulate a minimal Wasm VM in Envoy */ + +typedef struct _vm { + wasm_engine_t *engine; + wasm_store_t *store; + wasm_module_t *module; + wasm_shared_module_t *shared_module; + wasm_instance_t *instance; + wasm_func_t **function_list; + wasm_memory_t *memory; + wasm_table_t *table; + wasm_extern_vec_t *exports; +} wasm_vm_t; + +typedef enum _clone_level { + not_cloneable = 0, + compiled_bytecode, + instantiated_module +} clone_level; + +typedef struct _thread_arg_t { + char name[32]; + bool *ready_go_flag; + pthread_mutex_t *ready_go_lock; + pthread_cond_t *ready_go_cond; + const wasm_vm_t *base_vm; +} thread_arg_t; + +wasm_vm_t * +vm_new() +{ + wasm_vm_t *vm = NULL; + + vm = malloc(sizeof(struct _vm)); + if (!vm) + goto fail; + + memset(vm, 0, sizeof(wasm_vm_t)); + + vm->engine = wasm_engine_new(); + if (!vm->engine) + goto fail; + + vm->store = wasm_store_new(vm->engine); + if (!vm->store) + goto fail; + + return vm; + +fail: + if (vm) { + if (vm->engine) + wasm_engine_delete(vm->engine); + + free(vm); + } + return NULL; +} + +wasm_vm_t * +vm_release(wasm_vm_t *vm) +{ + if (!vm) + return NULL; + + if (vm->function_list) { + free(vm->function_list); + vm->function_list = NULL; + } + + vm->memory = NULL; + + if (vm->exports) { + wasm_extern_vec_delete(vm->exports); + free(vm->exports); + vm->exports = NULL; + } + + wasm_instance_delete(vm->instance); + vm->instance = NULL; + + wasm_shared_module_delete(vm->shared_module); + vm->shared_module = NULL; + + wasm_module_delete(vm->module); + vm->module = NULL; + + wasm_store_delete(vm->store); + vm->store = NULL; + + wasm_engine_delete(vm->engine); + vm->engine = NULL; + + free(vm); + return NULL; +} + +bool +vm_load(wasm_vm_t *vm, const wasm_byte_vec_t *binary) +{ + vm->module = wasm_module_new(vm->store, binary); + vm->shared_module = wasm_module_share(vm->module); + return vm->module != NULL; +} + +bool +vm_link(wasm_vm_t *vm, wasm_extern_vec_t *imports) +{ + vm->instance = wasm_instance_new(vm->store, vm->module, imports, NULL); + if (!vm->instance) + goto fail; + + vm->exports = malloc(sizeof(wasm_extern_vec_t)); + if (!vm->exports) + goto fail; + + memset(vm->exports, 0, sizeof(wasm_extern_vec_t)); + wasm_instance_exports(vm->instance, vm->exports); + /* an exported memory, and two exported functions */ + assert(vm->exports->size == 3); + + /* bind memory */ + assert(wasm_extern_kind(vm->exports->data[0]) == WASM_EXTERN_MEMORY); + vm->memory = wasm_extern_as_memory(vm->exports->data[0]); + + vm->function_list = malloc(2 * sizeof(wasm_func_t *)); + if (!vm->function_list) + goto fail; + + memset(vm->function_list, 0, 2 * sizeof(wasm_func_t *)); + + /* bind wasm_set_byte(...) */ + assert(wasm_extern_kind(vm->exports->data[1]) == WASM_EXTERN_FUNC); + vm->function_list[0] = wasm_extern_as_func(vm->exports->data[1]); + + /* bind wasm_get_byte(...) */ + assert(wasm_extern_kind(vm->exports->data[2]) == WASM_EXTERN_FUNC); + vm->function_list[1] = wasm_extern_as_func(vm->exports->data[2]); + + return true; +fail: + return false; +} + +wasm_vm_t * +vm_clone_from_module(const wasm_vm_t *base) +{ + printf("Initializing...\n"); + wasm_vm_t *secondary = NULL; + + secondary = vm_new(); + if (secondary) { + printf("Reuse module and bypass vm_load()..."); + secondary->module = + wasm_module_obtain(base->store, base->shared_module); + if (!secondary->module) + secondary = vm_release(secondary); + } + + return secondary; +} + +wasm_vm_t * +vm_clone_from_instance(const wasm_vm_t *base) +{ + /** + * if do a clone of the level instantiated_module, need to malloc and + * initialie + * - global. WASMGlobalIntance and global data + * - memory. WAAMMemoryInstance, memory_data and heap + * - table. WASMTableInstance, table_data + * - exports. all global, memory and table + * + * it is almost everything in wasm_instantiate() except funciton. + */ + (void)base; + printf("Unsupported\n"); + return NULL; +} + +wasm_vm_t * +vm_clone(const wasm_vm_t *base, clone_level level) +{ + if (level == not_cloneable) + return NULL; + + if (level == compiled_bytecode) + return vm_clone_from_module(base); + else + return vm_clone_from_instance(base); +} + +bool +vm_memory_set_byte(const wasm_vm_t *vm, uint32_t offset, uint8_t byte) +{ + byte_t *data = wasm_memory_data(vm->memory); + assert(data); + *(data + offset) = byte; + return true; +} + +bool +vm_memory_get_byte(const wasm_vm_t *vm, uint32_t offset, uint8_t *byte) +{ + byte_t *data = wasm_memory_data(vm->memory); + assert(data); + *byte = *(data + offset); + return true; +} + +bool +vm_function_set_byte(const wasm_vm_t *vm, uint32_t offset, uint8_t byte) +{ + wasm_val_t a_v[2] = { WASM_I32_VAL(offset), WASM_I32_VAL(byte) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(a_v); + wasm_val_vec_t results = WASM_EMPTY_VEC; + wasm_trap_t *trap = wasm_func_call(vm->function_list[0], &args, &results); + if (trap) { + printf("call wasm_set_byte failed"); + wasm_trap_delete(trap); + return false; + } + + return true; +} + +bool +vm_function_get_byte(const wasm_vm_t *vm, uint32_t offset, uint8_t *byte) +{ + wasm_val_t a_v[1] = { WASM_I32_VAL(offset) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(a_v); + wasm_val_t r_v[1] = { WASM_INIT_VAL }; + wasm_val_vec_t results = WASM_ARRAY_VEC(r_v); + wasm_trap_t *trap = wasm_func_call(vm->function_list[1], &args, &results); + if (trap) { + printf("call wasm_get_byte failed"); + wasm_trap_delete(trap); + return false; + } + + assert(results.data->kind == WASM_I32); + *byte = results.data->of.i32; + return true; +} + +static bool +load_wasm_file_content(const char *file_name, wasm_byte_vec_t *out) +{ + bool ret = false; +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE *file = fopen(file_name, "rb"); +#else + FILE *file = fopen(file_name, "rb"); +#endif + if (!file) { + printf("> Error loading .wasm!\n"); + goto quit; + } + + int offset = fseek(file, 0L, SEEK_END); + if (offset == -1) { + printf("> Error loading .wasm!\n"); + goto close_file; + } + + long file_size = ftell(file); + if (file_size == -1) { + printf("> Error loading .wasm!\n"); + goto close_file; + } + + offset = fseek(file, 0L, SEEK_SET); + if (offset == -1) { + printf("> Error loading .wasm!\n"); + goto close_file; + } + + wasm_byte_vec_new_uninitialized(out, file_size); + if (fread(out->data, file_size, 1, file) != 1) { + printf("> Error loading content!\n"); + goto close_file; + } + + ret = true; +close_file: + fclose(file); +quit: + return ret; +} + +static pthread_key_t name_key; + +wasm_trap_t * +report_cb(const wasm_val_vec_t *args, wasm_val_vec_t *results) +{ + (void)results; + + assert(args->data[0].kind == WASM_I32); + uint32_t chk_pnt_no = args->data[0].of.i32; + + char *name = pthread_getspecific(name_key); + printf("[%s] Pass CHK POINT #%u\n", name, chk_pnt_no); + + return NULL; +} + +bool +run_code_start(wasm_vm_t **out) +{ + bool ret = false; + + printf("Initializing...\n"); + wasm_vm_t *vm = vm_new(); + if (!vm) + goto fail; + + printf("Loading binary...\n"); + wasm_byte_vec_t binary = { 0 }; +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + const char *file_name = "clone.aot"; +#else + const char *file_name = "clone.wasm"; +#endif + if (!load_wasm_file_content(file_name, &binary)) + goto release_vm; + + printf("Compiling module...\n"); + ret = vm_load(vm, &binary); + wasm_byte_vec_delete(&binary); + if (!ret) + goto release_vm; + + printf("Creating callback...\n"); + wasm_functype_t *callback_type = + wasm_functype_new_1_0(wasm_valtype_new_i32()); + if (!callback_type) + goto release_vm; + + wasm_func_t *callback = wasm_func_new(vm->store, callback_type, report_cb); + wasm_functype_delete(callback_type); + if (!callback) + goto release_vm; + + printf("Instantiating module...\n"); + wasm_extern_t *externs[] = { wasm_func_as_extern(callback) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); + ret = vm_link(vm, &imports); + wasm_func_delete(callback); + if (!ret) + goto release_vm; + + *out = vm; + return true; + +release_vm: + vm_release(vm); +fail: + return false; +} + +bool +run_warm_start_w_compiled_bytecode(const wasm_vm_t *first, wasm_vm_t **out) +{ + bool ret; + wasm_vm_t *secondary = vm_clone(first, compiled_bytecode); + if (!secondary) + goto fail; + + printf("Creating callback...\n"); + wasm_functype_t *callback_type = + wasm_functype_new_1_0(wasm_valtype_new_i32()); + if (!callback_type) + goto release_vm; + + wasm_func_t *callback = + wasm_func_new(secondary->store, callback_type, report_cb); + wasm_functype_delete(callback_type); + if (!callback) + goto release_vm; + + printf("Instantiating module...\n"); + wasm_extern_t *externs[] = { wasm_func_as_extern(callback) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); + ret = vm_link(secondary, &imports); + wasm_func_delete(callback); + if (!ret) + goto release_vm; + + *out = secondary; + return true; + +release_vm: + vm_release(secondary); +fail: + return false; +} + +bool +run_warm_start_w_instantiated_module(const wasm_vm_t *first, wasm_vm_t **out) +{ + wasm_vm_t *secondary = vm_clone(first, instantiated_module); + if (!secondary) + return false; + + *out = secondary; + return true; +} + +void +run_test(const wasm_vm_t *vm) +{ + uint8_t byte = 0xFF; + + /* read initialization */ + vm_function_get_byte(vm, 10, &byte); + assert(byte == 0x0); + vm_memory_get_byte(vm, 10, &byte); + assert(byte == 0x0); + + /* read after writing */ + vm_function_set_byte(vm, 16, 0xab); + vm_function_get_byte(vm, 16, &byte); + assert(byte == 0xab); + + vm_memory_set_byte(vm, 16, 0xcd); + vm_memory_get_byte(vm, 16, &byte); + assert(byte == 0xcd); + + /* reading and writing across */ + vm_function_set_byte(vm, 16, 0xef); + vm_memory_get_byte(vm, 16, &byte); + assert(byte == 0xef); + + vm_memory_set_byte(vm, 16, 0x67); + vm_function_get_byte(vm, 16, &byte); + assert(byte == 0x67); + + printf("All Passed ...\n"); +} + +static void * +thrd_func(void *arg) +{ + thread_arg_t *thrd_arg = (thread_arg_t *)arg; + + sleep(rand() % 5); + printf("Running warm start at %s...\n", thrd_arg->name); + + pthread_setspecific(name_key, thrd_arg->name); + + wasm_vm_t *vm; + if (!run_warm_start_w_compiled_bytecode(thrd_arg->base_vm, &vm)) + return NULL; + + pthread_mutex_trylock(thrd_arg->ready_go_lock); + while (!(*thrd_arg->ready_go_flag)) { + pthread_cond_wait(thrd_arg->ready_go_cond, thrd_arg->ready_go_lock); + } + pthread_mutex_unlock(thrd_arg->ready_go_lock); + + printf("Running test at %s...\n", thrd_arg->name); + run_test(vm); + + vm_release(vm); + pthread_exit(NULL); + return NULL; +} + +int +main() +{ + int ret = EXIT_FAILURE; + bool ready_go_flag = false; + pthread_mutex_t ready_go_lock = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t ready_go_cond = PTHREAD_COND_INITIALIZER; + pthread_key_create(&name_key, NULL); + pthread_setspecific(name_key, "Execution Thread"); + + printf("Running cold start at the execution thread...\n"); + wasm_vm_t *base_vm; + if (!run_code_start(&base_vm)) + goto quit; + run_test(base_vm); + + printf("Running warm start at other threads...\n"); + + pthread_t tids[WORKER_NUMBER] = { 0 }; + thread_arg_t thrd_args[WORKER_NUMBER] = { 0 }; + for (size_t i = 0; i < sizeof(tids) / sizeof(tids[0]); i++) { + thread_arg_t *thrd_arg = thrd_args + i; + + snprintf(thrd_arg->name, 32, "Worker#%lu", i); + thrd_arg->ready_go_cond = &ready_go_cond; + thrd_arg->ready_go_lock = &ready_go_lock; + thrd_arg->ready_go_flag = &ready_go_flag; + thrd_arg->base_vm = base_vm; + + int ret = pthread_create(&tids[i], NULL, thrd_func, thrd_arg); + if (ret != 0) + break; + } + + sleep(1); + pthread_mutex_trylock(&ready_go_lock); + ready_go_flag = true; + pthread_mutex_unlock(&ready_go_lock); + pthread_cond_broadcast(&ready_go_cond); + + sleep(3); + for (size_t i = 0; i < sizeof(tids) / sizeof(tids[0]); i++) { + if (tids[i] != 0) + pthread_join(tids[i], NULL); + } + + vm_release(base_vm); + ret = EXIT_SUCCESS; +quit: + return ret; +} |