Enable shared memory && add pthread support (#282)
This commit is contained in:
@ -86,6 +86,10 @@ enum {
|
||||
#define WASM_ENABLE_LIBC_WASI 0
|
||||
#endif
|
||||
|
||||
#ifndef WASM_ENABLE_LIB_PTHREAD
|
||||
#define WASM_ENABLE_LIB_PTHREAD 0
|
||||
#endif
|
||||
|
||||
#ifndef WASM_ENABLE_BASE_LIB
|
||||
#define WASM_ENABLE_BASE_LIB 0
|
||||
#endif
|
||||
@ -99,6 +103,16 @@ enum {
|
||||
#define WASM_ENABLE_BULK_MEMORY 0
|
||||
#endif
|
||||
|
||||
/* Shared memory */
|
||||
#ifndef WASM_ENABLE_SHARED_MEMORY
|
||||
#define WASM_ENABLE_SHARED_MEMORY 0
|
||||
#endif
|
||||
|
||||
/* Thread manager */
|
||||
#ifndef WASM_ENABLE_THREAD_MGR
|
||||
#define WASM_ENABLE_THREAD_MGR 0
|
||||
#endif
|
||||
|
||||
/* WASM log system */
|
||||
#ifndef WASM_ENABLE_LOG
|
||||
#define WASM_ENABLE_LOG 1
|
||||
@ -206,5 +220,9 @@ enum {
|
||||
#define WASM_ENABLE_SPEC_TEST 0
|
||||
#endif
|
||||
|
||||
/* Default max thread num per cluster. Can be overwrite by
|
||||
wasm_runtime_set_max_thread_num */
|
||||
#define CLUSTER_MAX_THREAD_NUM 4
|
||||
|
||||
#endif /* end of _CONFIG_H_ */
|
||||
|
||||
|
||||
@ -167,30 +167,24 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
||||
module_inst->heap_data.ptr = p;
|
||||
p += heap_size;
|
||||
module_inst->heap_data_end.ptr = p;
|
||||
if (!(heap_handle = mem_allocator_create(module_inst->heap_data.ptr,
|
||||
heap_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module instantiate failed: init app heap failed.");
|
||||
goto fail1;
|
||||
}
|
||||
module_inst->heap_handle.ptr = heap_handle;
|
||||
module_inst->heap_data_size = heap_size;
|
||||
#if WASM_ENABLE_SPEC_TEST == 0
|
||||
module_inst->heap_base_offset = -(int32)heap_size;
|
||||
#else
|
||||
module_inst->heap_base_offset = 0;
|
||||
#endif
|
||||
if (heap_size > 0) {
|
||||
if (!(heap_handle = mem_allocator_create(module_inst->heap_data.ptr,
|
||||
heap_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module instantiate failed: init app heap failed.");
|
||||
goto fail1;
|
||||
}
|
||||
module_inst->heap_handle.ptr = heap_handle;
|
||||
}
|
||||
|
||||
/* Init memory info */
|
||||
module_inst->memory_data.ptr = p;
|
||||
p += (uint32)memory_data_size;
|
||||
module_inst->memory_data_end.ptr = p;
|
||||
module_inst->memory_data_size = (uint32)memory_data_size;
|
||||
#if WASM_ENABLE_SPEC_TEST == 0
|
||||
module_inst->total_mem_size = (uint32)(heap_size + memory_data_size);
|
||||
#else
|
||||
module_inst->total_mem_size = (uint32)memory_data_size;
|
||||
#endif
|
||||
module_inst->mem_cur_page_count = module->mem_init_page_count;
|
||||
module_inst->mem_max_page_count = module->mem_max_page_count;
|
||||
|
||||
@ -210,7 +204,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
||||
|
||||
bh_assert(data_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST
|
||||
|| data_seg->offset.init_expr_type ==
|
||||
|| data_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_GET_GLOBAL);
|
||||
|
||||
/* Resolve memory data base offset */
|
||||
@ -264,8 +258,10 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
||||
return true;
|
||||
|
||||
fail2:
|
||||
mem_allocator_destroy(module_inst->heap_handle.ptr);
|
||||
module_inst->heap_handle.ptr = NULL;
|
||||
if (heap_size > 0) {
|
||||
mem_allocator_destroy(module_inst->heap_handle.ptr);
|
||||
module_inst->heap_handle.ptr = NULL;
|
||||
}
|
||||
fail1:
|
||||
wasm_runtime_free(module_inst->heap_data.ptr);
|
||||
module_inst->heap_data.ptr = NULL;
|
||||
@ -361,7 +357,7 @@ execute_start_function(AOTModuleInstance *module_inst)
|
||||
}
|
||||
|
||||
AOTModuleInstance*
|
||||
aot_instantiate(AOTModule *module,
|
||||
aot_instantiate(AOTModule *module, bool is_sub_inst,
|
||||
uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
@ -376,10 +372,6 @@ aot_instantiate(AOTModule *module,
|
||||
|
||||
/* Check heap size */
|
||||
heap_size = align_uint(heap_size, 8);
|
||||
if (heap_size == 0)
|
||||
heap_size = APP_HEAP_SIZE_DEFAULT;
|
||||
if (heap_size < APP_HEAP_SIZE_MIN)
|
||||
heap_size = APP_HEAP_SIZE_MIN;
|
||||
if (heap_size > APP_HEAP_SIZE_MAX)
|
||||
heap_size = APP_HEAP_SIZE_MAX;
|
||||
|
||||
@ -422,16 +414,17 @@ aot_instantiate(AOTModule *module,
|
||||
goto fail;
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
if (!wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst,
|
||||
module->wasi_args.dir_list,
|
||||
module->wasi_args.dir_count,
|
||||
module->wasi_args.map_dir_list,
|
||||
module->wasi_args.map_dir_count,
|
||||
module->wasi_args.env,
|
||||
module->wasi_args.env_count,
|
||||
module->wasi_args.argv,
|
||||
module->wasi_args.argc,
|
||||
error_buf, error_buf_size))
|
||||
if (heap_size > 0
|
||||
&& !wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst,
|
||||
module->wasi_args.dir_list,
|
||||
module->wasi_args.dir_count,
|
||||
module->wasi_args.map_dir_list,
|
||||
module->wasi_args.map_dir_count,
|
||||
module->wasi_args.env,
|
||||
module->wasi_args.env_count,
|
||||
module->wasi_args.argv,
|
||||
module->wasi_args.argc,
|
||||
error_buf, error_buf_size))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
@ -455,19 +448,21 @@ aot_instantiate(AOTModule *module,
|
||||
return module_inst;
|
||||
|
||||
fail:
|
||||
aot_deinstantiate(module_inst);
|
||||
aot_deinstantiate(module_inst, is_sub_inst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
aot_deinstantiate(AOTModuleInstance *module_inst)
|
||||
aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
|
||||
{
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
/* Destroy wasi resource before freeing app heap, since some fields of
|
||||
wasi contex are allocated from app heap, and if app heap is freed,
|
||||
these fields will be set to NULL, we cannot free their internal data
|
||||
which may allocated from global heap. */
|
||||
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst);
|
||||
/* Only destroy wasi ctx in the main module instance */
|
||||
if (!is_sub_inst)
|
||||
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst);
|
||||
#endif
|
||||
|
||||
if (module_inst->heap_handle.ptr)
|
||||
@ -798,13 +793,17 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Destroy heap's lock firstly, if its memory is re-allocated,
|
||||
we cannot access its lock again. */
|
||||
mem_allocator_destroy_lock(module_inst->heap_handle.ptr);
|
||||
if (heap_size > 0) {
|
||||
/* Destroy heap's lock firstly, if its memory is re-allocated,
|
||||
we cannot access its lock again. */
|
||||
mem_allocator_destroy_lock(module_inst->heap_handle.ptr);
|
||||
}
|
||||
if (!(heap_data = wasm_runtime_realloc(heap_data_old, (uint32)total_size))) {
|
||||
if (!(heap_data = wasm_runtime_malloc((uint32)total_size))) {
|
||||
/* Restore heap's lock if memory re-alloc failed */
|
||||
mem_allocator_reinit_lock(module_inst->heap_handle.ptr);
|
||||
if (heap_size > 0) {
|
||||
/* Restore heap's lock if memory re-alloc failed */
|
||||
mem_allocator_reinit_lock(module_inst->heap_handle.ptr);
|
||||
}
|
||||
aot_set_exception(module_inst, "fail to enlarge memory.");
|
||||
return false;
|
||||
}
|
||||
@ -817,23 +816,21 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count)
|
||||
0, (uint32)total_size - total_size_old);
|
||||
|
||||
module_inst->heap_data.ptr = heap_data;
|
||||
module_inst->heap_handle.ptr = (uint8*)heap_handle_old
|
||||
+ (heap_data - heap_data_old);
|
||||
module_inst->heap_data_end.ptr = heap_data + heap_size;
|
||||
|
||||
if (mem_allocator_migrate(module_inst->heap_handle.ptr,
|
||||
heap_handle_old) != 0) {
|
||||
aot_set_exception(module_inst, "fail to enlarge memory.");
|
||||
return false;
|
||||
if (heap_size > 0) {
|
||||
module_inst->heap_handle.ptr = (uint8*)heap_handle_old
|
||||
+ (heap_data - heap_data_old);
|
||||
if (mem_allocator_migrate(module_inst->heap_handle.ptr,
|
||||
heap_handle_old) != 0) {
|
||||
aot_set_exception(module_inst, "fail to enlarge memory.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module_inst->mem_cur_page_count = total_page_count;
|
||||
module_inst->memory_data_size = (uint32)memory_data_size;
|
||||
#if WASM_ENABLE_SPEC_TEST == 0
|
||||
module_inst->total_mem_size = (uint32)(heap_size + memory_data_size);
|
||||
#else
|
||||
module_inst->total_mem_size = (uint32)memory_data_size;
|
||||
#endif
|
||||
module_inst->memory_data.ptr = (uint8*)heap_data + heap_size;
|
||||
module_inst->memory_data_end.ptr = (uint8*)module_inst->memory_data.ptr
|
||||
+ (uint32)memory_data_size;
|
||||
|
||||
@ -296,6 +296,7 @@ aot_unload(AOTModule *module);
|
||||
* Instantiate a AOT module.
|
||||
*
|
||||
* @param module the AOT module to instantiate
|
||||
* @param is_sub_inst the flag of sub instance
|
||||
* @param heap_size the default heap size of the module instance, a heap will
|
||||
* be created besides the app memory space. Both wasm app and native
|
||||
* function can allocate memory from the heap. If heap_size is 0, the
|
||||
@ -306,7 +307,7 @@ aot_unload(AOTModule *module);
|
||||
* @return return the instantiated AOT module instance, NULL if failed
|
||||
*/
|
||||
AOTModuleInstance*
|
||||
aot_instantiate(AOTModule *module,
|
||||
aot_instantiate(AOTModule *module, bool is_sub_inst,
|
||||
uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size);
|
||||
|
||||
@ -314,9 +315,10 @@ aot_instantiate(AOTModule *module,
|
||||
* Deinstantiate a AOT module instance, destroy the resources.
|
||||
*
|
||||
* @param module_inst the AOT module instance to destroy
|
||||
* @param is_sub_inst the flag of sub instance
|
||||
*/
|
||||
void
|
||||
aot_deinstantiate(AOTModuleInstance *module_inst);
|
||||
aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst);
|
||||
|
||||
/**
|
||||
* Lookup an exported function in the AOT module instance.
|
||||
|
||||
@ -6,9 +6,13 @@
|
||||
#include "wasm_exec_env.h"
|
||||
#include "wasm_runtime_common.h"
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
#include "../libraries/thread-mgr/thread_manager.h"
|
||||
#endif
|
||||
|
||||
WASMExecEnv *
|
||||
wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
|
||||
uint32 stack_size)
|
||||
wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
|
||||
uint32 stack_size)
|
||||
{
|
||||
uint64 total_size = offsetof(WASMExecEnv, wasm_stack.s.bottom)
|
||||
+ (uint64)stack_size;
|
||||
@ -22,26 +26,87 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
|
||||
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (!(exec_env->argv_buf = wasm_runtime_malloc(sizeof(uint32) * 64))) {
|
||||
wasm_runtime_free(exec_env);
|
||||
return NULL;
|
||||
goto fail1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
if (os_mutex_init(&exec_env->wait_lock) != 0)
|
||||
goto fail2;
|
||||
|
||||
if (os_cond_init(&exec_env->wait_cond) != 0)
|
||||
goto fail3;
|
||||
#endif
|
||||
|
||||
exec_env->module_inst = module_inst;
|
||||
exec_env->wasm_stack_size = stack_size;
|
||||
exec_env->wasm_stack.s.top_boundary =
|
||||
exec_env->wasm_stack.s.bottom + stack_size;
|
||||
exec_env->wasm_stack.s.top = exec_env->wasm_stack.s.bottom;
|
||||
return exec_env;
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
fail3:
|
||||
os_mutex_destroy(&exec_env->wait_lock);
|
||||
fail2:
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
wasm_runtime_free(exec_env->argv_buf);
|
||||
fail1:
|
||||
#endif
|
||||
wasm_runtime_free(exec_env);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_exec_env_destroy_internal(WASMExecEnv *exec_env)
|
||||
{
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
os_mutex_destroy(&exec_env->wait_lock);
|
||||
os_cond_destroy(&exec_env->wait_cond);
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
wasm_runtime_free(exec_env->argv_buf);
|
||||
#endif
|
||||
wasm_runtime_free(exec_env);
|
||||
}
|
||||
|
||||
WASMExecEnv *
|
||||
wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
|
||||
uint32 stack_size)
|
||||
{
|
||||
WASMExecEnv *exec_env = wasm_exec_env_create_internal(module_inst,
|
||||
stack_size);
|
||||
/* Set the aux_stack_boundary to 0 */
|
||||
exec_env->aux_stack_boundary = 0;
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
WASMCluster *cluster;
|
||||
|
||||
if (!exec_env)
|
||||
return NULL;
|
||||
|
||||
/* Create a new cluster for this exec_env */
|
||||
cluster = wasm_cluster_create(exec_env);
|
||||
if (!cluster) {
|
||||
wasm_exec_env_destroy_internal(exec_env);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return exec_env;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_exec_env_destroy(WASMExecEnv *exec_env)
|
||||
{
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
wasm_runtime_free(exec_env->argv_buf);
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
/* Terminate all sub-threads */
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
if (cluster) {
|
||||
wasm_cluster_terminate_all_except_self(cluster, exec_env);
|
||||
wasm_cluster_del_exec_env(cluster, exec_env);
|
||||
}
|
||||
#endif
|
||||
wasm_runtime_free(exec_env);
|
||||
wasm_exec_env_destroy_internal(exec_env);
|
||||
}
|
||||
|
||||
WASMModuleInstanceCommon *
|
||||
@ -59,3 +124,16 @@ wasm_exec_env_set_thread_info(WASMExecEnv *exec_env)
|
||||
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
void *
|
||||
wasm_exec_env_get_thread_arg(WASMExecEnv *exec_env)
|
||||
{
|
||||
return exec_env->thread_arg;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg)
|
||||
{
|
||||
exec_env->thread_arg = thread_arg;
|
||||
}
|
||||
#endif
|
||||
@ -18,6 +18,10 @@ extern "C" {
|
||||
struct WASMModuleInstanceCommon;
|
||||
struct WASMInterpFrame;
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
typedef struct WASMCluster WASMCluster;
|
||||
#endif
|
||||
|
||||
/* Execution environment */
|
||||
typedef struct WASMExecEnv {
|
||||
/* Next thread's exec env of a WASM module instance. */
|
||||
@ -41,6 +45,28 @@ typedef struct WASMExecEnv {
|
||||
exception. */
|
||||
uint8 *native_stack_boundary;
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
/* Used to terminate or suspend the interpreter
|
||||
bit 0: need terminate
|
||||
bit 1: need suspend
|
||||
bit 2: need to go into breakpoint */
|
||||
uintptr_t suspend_flags;
|
||||
|
||||
/* Must be provided by thread library */
|
||||
void* (*thread_start_routine)(void *);
|
||||
void *thread_arg;
|
||||
|
||||
/* pointer to the cluster */
|
||||
WASMCluster *cluster;
|
||||
|
||||
/* used to support debugger */
|
||||
korp_mutex wait_lock;
|
||||
korp_cond wait_cond;
|
||||
#endif
|
||||
|
||||
/* Aux stack boundary */
|
||||
uint32 aux_stack_boundary;
|
||||
|
||||
/* attachment for native function */
|
||||
void *attachment;
|
||||
|
||||
@ -76,6 +102,13 @@ typedef struct WASMExecEnv {
|
||||
} wasm_stack;
|
||||
} WASMExecEnv;
|
||||
|
||||
WASMExecEnv *
|
||||
wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
|
||||
uint32 stack_size);
|
||||
|
||||
void
|
||||
wasm_exec_env_destroy_internal(WASMExecEnv *exec_env);
|
||||
|
||||
WASMExecEnv *
|
||||
wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
|
||||
uint32 stack_size);
|
||||
@ -165,6 +198,15 @@ wasm_exec_env_get_module_inst(WASMExecEnv *exec_env);
|
||||
void
|
||||
wasm_exec_env_set_thread_info(WASMExecEnv *exec_env);
|
||||
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
void *
|
||||
wasm_exec_env_get_thread_arg(WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -28,6 +28,17 @@ get_base_lib_export_apis(NativeSymbol **p_base_lib_apis);
|
||||
uint32
|
||||
get_ext_lib_export_apis(NativeSymbol **p_ext_lib_apis);
|
||||
|
||||
#if WASM_ENABLE_LIB_PTHREAD != 0
|
||||
bool
|
||||
lib_pthread_init();
|
||||
|
||||
void
|
||||
lib_pthread_destroy();
|
||||
|
||||
uint32
|
||||
get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis);
|
||||
#endif
|
||||
|
||||
static bool
|
||||
check_symbol_signature(const WASMType *type, const char *signature)
|
||||
{
|
||||
@ -278,6 +289,17 @@ wasm_native_init()
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LIB_PTHREAD != 0
|
||||
if (!lib_pthread_init())
|
||||
return false;
|
||||
|
||||
n_native_symbols = get_lib_pthread_export_apis(&native_symbols);
|
||||
if (n_native_symbols > 0
|
||||
&& !wasm_native_register_natives("env",
|
||||
native_symbols, n_native_symbols))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -286,6 +308,10 @@ wasm_native_destroy()
|
||||
{
|
||||
NativeSymbolsNode *node, *node_next;
|
||||
|
||||
#if WASM_ENABLE_LIB_PTHREAD != 0
|
||||
lib_pthread_destroy();
|
||||
#endif
|
||||
|
||||
node = g_native_symbols_list;
|
||||
while (node) {
|
||||
node_next = node->next;
|
||||
|
||||
@ -15,6 +15,12 @@
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
#include "../aot/aot_runtime.h"
|
||||
#endif
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
#include "../libraries/thread-mgr/thread_manager.h"
|
||||
#endif
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
#include "wasm_shared_memory.h"
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
/*
|
||||
@ -90,25 +96,50 @@ wasm_runtime_env_init()
|
||||
return false;
|
||||
|
||||
if (wasm_native_init() == false) {
|
||||
bh_platform_destroy();
|
||||
return false;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE
|
||||
if (BHT_OK != os_mutex_init(®istered_module_list_lock)) {
|
||||
wasm_native_destroy();
|
||||
bh_platform_destroy();
|
||||
return false;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
if (BHT_OK != os_mutex_init(&loading_module_list_lock)) {
|
||||
os_mutex_destroy(®istered_module_list_lock);
|
||||
wasm_native_destroy();
|
||||
bh_platform_destroy();
|
||||
return false;
|
||||
goto fail3;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY
|
||||
if (!wasm_shared_memory_init()) {
|
||||
goto fail4;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
if (!thread_manager_init()) {
|
||||
goto fail5;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
fail5:
|
||||
#endif
|
||||
#if WASM_ENABLE_SHARED_MEMORY
|
||||
wasm_shared_memory_destroy();
|
||||
fail4:
|
||||
#endif
|
||||
#if WASM_ENABLE_MULTI_MODULE
|
||||
os_mutex_destroy(&loading_module_list_lock);
|
||||
fail3:
|
||||
os_mutex_destroy(®istered_module_list_lock);
|
||||
fail2:
|
||||
#endif
|
||||
wasm_native_destroy();
|
||||
fail1:
|
||||
bh_platform_destroy();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -147,6 +178,15 @@ wasm_runtime_destroy()
|
||||
wasm_runtime_destroy_registered_module_list();
|
||||
os_mutex_destroy(®istered_module_list_lock);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY
|
||||
wasm_shared_memory_destroy();
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
thread_manager_destroy();
|
||||
#endif
|
||||
|
||||
wasm_native_destroy();
|
||||
bh_platform_destroy();
|
||||
|
||||
@ -191,7 +231,6 @@ get_package_type(const uint8 *buf, uint32 size)
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static module_reader reader;
|
||||
static module_destroyer destroyer;
|
||||
|
||||
void
|
||||
wasm_runtime_set_module_reader(const module_reader reader_cb,
|
||||
const module_destroyer destroyer_cb)
|
||||
@ -492,6 +531,42 @@ wasm_runtime_is_built_in_module(const char *module_name)
|
||||
);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
bool
|
||||
wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env,
|
||||
uint32 start_offset, uint32 size)
|
||||
{
|
||||
WASMModuleInstanceCommon *module_inst
|
||||
= wasm_exec_env_get_module_inst(exec_env);
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
return wasm_set_aux_stack(exec_env, start_offset, size);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_exec_env_get_aux_stack(WASMExecEnv *exec_env,
|
||||
uint32 *start_offset, uint32 *size)
|
||||
{
|
||||
WASMModuleInstanceCommon *module_inst
|
||||
= wasm_exec_env_get_module_inst(exec_env);
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
return wasm_get_aux_stack(exec_env, start_offset, size);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_runtime_set_max_thread_num(uint32 num)
|
||||
{
|
||||
wasm_cluster_set_max_thread_num(num);
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_THREAD_MGR */
|
||||
|
||||
static WASMModuleCommon *
|
||||
register_module_with_null_name(WASMModuleCommon *module_common,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
@ -618,47 +693,63 @@ wasm_runtime_unload(WASMModuleCommon *module)
|
||||
}
|
||||
|
||||
WASMModuleInstanceCommon *
|
||||
wasm_runtime_instantiate(WASMModuleCommon *module,
|
||||
uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst,
|
||||
uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module->module_type == Wasm_Module_Bytecode)
|
||||
return (WASMModuleInstanceCommon*)
|
||||
wasm_instantiate((WASMModule*)module,
|
||||
wasm_instantiate((WASMModule*)module, is_sub_inst,
|
||||
stack_size, heap_size,
|
||||
error_buf, error_buf_size);
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module->module_type == Wasm_Module_AoT)
|
||||
return (WASMModuleInstanceCommon*)
|
||||
aot_instantiate((AOTModule*)module,
|
||||
aot_instantiate((AOTModule*)module, is_sub_inst,
|
||||
stack_size, heap_size,
|
||||
error_buf, error_buf_size);
|
||||
#endif
|
||||
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate module failed, invalid module type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WASMModuleInstanceCommon *
|
||||
wasm_runtime_instantiate(WASMModuleCommon *module,
|
||||
uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
return wasm_runtime_instantiate_internal(module, false,
|
||||
stack_size, heap_size,
|
||||
error_buf, error_buf_size);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst)
|
||||
wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst,
|
||||
bool is_sub_inst)
|
||||
{
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
wasm_deinstantiate((WASMModuleInstance*)module_inst);
|
||||
wasm_deinstantiate((WASMModuleInstance*)module_inst, is_sub_inst);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT) {
|
||||
aot_deinstantiate((AOTModuleInstance*)module_inst);
|
||||
aot_deinstantiate((AOTModuleInstance*)module_inst, is_sub_inst);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst)
|
||||
{
|
||||
return wasm_runtime_deinstantiate_internal(module_inst, false);
|
||||
}
|
||||
|
||||
WASMExecEnv *
|
||||
wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,
|
||||
uint32 stack_size)
|
||||
@ -1442,6 +1533,24 @@ wasm_runtime_set_wasi_ctx(WASMModuleInstanceCommon *module_inst,
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_LIBC_WASI */
|
||||
|
||||
WASMModuleCommon*
|
||||
wasm_exec_env_get_module(WASMExecEnv *exec_env)
|
||||
{
|
||||
WASMModuleInstanceCommon *module_inst =
|
||||
wasm_runtime_get_module_inst(exec_env);
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode)
|
||||
return (WASMModuleCommon*)
|
||||
((WASMModuleInstance*)module_inst)->module;
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT)
|
||||
return (WASMModuleCommon*)
|
||||
((AOTModuleInstance*)module_inst)->aot_module.ptr;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of wasm_application_execute_main()
|
||||
*/
|
||||
|
||||
@ -105,6 +105,17 @@ wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
|
||||
void
|
||||
wasm_runtime_unload(WASMModuleCommon *module);
|
||||
|
||||
/* Internal API */
|
||||
WASMModuleInstanceCommon *
|
||||
wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst,
|
||||
uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size);
|
||||
|
||||
/* Internal API */
|
||||
void
|
||||
wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst,
|
||||
bool is_sub_inst);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASMModuleInstanceCommon *
|
||||
wasm_runtime_instantiate(WASMModuleCommon *module,
|
||||
@ -319,6 +330,16 @@ wasm_runtime_destroy_loading_module_list();
|
||||
bool
|
||||
wasm_runtime_is_built_in_module(const char *module_name);
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
bool
|
||||
wasm_exec_env_get_aux_stack(WASMExecEnv *exec_env,
|
||||
uint32 *start_offset, uint32 *size);
|
||||
|
||||
bool
|
||||
wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env,
|
||||
uint32 start_offset, uint32 size);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
/* See wasm_export.h for description */
|
||||
void
|
||||
@ -356,6 +377,10 @@ wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst);
|
||||
|
||||
#endif /* end of WASM_ENABLE_LIBC_WASI */
|
||||
|
||||
/* Get module of the current exec_env */
|
||||
WASMModuleCommon*
|
||||
wasm_exec_env_get_module(WASMExecEnv *exec_env);
|
||||
|
||||
/**
|
||||
* Enlarge wasm memory data space.
|
||||
*
|
||||
|
||||
124
core/iwasm/common/wasm_shared_memory.c
Normal file
124
core/iwasm/common/wasm_shared_memory.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
|
||||
#include "bh_log.h"
|
||||
#include "wasm_shared_memory.h"
|
||||
|
||||
static bh_list shared_memory_list_head;
|
||||
static bh_list *const shared_memory_list = &shared_memory_list_head;
|
||||
static korp_mutex shared_memory_list_lock;
|
||||
|
||||
bool
|
||||
wasm_shared_memory_init()
|
||||
{
|
||||
if (os_mutex_init(&shared_memory_list_lock) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_shared_memory_destroy()
|
||||
{
|
||||
os_mutex_destroy(&shared_memory_list_lock);
|
||||
}
|
||||
|
||||
static WASMSharedMemNode*
|
||||
search_module(WASMModuleCommon *module)
|
||||
{
|
||||
WASMSharedMemNode *node;
|
||||
|
||||
os_mutex_lock(&shared_memory_list_lock);
|
||||
node = bh_list_first_elem(shared_memory_list);
|
||||
|
||||
while (node) {
|
||||
if (module == node->module) {
|
||||
os_mutex_unlock(&shared_memory_list_lock);
|
||||
return node;
|
||||
}
|
||||
node = bh_list_elem_next(node);
|
||||
}
|
||||
|
||||
os_mutex_unlock(&shared_memory_list_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WASMSharedMemNode*
|
||||
wasm_module_get_shared_memory(WASMModuleCommon *module)
|
||||
{
|
||||
return search_module(module);
|
||||
}
|
||||
|
||||
int32
|
||||
shared_memory_inc_reference(WASMModuleCommon *module)
|
||||
{
|
||||
WASMSharedMemNode *node = search_module(module);
|
||||
if (node) {
|
||||
os_mutex_lock(&node->lock);
|
||||
node->ref_count++;
|
||||
os_mutex_unlock(&node->lock);
|
||||
return node->ref_count;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32
|
||||
shared_memory_dec_reference(WASMModuleCommon *module)
|
||||
{
|
||||
WASMSharedMemNode *node = search_module(module);
|
||||
uint32 ref_count = 0;
|
||||
if (node) {
|
||||
os_mutex_lock(&node->lock);
|
||||
ref_count = --node->ref_count;
|
||||
os_mutex_unlock(&node->lock);
|
||||
if (ref_count == 0) {
|
||||
os_mutex_lock(&shared_memory_list_lock);
|
||||
bh_list_remove(shared_memory_list, node);
|
||||
os_mutex_unlock(&shared_memory_list_lock);
|
||||
|
||||
os_mutex_destroy(&node->lock);
|
||||
wasm_runtime_free(node);
|
||||
}
|
||||
return ref_count;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
WASMMemoryInstance*
|
||||
shared_memory_get_memory_inst(WASMSharedMemNode *node)
|
||||
{
|
||||
return node->u.wasm_memory;
|
||||
}
|
||||
|
||||
WASMSharedMemNode*
|
||||
shared_memory_set_memory_inst(WASMModuleCommon *module,
|
||||
WASMMemoryInstance *memory)
|
||||
{
|
||||
WASMSharedMemNode *node;
|
||||
bh_list_status ret;
|
||||
|
||||
if (!(node = wasm_runtime_malloc(sizeof(WASMSharedMemNode))))
|
||||
return NULL;
|
||||
|
||||
node->module = module;
|
||||
node->u.wasm_memory = memory;
|
||||
node->ref_count = 1;
|
||||
if (os_mutex_init(&node->lock) != 0) {
|
||||
wasm_runtime_free(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_mutex_lock(&shared_memory_list_lock);
|
||||
ret = bh_list_insert(shared_memory_list, node);
|
||||
bh_assert(ret == BH_LIST_SUCCESS);
|
||||
os_mutex_unlock(&shared_memory_list_lock);
|
||||
|
||||
(void)ret;
|
||||
return node;
|
||||
}
|
||||
|
||||
#endif /* end of WASM_ENABLE_SHARED_MEMORY */
|
||||
82
core/iwasm/common/wasm_shared_memory.h
Normal file
82
core/iwasm/common/wasm_shared_memory.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _WASM_SHARED_MEMORY_H
|
||||
#define _WASM_SHARED_MEMORY_H
|
||||
|
||||
#include "bh_common.h"
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
#include "wasm_runtime.h"
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
#include "aot_runtime.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct WASMSharedMemNode {
|
||||
bh_list_link l;
|
||||
/* Lock */
|
||||
korp_mutex lock;
|
||||
/* The module reference */
|
||||
WASMModuleCommon *module;
|
||||
/* The memory information */
|
||||
union {
|
||||
#if WASM_ENABLE_INTERP
|
||||
WASMMemoryInstance *wasm_memory;
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT
|
||||
struct {
|
||||
/* memory space info */
|
||||
uint32 mem_cur_page_count;
|
||||
uint32 mem_max_page_count;
|
||||
uint32 memory_data_size;
|
||||
AOTPointer memory_data;
|
||||
AOTPointer memory_data_end;
|
||||
|
||||
/* heap space info */
|
||||
int32 heap_base_offset;
|
||||
uint32 heap_data_size;
|
||||
AOTPointer heap_data;
|
||||
AOTPointer heap_data_end;
|
||||
AOTPointer heap_handle;
|
||||
} aot_memory;
|
||||
#endif
|
||||
} u;
|
||||
|
||||
/* reference count */
|
||||
uint32 ref_count;
|
||||
} WASMSharedMemNode;
|
||||
|
||||
bool
|
||||
wasm_shared_memory_init();
|
||||
|
||||
void
|
||||
wasm_shared_memory_destroy();
|
||||
|
||||
WASMSharedMemNode*
|
||||
wasm_module_get_shared_memory(WASMModuleCommon *module);
|
||||
|
||||
int32
|
||||
shared_memory_inc_reference(WASMModuleCommon *module);
|
||||
|
||||
int32
|
||||
shared_memory_dec_reference(WASMModuleCommon *module);
|
||||
|
||||
WASMMemoryInstance*
|
||||
shared_memory_get_memory_inst(WASMSharedMemNode *node);
|
||||
|
||||
WASMSharedMemNode*
|
||||
shared_memory_set_memory_inst(WASMModuleCommon *module,
|
||||
WASMMemoryInstance *memory);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* end of _WASM_SHARED_MEMORY_H */
|
||||
@ -319,7 +319,7 @@ wasm_runtime_lookup_wasi_start_function(wasm_module_inst_t module_inst);
|
||||
* @param name the name of the function
|
||||
* @param signature the signature of the function, ignored currently
|
||||
*
|
||||
* @return the function instance found. Otherwise NULL will be returned.
|
||||
* @return the function instance found, NULL if not found
|
||||
*/
|
||||
wasm_function_inst_t
|
||||
wasm_runtime_lookup_function(wasm_module_inst_t const module_inst,
|
||||
@ -331,7 +331,8 @@ wasm_runtime_lookup_function(wasm_module_inst_t const module_inst,
|
||||
* @param module_inst the module instance
|
||||
* @param stack_size the stack size to execute a WASM function
|
||||
*
|
||||
* @return the execution environment. In case of invalid stack size, NULL will be returned.
|
||||
* @return the execution environment, NULL if failed, e.g. invalid
|
||||
* stack size is passed
|
||||
*/
|
||||
wasm_exec_env_t
|
||||
wasm_runtime_create_exec_env(wasm_module_inst_t module_inst,
|
||||
@ -386,7 +387,7 @@ wasm_runtime_call_wasm(wasm_exec_env_t exec_env,
|
||||
* @param argv the arguments array
|
||||
*
|
||||
* @return true if the main function is called, false otherwise and exception
|
||||
* will be thrown, the caller can call wasm_runtime_get_exception to get
|
||||
* will be thrown, the caller can call wasm_runtime_get_exception to get
|
||||
* the exception info.
|
||||
*/
|
||||
bool
|
||||
@ -679,6 +680,16 @@ wasm_runtime_set_user_data(wasm_exec_env_t exec_env,
|
||||
void *
|
||||
wasm_runtime_get_user_data(wasm_exec_env_t exec_env);
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
/**
|
||||
* Set the max thread num per cluster.
|
||||
*
|
||||
* @param num maximum thread num
|
||||
*/
|
||||
void
|
||||
wasm_runtime_set_max_thread_num(uint32_t num);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -939,6 +939,18 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
#define CHECK_SUSPEND_FLAGS() do { \
|
||||
if (exec_env->suspend_flags != 0) { \
|
||||
if (exec_env->suspend_flags & 0x01) { \
|
||||
/* terminate current thread */ \
|
||||
return; \
|
||||
} \
|
||||
/* TODO: support suspend and breakpoint */ \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LABELS_AS_VALUES != 0
|
||||
|
||||
#define HANDLE_OP(opcode) HANDLE_##opcode
|
||||
@ -989,6 +1001,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
uint32 local_idx, local_offset, global_idx;
|
||||
uint8 local_type, *global_addr;
|
||||
uint32 cache_index;
|
||||
int32 aux_stack_top_global_idx = -1;
|
||||
|
||||
/* If the aux stack information is resolved,
|
||||
we will check the aux stack boundary */
|
||||
if (module->module->llvm_aux_stack_size) {
|
||||
aux_stack_top_global_idx = module->module->llvm_aux_stack_global_index;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_LABELS_AS_VALUES != 0
|
||||
#define HANDLE_OPCODE(op) &&HANDLE_##op
|
||||
@ -1103,11 +1122,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
HANDLE_OP_END ();
|
||||
|
||||
HANDLE_OP (WASM_OP_BR):
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
read_leb_uint32(frame_ip, frame_ip_end, depth);
|
||||
POP_CSP_N(depth);
|
||||
HANDLE_OP_END ();
|
||||
|
||||
HANDLE_OP (WASM_OP_BR_IF):
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
read_leb_uint32(frame_ip, frame_ip_end, depth);
|
||||
cond = (uint32)POP_I32();
|
||||
if (cond)
|
||||
@ -1115,6 +1140,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
HANDLE_OP_END ();
|
||||
|
||||
HANDLE_OP (WASM_OP_BR_TABLE):
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
read_leb_uint32(frame_ip, frame_ip_end, count);
|
||||
if (count <= BR_TABLE_TMP_BUF_LEN)
|
||||
depths = depth_buf;
|
||||
@ -1150,6 +1178,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
goto return_func;
|
||||
|
||||
HANDLE_OP (WASM_OP_CALL):
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
read_leb_uint32(frame_ip, frame_ip_end, fidx);
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (fidx >= module->function_count) {
|
||||
@ -1166,6 +1197,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
WASMType *cur_type, *cur_func_type;
|
||||
WASMTableInstance *cur_table_inst;
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* type check. compiler will make sure all like
|
||||
* (call_indirect (type $x) (i32.const 1))
|
||||
@ -1406,6 +1441,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
|
||||
switch (global->type) {
|
||||
case VALUE_TYPE_I32:
|
||||
/* Check aux stack boundary */
|
||||
if ((global_idx == (uint32)aux_stack_top_global_idx)
|
||||
&& (*(uint32*)(frame_sp - 1) < exec_env->aux_stack_boundary))
|
||||
goto out_of_bounds;
|
||||
case VALUE_TYPE_F32:
|
||||
*(int32*)global_addr = POP_I32();
|
||||
break;
|
||||
|
||||
@ -877,6 +877,18 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
#define CHECK_SUSPEND_FLAGS() do { \
|
||||
if (exec_env->suspend_flags != 0) { \
|
||||
if (exec_env->suspend_flags & 0x01) { \
|
||||
/* terminate current thread */ \
|
||||
return; \
|
||||
} \
|
||||
/* TODO: support suspend and breakpoint */ \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_OPCODE_COUNTER != 0
|
||||
typedef struct OpcodeInfo {
|
||||
char *name;
|
||||
@ -978,6 +990,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
uint8 *maddr = NULL;
|
||||
uint32 local_idx, local_offset, global_idx;
|
||||
uint8 opcode, local_type, *global_addr;
|
||||
int32 aux_stack_top_global_idx = -1;
|
||||
|
||||
#if WASM_ENABLE_LABELS_AS_VALUES != 0
|
||||
#define HANDLE_OPCODE(op) &&HANDLE_##op
|
||||
@ -991,6 +1004,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* If the aux stack information is resolved,
|
||||
we will check the aux stack boundary */
|
||||
if (module->module->llvm_aux_stack_size) {
|
||||
aux_stack_top_global_idx = module->module->llvm_aux_stack_global_index;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_LABELS_AS_VALUES == 0
|
||||
while (frame_ip < frame_ip_end) {
|
||||
opcode = *frame_ip++;
|
||||
@ -1024,10 +1043,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
HANDLE_OP_END ();
|
||||
|
||||
HANDLE_OP (WASM_OP_BR):
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
RECOVER_BR_INFO();
|
||||
HANDLE_OP_END ();
|
||||
|
||||
HANDLE_OP (WASM_OP_BR_IF):
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
cond = frame_lp[GET_OFFSET()];
|
||||
|
||||
if (cond)
|
||||
@ -1039,6 +1064,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
HANDLE_OP_END ();
|
||||
|
||||
HANDLE_OP (WASM_OP_BR_TABLE):
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
count = GET_OPERAND(uint32, 0);
|
||||
didx = GET_OPERAND(uint32, 2);
|
||||
frame_ip += 4;
|
||||
@ -1064,6 +1092,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
WASMType *cur_type, *cur_func_type;
|
||||
WASMTableInstance *cur_table_inst;
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
|
||||
tidx = GET_OPERAND(int32, 0);
|
||||
val = GET_OPERAND(int32, 2);
|
||||
frame_ip += 4;
|
||||
@ -1245,6 +1277,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
|
||||
switch (global->type) {
|
||||
case VALUE_TYPE_I32:
|
||||
/* Check aux stack boundary */
|
||||
if ((global_idx == (uint32)aux_stack_top_global_idx)
|
||||
&& (frame_lp[addr1] < exec_env->aux_stack_boundary))
|
||||
goto out_of_bounds;
|
||||
case VALUE_TYPE_F32:
|
||||
*(int32*)global_addr = frame_lp[addr1];
|
||||
break;
|
||||
@ -2482,6 +2518,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
goto call_func_from_entry;
|
||||
|
||||
HANDLE_OP (WASM_OP_CALL):
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
fidx = frame_lp[GET_OFFSET()];
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (fidx >= module->function_count) {
|
||||
|
||||
@ -1117,6 +1117,12 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table,
|
||||
else
|
||||
table->max_size = 0x10000;
|
||||
|
||||
if ((table->flags & 1) && table->init_size > table->max_size) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"size minimum must not be greater than maximum");
|
||||
return false;
|
||||
}
|
||||
|
||||
*p_buf = p;
|
||||
return true;
|
||||
}
|
||||
@ -2349,8 +2355,6 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
WASMGlobal *llvm_stack_top_global = NULL, *global;
|
||||
uint32 llvm_data_end = UINT32_MAX, llvm_heap_base = UINT32_MAX;
|
||||
uint32 llvm_stack_top = UINT32_MAX, global_index, i;
|
||||
uint32 data_end_global_index = UINT32_MAX;
|
||||
uint32 heap_base_global_index = UINT32_MAX;
|
||||
uint32 stack_top_global_index = UINT32_MAX;
|
||||
BlockAddr *block_addr_cache;
|
||||
uint64 total_size;
|
||||
@ -2462,67 +2466,93 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
wasm_runtime_free(block_addr_cache);
|
||||
|
||||
/* Resolve llvm auxiliary data/stack/heap info and reset memory info */
|
||||
if (!module->possible_memory_grow) {
|
||||
export = module->exports;
|
||||
for (i = 0; i < module->export_count; i++, export++) {
|
||||
if (export->kind == EXPORT_KIND_GLOBAL) {
|
||||
if (!strcmp(export->name, "__heap_base")) {
|
||||
global_index = export->index - module->import_global_count;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
heap_base_global_index = global_index;
|
||||
llvm_heap_base_global = global;
|
||||
llvm_heap_base = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __heap_base global, value: %d\n",
|
||||
llvm_heap_base);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(export->name, "__data_end")) {
|
||||
global_index = export->index - module->import_global_count;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
data_end_global_index = global_index;
|
||||
llvm_data_end_global = global;
|
||||
llvm_data_end = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __data_end global, value: %d\n",
|
||||
llvm_data_end);
|
||||
|
||||
llvm_data_end = align_uint(llvm_data_end, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (llvm_data_end_global && llvm_heap_base_global) {
|
||||
if ((data_end_global_index == heap_base_global_index + 1
|
||||
&& (int32)data_end_global_index > 1)
|
||||
|| (heap_base_global_index == data_end_global_index + 1
|
||||
&& (int32)heap_base_global_index > 1)) {
|
||||
global_index =
|
||||
data_end_global_index < heap_base_global_index
|
||||
? data_end_global_index - 1 : heap_base_global_index - 1;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
llvm_stack_top_global = global;
|
||||
llvm_stack_top = global->init_expr.u.i32;
|
||||
stack_top_global_index = global_index;
|
||||
LOG_VERBOSE("found llvm stack top global, "
|
||||
"value: %d, global index: %d\n",
|
||||
llvm_stack_top, global_index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
export = module->exports;
|
||||
for (i = 0; i < module->export_count; i++, export++) {
|
||||
if (export->kind == EXPORT_KIND_GLOBAL) {
|
||||
if (!strcmp(export->name, "__heap_base")) {
|
||||
global_index = export->index - module->import_global_count;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
llvm_heap_base_global = global;
|
||||
llvm_heap_base = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __heap_base global, value: %d\n",
|
||||
llvm_heap_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(export->name, "__data_end")) {
|
||||
global_index = export->index - module->import_global_count;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
llvm_data_end_global = global;
|
||||
llvm_data_end = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __data_end global, value: %d\n",
|
||||
llvm_data_end);
|
||||
|
||||
llvm_data_end = align_uint(llvm_data_end, 16);
|
||||
}
|
||||
}
|
||||
|
||||
/* For module compiled with -pthread option, the global is:
|
||||
[0] stack_top <-- 0
|
||||
[1] tls_pointer
|
||||
[2] tls_size
|
||||
[3] data_end <-- 3
|
||||
[4] global_base
|
||||
[5] heap_base <-- 5
|
||||
[6] dso_handle
|
||||
|
||||
For module compiled without -pthread option:
|
||||
[0] stack_top <-- 0
|
||||
[1] data_end <-- 1
|
||||
[2] global_base
|
||||
[3] heap_base <-- 3
|
||||
[4] dso_handle
|
||||
*/
|
||||
if (llvm_data_end_global && llvm_heap_base_global) {
|
||||
/* Resolve aux stack top global */
|
||||
for (global_index = 0; global_index < module->global_count; global_index++) {
|
||||
global = module->globals + global_index;
|
||||
if (global != llvm_data_end_global
|
||||
&& global != llvm_heap_base_global
|
||||
&& global->type == VALUE_TYPE_I32
|
||||
&& global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST
|
||||
&& (global->init_expr.u.i32 ==
|
||||
llvm_heap_base_global->init_expr.u.i32
|
||||
|| global->init_expr.u.i32 ==
|
||||
llvm_data_end_global->init_expr.u.i32)) {
|
||||
llvm_stack_top_global = global;
|
||||
llvm_stack_top = global->init_expr.u.i32;
|
||||
stack_top_global_index = global_index;
|
||||
LOG_VERBOSE("found llvm stack top global, "
|
||||
"value: %d, global index: %d\n",
|
||||
llvm_stack_top, global_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
module->llvm_aux_data_end = llvm_data_end;
|
||||
module->llvm_aux_stack_bottom = llvm_stack_top;
|
||||
module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end
|
||||
? llvm_stack_top - llvm_data_end
|
||||
: llvm_stack_top;
|
||||
module->llvm_aux_stack_global_index = stack_top_global_index;
|
||||
LOG_VERBOSE("aux stack bottom: %d, size: %d\n",
|
||||
module->llvm_aux_stack_bottom,
|
||||
module->llvm_aux_stack_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!module->possible_memory_grow) {
|
||||
if (llvm_data_end_global
|
||||
&& llvm_heap_base_global
|
||||
&& llvm_stack_top_global
|
||||
@ -2557,16 +2587,6 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size);
|
||||
}
|
||||
}
|
||||
|
||||
module->llvm_aux_data_end = llvm_data_end;
|
||||
module->llvm_aux_stack_bottom = llvm_stack_top;
|
||||
module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end
|
||||
? llvm_stack_top - llvm_data_end
|
||||
: llvm_stack_top;
|
||||
module->llvm_aux_stack_global_index = stack_top_global_index;
|
||||
LOG_VERBOSE("aux stack bottom: %d, size: %d\n",
|
||||
module->llvm_aux_stack_bottom,
|
||||
module->llvm_aux_stack_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3485,6 +3505,7 @@ fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
|
||||
@ -1545,67 +1545,76 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
wasm_runtime_free(block_addr_cache);
|
||||
|
||||
/* Resolve llvm auxiliary data/stack/heap info and reset memory info */
|
||||
if (!module->possible_memory_grow) {
|
||||
export = module->exports;
|
||||
for (i = 0; i < module->export_count; i++, export++) {
|
||||
if (export->kind == EXPORT_KIND_GLOBAL) {
|
||||
if (!strcmp(export->name, "__heap_base")) {
|
||||
global_index = export->index - module->import_global_count;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
heap_base_global_index = global_index;
|
||||
llvm_heap_base_global = global;
|
||||
llvm_heap_base = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __heap_base global, value: %d\n",
|
||||
llvm_heap_base);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(export->name, "__data_end")) {
|
||||
global_index = export->index - module->import_global_count;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
data_end_global_index = global_index;
|
||||
llvm_data_end_global = global;
|
||||
llvm_data_end = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __data_end global, value: %d\n",
|
||||
llvm_data_end);
|
||||
|
||||
llvm_data_end = align_uint(llvm_data_end, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (llvm_data_end_global && llvm_heap_base_global) {
|
||||
if ((data_end_global_index == heap_base_global_index + 1
|
||||
&& (int32)data_end_global_index > 1)
|
||||
|| (heap_base_global_index == data_end_global_index + 1
|
||||
&& (int32)heap_base_global_index > 1)) {
|
||||
global_index =
|
||||
data_end_global_index < heap_base_global_index
|
||||
? data_end_global_index - 1 : heap_base_global_index - 1;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
llvm_stack_top_global = global;
|
||||
llvm_stack_top = global->init_expr.u.i32;
|
||||
stack_top_global_index = global_index;
|
||||
LOG_VERBOSE("found llvm stack top global, "
|
||||
"value: %d, global index: %d\n",
|
||||
llvm_stack_top, global_index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
export = module->exports;
|
||||
for (i = 0; i < module->export_count; i++, export++) {
|
||||
if (export->kind == EXPORT_KIND_GLOBAL) {
|
||||
if (!strcmp(export->name, "__heap_base")) {
|
||||
global_index = export->index - module->import_global_count;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
heap_base_global_index = global_index;
|
||||
llvm_heap_base_global = global;
|
||||
llvm_heap_base = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __heap_base global, value: %d\n",
|
||||
llvm_heap_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(export->name, "__data_end")) {
|
||||
global_index = export->index - module->import_global_count;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
data_end_global_index = global_index;
|
||||
llvm_data_end_global = global;
|
||||
llvm_data_end = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __data_end global, value: %d\n",
|
||||
llvm_data_end);
|
||||
|
||||
llvm_data_end = align_uint(llvm_data_end, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (llvm_data_end_global && llvm_heap_base_global) {
|
||||
if ((data_end_global_index == heap_base_global_index + 1
|
||||
&& (int32)data_end_global_index > 1)
|
||||
|| (heap_base_global_index == data_end_global_index + 1
|
||||
&& (int32)heap_base_global_index > 1)) {
|
||||
global_index =
|
||||
data_end_global_index < heap_base_global_index
|
||||
? data_end_global_index - 1 : heap_base_global_index - 1;
|
||||
global = module->globals + global_index;
|
||||
if (global->type == VALUE_TYPE_I32
|
||||
&& global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
llvm_stack_top_global = global;
|
||||
llvm_stack_top = global->init_expr.u.i32;
|
||||
stack_top_global_index = global_index;
|
||||
LOG_VERBOSE("found llvm stack top global, "
|
||||
"value: %d, global index: %d\n",
|
||||
llvm_stack_top, global_index);
|
||||
}
|
||||
}
|
||||
module->llvm_aux_data_end = llvm_data_end;
|
||||
module->llvm_aux_stack_bottom = llvm_stack_top;
|
||||
module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end
|
||||
? llvm_stack_top - llvm_data_end
|
||||
: llvm_stack_top;
|
||||
module->llvm_aux_stack_global_index = stack_top_global_index;
|
||||
LOG_VERBOSE("aux stack bottom: %d, size: %d\n",
|
||||
module->llvm_aux_stack_bottom,
|
||||
module->llvm_aux_stack_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!module->possible_memory_grow) {
|
||||
if (llvm_data_end_global
|
||||
&& llvm_heap_base_global
|
||||
&& llvm_stack_top_global
|
||||
@ -1640,16 +1649,6 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size);
|
||||
}
|
||||
}
|
||||
|
||||
module->llvm_aux_data_end = llvm_data_end;
|
||||
module->llvm_aux_stack_bottom = llvm_stack_top;
|
||||
module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end
|
||||
? llvm_stack_top - llvm_data_end
|
||||
: llvm_stack_top;
|
||||
module->llvm_aux_stack_global_index = stack_top_global_index;
|
||||
LOG_VERBOSE("aux stack bottom: %d, size: %d\n",
|
||||
module->llvm_aux_stack_bottom,
|
||||
module->llvm_aux_stack_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
#include "bh_log.h"
|
||||
#include "mem_alloc.h"
|
||||
#include "../common/wasm_runtime_common.h"
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
#include "../common/wasm_shared_memory.h"
|
||||
#endif
|
||||
|
||||
static void
|
||||
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
|
||||
@ -86,6 +89,19 @@ memories_deinstantiate(WASMModuleInstance *module_inst,
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (memories[i]->owner != module_inst)
|
||||
continue;
|
||||
#endif
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (memories[i]->is_shared) {
|
||||
int32 ref_count =
|
||||
shared_memory_dec_reference(
|
||||
(WASMModuleCommon *)module_inst->module);
|
||||
bh_assert(ref_count >= 0);
|
||||
|
||||
/* if the reference count is not zero,
|
||||
don't free the memory */
|
||||
if (ref_count > 0)
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (memories[i]->heap_handle) {
|
||||
mem_allocator_destroy(memories[i]->heap_handle);
|
||||
@ -99,16 +115,45 @@ memories_deinstantiate(WASMModuleInstance *module_inst,
|
||||
}
|
||||
|
||||
static WASMMemoryInstance*
|
||||
memory_instantiate(uint32 num_bytes_per_page,
|
||||
memory_instantiate(WASMModuleInstance *module_inst,
|
||||
uint32 num_bytes_per_page,
|
||||
uint32 init_page_count, uint32 max_page_count,
|
||||
uint32 heap_size,
|
||||
uint32 heap_size, uint32 flags,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
WASMMemoryInstance *memory;
|
||||
uint64 total_size = offsetof(WASMMemoryInstance, base_addr) +
|
||||
(uint64)heap_size +
|
||||
uint64 heap_and_inst_size = offsetof(WASMMemoryInstance, base_addr) +
|
||||
(uint64)heap_size;
|
||||
uint64 total_size = heap_and_inst_size +
|
||||
num_bytes_per_page * (uint64)init_page_count;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
bool is_shared_memory = flags & 0x02 ? true : false;
|
||||
|
||||
/* shared memory */
|
||||
if (is_shared_memory) {
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory(
|
||||
(WASMModuleCommon *)module_inst->module);
|
||||
/* If the memory of this module has been instantiated,
|
||||
return the memory instance directly */
|
||||
if (node) {
|
||||
uint32 ref_count;
|
||||
ref_count = shared_memory_inc_reference(
|
||||
(WASMModuleCommon *)module_inst->module);
|
||||
bh_assert(ref_count > 0);
|
||||
memory = shared_memory_get_memory_inst(node);
|
||||
bh_assert(memory);
|
||||
|
||||
(void)ref_count;
|
||||
return memory;
|
||||
}
|
||||
/* Allocate max page for shared memory */
|
||||
total_size = heap_and_inst_size +
|
||||
num_bytes_per_page * (uint64)max_page_count;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Allocate memory space, addr data and global data */
|
||||
if (!(memory = runtime_malloc(total_size,
|
||||
error_buf, error_buf_size))) {
|
||||
@ -121,8 +166,17 @@ memory_instantiate(uint32 num_bytes_per_page,
|
||||
|
||||
memory->heap_data = memory->base_addr;
|
||||
memory->memory_data = memory->heap_data + heap_size;
|
||||
memory->end_addr = memory->memory_data +
|
||||
num_bytes_per_page * memory->cur_page_count;
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (is_shared_memory) {
|
||||
memory->end_addr = memory->memory_data +
|
||||
num_bytes_per_page * memory->max_page_count;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
memory->end_addr = memory->memory_data +
|
||||
num_bytes_per_page * memory->cur_page_count;
|
||||
}
|
||||
|
||||
bh_assert(memory->end_addr - (uint8*)memory == (uint32)total_size);
|
||||
|
||||
@ -134,10 +188,20 @@ memory_instantiate(uint32 num_bytes_per_page,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_SPEC_TEST == 0
|
||||
memory->heap_base_offset = -(int32)heap_size;
|
||||
#else
|
||||
memory->heap_base_offset = 0;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (is_shared_memory) {
|
||||
memory->is_shared = true;
|
||||
if (!shared_memory_set_memory_inst(
|
||||
(WASMModuleCommon *)module_inst->module, memory)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed:"
|
||||
"allocate memory failed.");
|
||||
wasm_runtime_free(memory);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return memory;
|
||||
}
|
||||
@ -169,6 +233,7 @@ memories_instantiate(const WASMModule *module,
|
||||
uint32 num_bytes_per_page = import->u.memory.num_bytes_per_page;
|
||||
uint32 init_page_count = import->u.memory.init_page_count;
|
||||
uint32 max_page_count = import->u.memory.max_page_count;
|
||||
uint32 flags = import->u.memory.flags;
|
||||
uint32 actual_heap_size = heap_size;
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
@ -197,8 +262,9 @@ memories_instantiate(const WASMModule *module,
|
||||
#endif
|
||||
{
|
||||
if (!(memory = memories[mem_index++] = memory_instantiate(
|
||||
num_bytes_per_page, init_page_count, max_page_count,
|
||||
actual_heap_size, error_buf, error_buf_size))) {
|
||||
module_inst, num_bytes_per_page, init_page_count,
|
||||
max_page_count, actual_heap_size, flags,
|
||||
error_buf, error_buf_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed: "
|
||||
"allocate memory failed.");
|
||||
@ -213,10 +279,12 @@ memories_instantiate(const WASMModule *module,
|
||||
/* instantiate memories from memory section */
|
||||
for (i = 0; i < module->memory_count; i++) {
|
||||
if (!(memory = memories[mem_index++] =
|
||||
memory_instantiate(module->memories[i].num_bytes_per_page,
|
||||
memory_instantiate(module_inst,
|
||||
module->memories[i].num_bytes_per_page,
|
||||
module->memories[i].init_page_count,
|
||||
module->memories[i].max_page_count,
|
||||
heap_size, error_buf, error_buf_size))) {
|
||||
heap_size, module->memories[i].flags,
|
||||
error_buf, error_buf_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed: "
|
||||
"allocate memory failed.");
|
||||
@ -236,7 +304,7 @@ memories_instantiate(const WASMModule *module,
|
||||
* for wasm code
|
||||
*/
|
||||
if (!(memory = memories[mem_index++] =
|
||||
memory_instantiate(0, 0, 0, heap_size,
|
||||
memory_instantiate(module_inst, 0, 0, 0, heap_size, 0,
|
||||
error_buf, error_buf_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed: "
|
||||
@ -792,6 +860,36 @@ execute_post_inst_function(WASMModuleInstance *module_inst)
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
static bool
|
||||
execute_memory_init_function(WASMModuleInstance *module_inst)
|
||||
{
|
||||
WASMFunctionInstance *memory_init_func = NULL;
|
||||
WASMType *memory_init_func_type;
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < module_inst->export_func_count; i++)
|
||||
if (!strcmp(module_inst->export_functions[i].name, "__wasm_call_ctors")) {
|
||||
memory_init_func = module_inst->export_functions[i].function;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!memory_init_func)
|
||||
/* Not found */
|
||||
return true;
|
||||
|
||||
memory_init_func_type = memory_init_func->u.func->func_type;
|
||||
if (memory_init_func_type->param_count != 0
|
||||
|| memory_init_func_type->result_count != 0)
|
||||
/* Not a valid function type, ignore it */
|
||||
return true;
|
||||
|
||||
return wasm_create_exec_env_and_call_function(module_inst,
|
||||
memory_init_func,
|
||||
0, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
execute_start_function(WASMModuleInstance *module_inst)
|
||||
{
|
||||
@ -819,7 +917,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst,
|
||||
while (sub_module_list_node) {
|
||||
WASMModule *sub_module = (WASMModule*)sub_module_list_node->module;
|
||||
WASMModuleInstance *sub_module_inst = wasm_instantiate(
|
||||
sub_module, stack_size, heap_size, error_buf, error_buf_size);
|
||||
sub_module, false, stack_size, heap_size, error_buf, error_buf_size);
|
||||
if (!sub_module_inst) {
|
||||
LOG_DEBUG("instantiate %s failed",
|
||||
sub_module_list_node->module_name);
|
||||
@ -833,7 +931,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst,
|
||||
if (!sub_module_inst_list_node) {
|
||||
LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d",
|
||||
sizeof(WASMSubModInstNode));
|
||||
wasm_deinstantiate(sub_module_inst);
|
||||
wasm_deinstantiate(sub_module_inst, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -859,7 +957,7 @@ sub_module_deinstantiate(WASMModuleInstance *module_inst)
|
||||
while (node) {
|
||||
WASMSubModInstNode *next_node = bh_list_elem_next(node);
|
||||
bh_list_remove(list, node);
|
||||
wasm_deinstantiate(node->module_inst);
|
||||
wasm_deinstantiate(node->module_inst, false);
|
||||
node = next_node;
|
||||
}
|
||||
}
|
||||
@ -869,7 +967,7 @@ sub_module_deinstantiate(WASMModuleInstance *module_inst)
|
||||
* Instantiate module
|
||||
*/
|
||||
WASMModuleInstance*
|
||||
wasm_instantiate(WASMModule *module,
|
||||
wasm_instantiate(WASMModule *module, bool is_sub_inst,
|
||||
uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
@ -887,10 +985,6 @@ wasm_instantiate(WASMModule *module,
|
||||
|
||||
/* Check heap size */
|
||||
heap_size = align_uint(heap_size, 8);
|
||||
if (heap_size == 0)
|
||||
heap_size = APP_HEAP_SIZE_DEFAULT;
|
||||
if (heap_size < APP_HEAP_SIZE_MIN)
|
||||
heap_size = APP_HEAP_SIZE_MIN;
|
||||
if (heap_size > APP_HEAP_SIZE_MAX)
|
||||
heap_size = APP_HEAP_SIZE_MAX;
|
||||
|
||||
@ -904,6 +998,8 @@ wasm_instantiate(WASMModule *module,
|
||||
|
||||
memset(module_inst, 0, (uint32)sizeof(WASMModuleInstance));
|
||||
|
||||
module_inst->module = module;
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
module_inst->sub_module_inst_list =
|
||||
&module_inst->sub_module_inst_list_head;
|
||||
@ -911,7 +1007,7 @@ wasm_instantiate(WASMModule *module,
|
||||
error_buf, error_buf_size);
|
||||
if (!ret) {
|
||||
LOG_DEBUG("build a sub module list failed");
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@ -922,7 +1018,7 @@ wasm_instantiate(WASMModule *module,
|
||||
module,
|
||||
module_inst,
|
||||
&global_data_size, error_buf, error_buf_size))) {
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
module_inst->global_count = global_count;
|
||||
@ -946,7 +1042,7 @@ wasm_instantiate(WASMModule *module,
|
||||
if (global_count > 0) {
|
||||
if (!(module_inst->global_data = runtime_malloc
|
||||
(global_data_size, error_buf, error_buf_size))) {
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -978,7 +1074,7 @@ wasm_instantiate(WASMModule *module,
|
||||
error_buf, error_buf_size)))
|
||||
#endif
|
||||
) {
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -989,7 +1085,7 @@ wasm_instantiate(WASMModule *module,
|
||||
*/
|
||||
if (!globals_instantiate_fix(globals, module,
|
||||
error_buf, error_buf_size)) {
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1063,7 +1159,7 @@ wasm_instantiate(WASMModule *module,
|
||||
memory_size);
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"data segment does not fit.");
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1075,7 +1171,7 @@ wasm_instantiate(WASMModule *module,
|
||||
set_error_buf(
|
||||
error_buf, error_buf_size,
|
||||
"Instantiate module failed: data segment does not fit.");
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1121,7 +1217,7 @@ wasm_instantiate(WASMModule *module,
|
||||
table_seg->base_offset.u.i32, table->cur_size);
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"elements segment does not fit");
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1132,7 +1228,7 @@ wasm_instantiate(WASMModule *module,
|
||||
table_seg->base_offset.u.i32, length, table->cur_size);
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"elements segment does not fit");
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1149,18 +1245,22 @@ wasm_instantiate(WASMModule *module,
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
if (!wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst,
|
||||
module->wasi_args.dir_list,
|
||||
module->wasi_args.dir_count,
|
||||
module->wasi_args.map_dir_list,
|
||||
module->wasi_args.map_dir_count,
|
||||
module->wasi_args.env,
|
||||
module->wasi_args.env_count,
|
||||
module->wasi_args.argv,
|
||||
module->wasi_args.argc,
|
||||
error_buf, error_buf_size)) {
|
||||
wasm_deinstantiate(module_inst);
|
||||
return NULL;
|
||||
/* The sub-instance will get the wasi_ctx from main-instance */
|
||||
if (!is_sub_inst) {
|
||||
if (heap_size > 0
|
||||
&& !wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst,
|
||||
module->wasi_args.dir_list,
|
||||
module->wasi_args.dir_count,
|
||||
module->wasi_args.map_dir_list,
|
||||
module->wasi_args.map_dir_count,
|
||||
module->wasi_args.env,
|
||||
module->wasi_args.env_count,
|
||||
module->wasi_args.argv,
|
||||
module->wasi_args.argc,
|
||||
error_buf, error_buf_size)) {
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1171,8 +1271,6 @@ wasm_instantiate(WASMModule *module,
|
||||
&module_inst->functions[module->start_function];
|
||||
}
|
||||
|
||||
module_inst->module = module;
|
||||
|
||||
/* module instance type */
|
||||
module_inst->module_type = Wasm_Module_Bytecode;
|
||||
|
||||
@ -1190,16 +1288,36 @@ wasm_instantiate(WASMModule *module,
|
||||
|| !execute_start_function(module_inst)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
module_inst->cur_exception);
|
||||
wasm_deinstantiate(module_inst);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
if (!module->is_wasi_module) {
|
||||
#endif
|
||||
/* Only execute the memory init function for main instance because
|
||||
the data segments will be dropped once initialized.
|
||||
*/
|
||||
if (!is_sub_inst) {
|
||||
if (!execute_memory_init_function(module_inst)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
module_inst->cur_exception);
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
(void)global_data_end;
|
||||
return module_inst;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_deinstantiate(WASMModuleInstance *module_inst)
|
||||
wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
|
||||
{
|
||||
if (!module_inst)
|
||||
return;
|
||||
@ -1213,7 +1331,9 @@ wasm_deinstantiate(WASMModuleInstance *module_inst)
|
||||
wasi contex are allocated from app heap, and if app heap is freed,
|
||||
these fields will be set to NULL, we cannot free their internal data
|
||||
which may allocated from global heap. */
|
||||
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst);
|
||||
/* Only destroy wasi ctx in the main module instance */
|
||||
if (!is_sub_inst)
|
||||
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst);
|
||||
#endif
|
||||
|
||||
if (module_inst->memory_count > 0)
|
||||
@ -1299,8 +1419,9 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
|
||||
WASMExecEnv *exec_env;
|
||||
bool ret;
|
||||
|
||||
if (!(exec_env = wasm_exec_env_create((WASMModuleInstanceCommon*)module_inst,
|
||||
module_inst->default_wasm_stack_size))) {
|
||||
if (!(exec_env = wasm_exec_env_create(
|
||||
(WASMModuleInstanceCommon*)module_inst,
|
||||
module_inst->default_wasm_stack_size))) {
|
||||
wasm_set_exception(module_inst, "allocate memory failed.");
|
||||
return false;
|
||||
}
|
||||
@ -1518,6 +1639,15 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (memory->is_shared) {
|
||||
/* For shared memory, we have reserved the maximum spaces during
|
||||
instantiate, only change the cur_page_count here */
|
||||
memory->cur_page_count = total_page_count;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (heap_size > 0) {
|
||||
/* Destroy heap's lock firstly, if its memory is re-allocated,
|
||||
we cannot access its lock again. */
|
||||
@ -1612,3 +1742,66 @@ wasm_call_indirect(WASMExecEnv *exec_env,
|
||||
got_exception:
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
bool
|
||||
wasm_set_aux_stack(WASMExecEnv *exec_env,
|
||||
uint32 start_offset, uint32 size)
|
||||
{
|
||||
WASMModuleInstance *module_inst =
|
||||
(WASMModuleInstance*)exec_env->module_inst;
|
||||
|
||||
uint32 stack_top_idx =
|
||||
module_inst->module->llvm_aux_stack_global_index;
|
||||
uint32 data_end =
|
||||
module_inst->module->llvm_aux_data_end;
|
||||
uint32 stack_bottom =
|
||||
module_inst->module->llvm_aux_stack_bottom;
|
||||
bool is_stack_before_data =
|
||||
stack_bottom < data_end ? true : false;
|
||||
|
||||
/* Check the aux stack space, currently we don't allocate space in heap */
|
||||
if ((is_stack_before_data && (size > start_offset))
|
||||
|| ((!is_stack_before_data) && (start_offset - data_end < size)))
|
||||
return false;
|
||||
|
||||
if (stack_bottom) {
|
||||
/* The aux stack top is a wasm global,
|
||||
set the initial value for the global */
|
||||
uint8 *global_addr =
|
||||
module_inst->global_data +
|
||||
module_inst->globals[stack_top_idx].data_offset;
|
||||
*(int32*)global_addr = start_offset;
|
||||
/* The aux stack boundary is a constant value,
|
||||
set the value to exec_env */
|
||||
exec_env->aux_stack_boundary = start_offset - size;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_get_aux_stack(WASMExecEnv *exec_env,
|
||||
uint32 *start_offset, uint32 *size)
|
||||
{
|
||||
WASMModuleInstance *module_inst =
|
||||
(WASMModuleInstance*)exec_env->module_inst;
|
||||
|
||||
/* The aux stack information is resolved in loader
|
||||
and store in module */
|
||||
uint32 stack_bottom =
|
||||
module_inst->module->llvm_aux_stack_bottom;
|
||||
uint32 total_aux_stack_size =
|
||||
module_inst->module->llvm_aux_stack_size;
|
||||
|
||||
if (stack_bottom != 0 && total_aux_stack_size != 0) {
|
||||
if (start_offset)
|
||||
*start_offset = stack_bottom;
|
||||
if (size)
|
||||
*size = total_aux_stack_size;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@ -22,6 +22,10 @@ typedef struct WASMTableInstance WASMTableInstance;
|
||||
typedef struct WASMGlobalInstance WASMGlobalInstance;
|
||||
|
||||
typedef struct WASMMemoryInstance {
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
/* shared memory flag */
|
||||
bool is_shared;
|
||||
#endif
|
||||
/* Number bytes per page */
|
||||
uint32 num_bytes_per_page;
|
||||
/* Current page count */
|
||||
@ -269,12 +273,12 @@ void
|
||||
wasm_unload(WASMModule *module);
|
||||
|
||||
WASMModuleInstance *
|
||||
wasm_instantiate(WASMModule *module,
|
||||
wasm_instantiate(WASMModule *module, bool is_sub_inst,
|
||||
uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size);
|
||||
|
||||
void
|
||||
wasm_deinstantiate(WASMModuleInstance *module_inst);
|
||||
wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst);
|
||||
|
||||
WASMFunctionInstance *
|
||||
wasm_lookup_function(const WASMModuleInstance *module_inst,
|
||||
@ -358,6 +362,16 @@ wasm_call_indirect(WASMExecEnv *exec_env,
|
||||
uint32_t element_indices,
|
||||
uint32_t argc, uint32_t argv[]);
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
bool
|
||||
wasm_set_aux_stack(WASMExecEnv *exec_env,
|
||||
uint32 start_offset, uint32 size);
|
||||
|
||||
bool
|
||||
wasm_get_aux_stack(WASMExecEnv *exec_env,
|
||||
uint32 *start_offset, uint32 *size);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
13
core/iwasm/libraries/lib-pthread/lib_pthread.cmake
Normal file
13
core/iwasm/libraries/lib-pthread/lib_pthread.cmake
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
set (LIB_PTHREAD_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_definitions (-DWASM_ENABLE_LIB_PTHREAD=1)
|
||||
|
||||
include_directories(${LIB_PTHREAD_DIR})
|
||||
|
||||
file (GLOB source_all ${LIB_PTHREAD_DIR}/*.c)
|
||||
|
||||
set (LIB_PTHREAD_SOURCE ${source_all})
|
||||
|
||||
731
core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c
Normal file
731
core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c
Normal file
@ -0,0 +1,731 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "bh_common.h"
|
||||
#include "bh_log.h"
|
||||
#include "wasm_export.h"
|
||||
#include "../interpreter/wasm.h"
|
||||
#include "../common/wasm_runtime_common.h"
|
||||
#include "thread_manager.h"
|
||||
|
||||
#define get_module(exec_env) \
|
||||
wasm_exec_env_get_module(exec_env)
|
||||
|
||||
#define get_module_inst(exec_env) \
|
||||
wasm_runtime_get_module_inst(exec_env)
|
||||
|
||||
#define get_thread_arg(exec_env) \
|
||||
wasm_exec_env_get_thread_arg(exec_env)
|
||||
|
||||
#define get_wasi_ctx(module_inst) \
|
||||
wasm_runtime_get_wasi_ctx(module_inst)
|
||||
|
||||
#define validate_app_addr(offset, size) \
|
||||
wasm_runtime_validate_app_addr(module_inst, offset, size)
|
||||
|
||||
#define validate_native_addr(addr, size) \
|
||||
wasm_runtime_validate_native_addr(module_inst, addr, size)
|
||||
|
||||
#define addr_app_to_native(offset) \
|
||||
wasm_runtime_addr_app_to_native(module_inst, offset)
|
||||
|
||||
#define addr_native_to_app(ptr) \
|
||||
wasm_runtime_addr_native_to_app(module_inst, ptr)
|
||||
|
||||
extern bool
|
||||
wasm_runtime_call_indirect(wasm_exec_env_t exec_env,
|
||||
uint32 element_indices,
|
||||
uint32 argc, uint32 argv[]);
|
||||
|
||||
enum {
|
||||
T_THREAD,
|
||||
T_MUTEX,
|
||||
T_COND,
|
||||
};
|
||||
|
||||
enum thread_status_t {
|
||||
THREAD_INIT,
|
||||
THREAD_RUNNING,
|
||||
THREAD_CANCELLED,
|
||||
THREAD_EXIT,
|
||||
};
|
||||
|
||||
enum mutex_status_t {
|
||||
MUTEX_CREATED,
|
||||
MUTEX_DESTROYED,
|
||||
};
|
||||
|
||||
enum cond_status_t {
|
||||
COND_CREATED,
|
||||
COND_DESTROYED,
|
||||
};
|
||||
|
||||
typedef struct ClusterInfoNode {
|
||||
bh_list_link l;
|
||||
WASMCluster *cluster;
|
||||
HashMap *thread_info_map;
|
||||
} ClusterInfoNode;
|
||||
|
||||
typedef struct ThreadInfoNode {
|
||||
wasm_exec_env_t parent_exec_env;
|
||||
wasm_exec_env_t exec_env;
|
||||
/* the id returned to app */
|
||||
uint32 handle;
|
||||
/* type can be [THREAD | MUTEX | CONDITION] */
|
||||
uint32 type;
|
||||
/* Thread status, this variable should be volatile
|
||||
as its value may be changed in different threads */
|
||||
volatile uint32 status;
|
||||
union {
|
||||
korp_tid thread;
|
||||
korp_mutex *mutex;
|
||||
korp_cond *cond;
|
||||
} u;
|
||||
} ThreadInfoNode;
|
||||
|
||||
typedef struct {
|
||||
ThreadInfoNode *info_node;
|
||||
/* table elem index of the app's entry function */
|
||||
uint32 elem_index;
|
||||
/* arg of the app's entry function */
|
||||
void *arg;
|
||||
wasm_module_inst_t module_inst;
|
||||
} ThreadRoutineArgs;
|
||||
|
||||
static bh_list cluster_info_list;
|
||||
static korp_mutex pthread_global_lock;
|
||||
static uint32 handle_id = 1;
|
||||
|
||||
static void
|
||||
lib_pthread_destroy_callback(WASMCluster *cluster);
|
||||
|
||||
static uint32
|
||||
thread_handle_hash(void *handle)
|
||||
{
|
||||
return (uint32)(uintptr_t)handle;
|
||||
}
|
||||
|
||||
static bool
|
||||
thread_handle_equal(void *h1, void *h2)
|
||||
{
|
||||
return (uint32)(uintptr_t)h1 == (uint32)(uintptr_t)h2 ? true : false;
|
||||
}
|
||||
|
||||
static void
|
||||
thread_info_destroy(void *node)
|
||||
{
|
||||
ThreadInfoNode *info_node = (ThreadInfoNode *)node;
|
||||
ThreadRoutineArgs *args;
|
||||
|
||||
pthread_mutex_lock(&pthread_global_lock);
|
||||
if (info_node->type == T_THREAD) {
|
||||
args = get_thread_arg(info_node->exec_env);
|
||||
if (args) {
|
||||
wasm_runtime_free(args);
|
||||
}
|
||||
}
|
||||
else if (info_node->type == T_MUTEX) {
|
||||
if (info_node->status != MUTEX_DESTROYED)
|
||||
os_mutex_destroy(info_node->u.mutex);
|
||||
wasm_runtime_free(info_node->u.mutex);
|
||||
}
|
||||
else if (info_node->type == T_COND) {
|
||||
if (info_node->status != COND_DESTROYED)
|
||||
os_cond_destroy(info_node->u.cond);
|
||||
wasm_runtime_free(info_node->u.cond);
|
||||
}
|
||||
wasm_runtime_free(info_node);
|
||||
pthread_mutex_unlock(&pthread_global_lock);
|
||||
}
|
||||
|
||||
bool
|
||||
lib_pthread_init()
|
||||
{
|
||||
if (0 != os_mutex_init(&pthread_global_lock))
|
||||
return false;
|
||||
bh_list_init(&cluster_info_list);
|
||||
if (!wasm_cluster_register_destroy_callback(
|
||||
lib_pthread_destroy_callback)) {
|
||||
os_mutex_destroy(&pthread_global_lock);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
lib_pthread_destroy()
|
||||
{
|
||||
os_mutex_destroy(&pthread_global_lock);
|
||||
}
|
||||
|
||||
static ClusterInfoNode*
|
||||
get_cluster_info(WASMCluster *cluster)
|
||||
{
|
||||
ClusterInfoNode *node;
|
||||
|
||||
os_mutex_lock(&pthread_global_lock);
|
||||
node = bh_list_first_elem(&cluster_info_list);
|
||||
|
||||
while (node) {
|
||||
if (cluster == node->cluster) {
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
return node;
|
||||
}
|
||||
node = bh_list_elem_next(node);
|
||||
}
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ClusterInfoNode*
|
||||
create_cluster_info(WASMCluster *cluster)
|
||||
{
|
||||
ClusterInfoNode *node;
|
||||
bh_list_status ret;
|
||||
|
||||
if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->cluster = cluster;
|
||||
if (!(node->thread_info_map =
|
||||
bh_hash_map_create(32, true,
|
||||
(HashFunc)thread_handle_hash,
|
||||
(KeyEqualFunc)thread_handle_equal,
|
||||
NULL,
|
||||
thread_info_destroy))) {
|
||||
wasm_runtime_free(node);
|
||||
return NULL;
|
||||
}
|
||||
os_mutex_lock(&pthread_global_lock);
|
||||
ret = bh_list_insert(&cluster_info_list, node);
|
||||
bh_assert(ret == 0);
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
|
||||
(void)ret;
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool
|
||||
destroy_cluster_info(WASMCluster *cluster)
|
||||
{
|
||||
ClusterInfoNode *node = get_cluster_info(cluster);
|
||||
if (node) {
|
||||
bh_hash_map_destroy(node->thread_info_map);
|
||||
os_mutex_lock(&pthread_global_lock);
|
||||
bh_list_remove(&cluster_info_list, node);
|
||||
wasm_runtime_free(node);
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
lib_pthread_destroy_callback(WASMCluster *cluster)
|
||||
{
|
||||
destroy_cluster_info(cluster);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_thread_info_node(ThreadInfoNode *thread_info)
|
||||
{
|
||||
ClusterInfoNode *node;
|
||||
bool ret;
|
||||
WASMCluster *cluster =
|
||||
wasm_exec_env_get_cluster(thread_info->exec_env);
|
||||
|
||||
if ((node = get_cluster_info(cluster))) {
|
||||
ret = bh_hash_map_remove(node->thread_info_map,
|
||||
(void *)(uintptr_t)thread_info->handle,
|
||||
NULL, NULL);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
thread_info_destroy(thread_info);
|
||||
}
|
||||
|
||||
static bool
|
||||
append_thread_info_node(ThreadInfoNode *thread_info)
|
||||
{
|
||||
ClusterInfoNode *node;
|
||||
WASMCluster *cluster =
|
||||
wasm_exec_env_get_cluster(thread_info->exec_env);
|
||||
|
||||
if (!(node = get_cluster_info(cluster))) {
|
||||
if (!(node = create_cluster_info(cluster))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bh_hash_map_insert(node->thread_info_map,
|
||||
(void *)(uintptr_t)thread_info->handle,
|
||||
thread_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static ThreadInfoNode*
|
||||
get_thread_info(wasm_exec_env_t exec_env, uint32 handle)
|
||||
{
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
ClusterInfoNode *info = get_cluster_info(cluster);
|
||||
return bh_hash_map_find(info->thread_info_map, (void *)(uintptr_t)handle);
|
||||
}
|
||||
|
||||
static uint32
|
||||
allocate_handle()
|
||||
{
|
||||
uint32 id;
|
||||
os_mutex_lock(&pthread_global_lock);
|
||||
id = handle_id++;
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
return id;
|
||||
}
|
||||
|
||||
static void*
|
||||
pthread_start_routine(void *arg)
|
||||
{
|
||||
wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
|
||||
wasm_exec_env_t parent_exec_env;
|
||||
wasm_module_inst_t module_inst = get_module_inst(exec_env);
|
||||
ThreadRoutineArgs *routine_args = exec_env->thread_arg;
|
||||
ThreadInfoNode *info_node = routine_args->info_node;
|
||||
uint32 argv[1];
|
||||
|
||||
parent_exec_env = info_node->parent_exec_env;
|
||||
os_mutex_lock(&parent_exec_env->wait_lock);
|
||||
info_node->exec_env = exec_env;
|
||||
info_node->u.thread = exec_env->handle;
|
||||
if (!append_thread_info_node(info_node)) {
|
||||
wasm_runtime_deinstantiate_internal(module_inst, true);
|
||||
delete_thread_info_node(info_node);
|
||||
os_cond_signal(&parent_exec_env->wait_cond);
|
||||
os_mutex_unlock(&parent_exec_env->wait_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info_node->status = THREAD_RUNNING;
|
||||
os_cond_signal(&parent_exec_env->wait_cond);
|
||||
os_mutex_unlock(&parent_exec_env->wait_lock);
|
||||
|
||||
if (!validate_native_addr(routine_args->arg, sizeof(uint32))) {
|
||||
/* If there are exceptions, copy the exception to
|
||||
all other instance in this cluster */
|
||||
wasm_cluster_spread_exception(exec_env);
|
||||
wasm_runtime_deinstantiate_internal(module_inst, true);
|
||||
delete_thread_info_node(info_node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
argv[0] = addr_native_to_app(routine_args->arg);
|
||||
|
||||
if(!wasm_runtime_call_indirect(exec_env,
|
||||
routine_args->elem_index,
|
||||
1, argv)) {
|
||||
wasm_cluster_spread_exception(exec_env);
|
||||
}
|
||||
|
||||
/* routine exit, destroy instance */
|
||||
wasm_runtime_deinstantiate_internal(module_inst, true);
|
||||
|
||||
info_node->status = THREAD_EXIT;
|
||||
|
||||
delete_thread_info_node(info_node);
|
||||
|
||||
return (void *)(uintptr_t)argv[0];
|
||||
}
|
||||
|
||||
static int
|
||||
pthread_create_wrapper(wasm_exec_env_t exec_env,
|
||||
uint32 *thread, /* thread_handle */
|
||||
const void *attr, /* not supported */
|
||||
uint32 elem_index, /* entry function */
|
||||
void *arg) /* arguments buffer */
|
||||
{
|
||||
wasm_module_t module = get_module(exec_env);
|
||||
wasm_module_inst_t new_module_inst = NULL;
|
||||
ThreadInfoNode *info_node = NULL;
|
||||
ThreadRoutineArgs *routine_args = NULL;
|
||||
uint32 thread_handle;
|
||||
int32 ret = -1;
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
wasm_module_inst_t module_inst = get_module_inst(exec_env);
|
||||
WASIContext *wasi_ctx = get_wasi_ctx(module_inst);
|
||||
#endif
|
||||
|
||||
if (!(new_module_inst =
|
||||
wasm_runtime_instantiate_internal(module, true, 8192, 0,
|
||||
NULL, 0)))
|
||||
return -1;
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
if (wasi_ctx)
|
||||
wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
|
||||
#endif
|
||||
|
||||
if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
|
||||
goto fail;
|
||||
|
||||
memset(info_node, 0, sizeof(ThreadInfoNode));
|
||||
thread_handle = allocate_handle();
|
||||
info_node->parent_exec_env = exec_env;
|
||||
info_node->handle = thread_handle;
|
||||
info_node->type = T_THREAD;
|
||||
info_node->status = THREAD_INIT;
|
||||
|
||||
if (!(routine_args = wasm_runtime_malloc(sizeof(ThreadRoutineArgs))))
|
||||
goto fail;
|
||||
|
||||
routine_args->arg = arg;
|
||||
routine_args->elem_index = elem_index;
|
||||
routine_args->info_node = info_node;
|
||||
routine_args->module_inst = new_module_inst;
|
||||
|
||||
os_mutex_lock(&exec_env->wait_lock);
|
||||
ret = wasm_cluster_create_thread(exec_env, new_module_inst,
|
||||
pthread_start_routine,
|
||||
(void *)routine_args);
|
||||
if (ret != 0) {
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Wait for the thread routine to assign the exec_env to
|
||||
thread_info_node, otherwise the exec_env in the thread
|
||||
info node may be NULL in the next pthread API call */
|
||||
os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
|
||||
if (thread)
|
||||
*thread = thread_handle;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (new_module_inst)
|
||||
wasm_runtime_deinstantiate_internal(new_module_inst, true);
|
||||
if (info_node)
|
||||
wasm_runtime_free(info_node);
|
||||
if (routine_args)
|
||||
wasm_runtime_free(routine_args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread,
|
||||
int32 retval_offset) /* void **retval */
|
||||
{
|
||||
uint32 *ret;
|
||||
int32 join_ret;
|
||||
void **retval;
|
||||
ThreadInfoNode *node;
|
||||
wasm_module_inst_t module_inst;
|
||||
wasm_exec_env_t target_exec_env;
|
||||
|
||||
node = get_thread_info(exec_env, thread);
|
||||
if (!node) {
|
||||
/* The thread has exited, return 0 to app */
|
||||
return 0;
|
||||
}
|
||||
|
||||
target_exec_env = node->exec_env;
|
||||
bh_assert(target_exec_env != NULL);
|
||||
module_inst = get_module_inst(target_exec_env);
|
||||
|
||||
/* validate addr before join thread, otherwise
|
||||
the module_inst may be freed */
|
||||
if (!validate_app_addr(retval_offset, sizeof(uint32))) {
|
||||
/* Join failed, but we don't want to terminate all threads,
|
||||
do not spread exception here */
|
||||
wasm_runtime_set_exception(module_inst, NULL);
|
||||
return -1;
|
||||
}
|
||||
retval = (void **)addr_app_to_native(retval_offset);
|
||||
|
||||
join_ret = wasm_cluster_join_thread(target_exec_env, (void **)&ret);
|
||||
|
||||
if (retval_offset != 0)
|
||||
*retval = (void*)ret;
|
||||
|
||||
return join_ret;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_detach_wrapper(wasm_exec_env_t exec_env, uint32 thread)
|
||||
{
|
||||
ThreadInfoNode *node;
|
||||
wasm_exec_env_t target_exec_env;
|
||||
|
||||
node = get_thread_info(exec_env, thread);
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
target_exec_env = node->exec_env;
|
||||
bh_assert(target_exec_env != NULL);
|
||||
|
||||
return wasm_cluster_detach_thread(target_exec_env);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cancel_wrapper(wasm_exec_env_t exec_env, uint32 thread)
|
||||
{
|
||||
ThreadInfoNode *node;
|
||||
wasm_exec_env_t target_exec_env;
|
||||
|
||||
node = get_thread_info(exec_env, thread);
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
target_exec_env = node->exec_env;
|
||||
bh_assert(target_exec_env != NULL);
|
||||
|
||||
return wasm_cluster_cancel_thread(target_exec_env);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_self_wrapper(wasm_exec_env_t exec_env)
|
||||
{
|
||||
ThreadRoutineArgs *args = get_thread_arg(exec_env);
|
||||
/* If thread_arg is NULL, it's the exec_env of the main thread,
|
||||
return id 0 to app */
|
||||
if (!args)
|
||||
return 0;
|
||||
|
||||
return args->info_node->handle;
|
||||
}
|
||||
|
||||
static void
|
||||
pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
|
||||
{
|
||||
wasm_module_inst_t module_inst = get_module_inst(exec_env);
|
||||
ThreadRoutineArgs *args = get_thread_arg(exec_env);
|
||||
/* Currently exit main thread is not allowed */
|
||||
if (!args)
|
||||
return;
|
||||
|
||||
/* routine exit, destroy instance */
|
||||
wasm_runtime_deinstantiate_internal(module_inst, true);
|
||||
|
||||
delete_thread_info_node(args->info_node);
|
||||
|
||||
wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_mutex_init_wrapper(wasm_exec_env_t exec_env, uint32 *mutex, void *attr)
|
||||
{
|
||||
korp_mutex *pmutex;
|
||||
ThreadInfoNode *info_node;
|
||||
|
||||
if (!(pmutex = wasm_runtime_malloc(sizeof(korp_mutex)))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (os_mutex_init(pmutex) != 0) {
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
|
||||
goto fail2;
|
||||
|
||||
memset(info_node, 0, sizeof(ThreadInfoNode));
|
||||
info_node->exec_env = exec_env;
|
||||
info_node->handle = allocate_handle();
|
||||
info_node->type = T_MUTEX;
|
||||
info_node->u.mutex = pmutex;
|
||||
info_node->status = MUTEX_CREATED;
|
||||
|
||||
if (!append_thread_info_node(info_node))
|
||||
goto fail3;
|
||||
|
||||
/* Return the mutex handle to app */
|
||||
if (mutex)
|
||||
*(uint32*)mutex = info_node->handle;
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
delete_thread_info_node(info_node);
|
||||
fail2:
|
||||
os_mutex_destroy(pmutex);
|
||||
fail1:
|
||||
wasm_runtime_free(pmutex);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_mutex_lock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
|
||||
{
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!info_node || info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
return os_mutex_lock(info_node->u.mutex);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_mutex_unlock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
|
||||
{
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!info_node || info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
return os_mutex_unlock(info_node->u.mutex);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_mutex_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
|
||||
{
|
||||
int32 ret_val;
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!info_node || info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
ret_val = os_mutex_destroy(info_node->u.mutex);
|
||||
|
||||
info_node->status = MUTEX_DESTROYED;
|
||||
delete_thread_info_node(info_node);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cond_init_wrapper(wasm_exec_env_t exec_env, uint32 *cond, void *attr)
|
||||
{
|
||||
korp_cond *pcond;
|
||||
ThreadInfoNode *info_node;
|
||||
|
||||
if (!(pcond = wasm_runtime_malloc(sizeof(korp_cond)))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (os_cond_init(pcond) != 0) {
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
|
||||
goto fail2;
|
||||
|
||||
memset(info_node, 0, sizeof(ThreadInfoNode));
|
||||
info_node->exec_env = exec_env;
|
||||
info_node->handle = allocate_handle();
|
||||
info_node->type = T_COND;
|
||||
info_node->u.cond = pcond;
|
||||
info_node->status = COND_CREATED;
|
||||
|
||||
if (!append_thread_info_node(info_node))
|
||||
goto fail3;
|
||||
|
||||
/* Return the cond handle to app */
|
||||
if (cond)
|
||||
*(uint32*)cond = info_node->handle;
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
delete_thread_info_node(info_node);
|
||||
fail2:
|
||||
os_cond_destroy(pcond);
|
||||
fail1:
|
||||
wasm_runtime_free(pcond);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cond_wait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, uint32 *mutex)
|
||||
{
|
||||
ThreadInfoNode *cond_info_node, *mutex_info_node;
|
||||
|
||||
cond_info_node = get_thread_info(exec_env, *cond);
|
||||
if (!cond_info_node || cond_info_node->type != T_COND)
|
||||
return -1;
|
||||
|
||||
mutex_info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!mutex_info_node || mutex_info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
return os_cond_wait(cond_info_node->u.cond, mutex_info_node->u.mutex);
|
||||
}
|
||||
|
||||
/* Currently we don't support struct timespec in built-in libc,
|
||||
so the pthread_cond_timedwait use useconds instead
|
||||
*/
|
||||
static int32
|
||||
pthread_cond_timedwait_wrapper(wasm_exec_env_t exec_env, uint32 *cond,
|
||||
uint32 *mutex, uint32 useconds)
|
||||
{
|
||||
ThreadInfoNode *cond_info_node, *mutex_info_node;
|
||||
|
||||
cond_info_node = get_thread_info(exec_env, *cond);
|
||||
if (!cond_info_node || cond_info_node->type != T_COND)
|
||||
return -1;
|
||||
|
||||
mutex_info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!mutex_info_node || mutex_info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
return os_cond_reltimedwait(cond_info_node->u.cond,
|
||||
mutex_info_node->u.mutex, useconds);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cond_signal_wrapper(wasm_exec_env_t exec_env, uint32 *cond)
|
||||
{
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *cond);
|
||||
if (!info_node || info_node->type != T_COND)
|
||||
return -1;
|
||||
|
||||
return os_cond_signal(info_node->u.cond);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cond_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *cond)
|
||||
{
|
||||
int32 ret_val;
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *cond);
|
||||
if (!info_node || info_node->type != T_COND)
|
||||
return -1;
|
||||
|
||||
ret_val = os_cond_destroy(info_node->u.cond);
|
||||
|
||||
info_node->status = COND_DESTROYED;
|
||||
delete_thread_info_node(info_node);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#define REG_NATIVE_FUNC(func_name, signature) \
|
||||
{ #func_name, func_name##_wrapper, signature, NULL }
|
||||
|
||||
static NativeSymbol native_symbols_lib_pthread[] = {
|
||||
REG_NATIVE_FUNC(pthread_create, "(**i*)i"),
|
||||
REG_NATIVE_FUNC(pthread_join, "(ii)i"),
|
||||
REG_NATIVE_FUNC(pthread_detach, "(i)i"),
|
||||
REG_NATIVE_FUNC(pthread_cancel, "(i)i"),
|
||||
REG_NATIVE_FUNC(pthread_self, "()i"),
|
||||
REG_NATIVE_FUNC(pthread_exit, "(i)"),
|
||||
REG_NATIVE_FUNC(pthread_mutex_init, "(**)i"),
|
||||
REG_NATIVE_FUNC(pthread_mutex_lock, "(*)i"),
|
||||
REG_NATIVE_FUNC(pthread_mutex_unlock, "(*)i"),
|
||||
REG_NATIVE_FUNC(pthread_mutex_destroy, "(*)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_init, "(**)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_wait, "(**)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_timedwait, "(**i)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_signal, "(*)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"),
|
||||
};
|
||||
|
||||
uint32
|
||||
get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis)
|
||||
{
|
||||
*p_lib_pthread_apis = native_symbols_lib_pthread;
|
||||
return sizeof(native_symbols_lib_pthread) / sizeof(NativeSymbol);
|
||||
}
|
||||
@ -1131,9 +1131,11 @@ typedef struct WASMNativeGlobalDef {
|
||||
} WASMNativeGlobalDef;
|
||||
|
||||
static WASMNativeGlobalDef native_global_defs[] = {
|
||||
#if WASM_ENABLE_SPEC_TEST != 0
|
||||
{ "spectest", "global_i32", .global_data.i32 = 666 },
|
||||
{ "spectest", "global_f32", .global_data.f32 = 666.6 },
|
||||
{ "spectest", "global_f64", .global_data.f64 = 666.6 },
|
||||
#endif
|
||||
{ "test", "global-i32", .global_data.i32 = 0 },
|
||||
{ "test", "global-f32", .global_data.f32 = 0 },
|
||||
{ "env", "STACKTOP", .global_data.u32 = 0 },
|
||||
|
||||
@ -58,6 +58,8 @@ static struct fd_table *
|
||||
wasi_ctx_get_curfds(wasm_module_inst_t module_inst,
|
||||
wasi_ctx_t wasi_ctx)
|
||||
{
|
||||
if (!wasi_ctx)
|
||||
return NULL;
|
||||
return (struct fd_table *)
|
||||
wasm_runtime_addr_app_to_native(module_inst,
|
||||
wasi_ctx->curfds_offset);
|
||||
@ -67,6 +69,8 @@ static struct argv_environ_values *
|
||||
wasi_ctx_get_argv_environ(wasm_module_inst_t module_inst,
|
||||
wasi_ctx_t wasi_ctx)
|
||||
{
|
||||
if (!wasi_ctx)
|
||||
return NULL;
|
||||
return (struct argv_environ_values *)
|
||||
wasm_runtime_addr_app_to_native(module_inst,
|
||||
wasi_ctx->argv_environ_offset);
|
||||
@ -76,6 +80,8 @@ static struct fd_prestats *
|
||||
wasi_ctx_get_prestats(wasm_module_inst_t module_inst,
|
||||
wasi_ctx_t wasi_ctx)
|
||||
{
|
||||
if (!wasi_ctx)
|
||||
return NULL;
|
||||
return (struct fd_prestats *)
|
||||
wasm_runtime_addr_app_to_native(module_inst,
|
||||
wasi_ctx->prestats_offset);
|
||||
@ -93,6 +99,9 @@ wasi_args_get(wasm_exec_env_t exec_env, int32 *argv_offsets, char *argv_buf)
|
||||
uint64 total_size;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
err = wasmtime_ssp_args_sizes_get(argv_environ, &argc, &argv_buf_size);
|
||||
if (err)
|
||||
return err;
|
||||
@ -133,6 +142,9 @@ wasi_args_sizes_get(wasm_exec_env_t exec_env,
|
||||
size_t argc, argv_buf_size;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(argc_app, sizeof(uint32))
|
||||
|| !validate_native_addr(argv_buf_size_app, sizeof(uint32)))
|
||||
return (wasi_errno_t)-1;
|
||||
@ -191,6 +203,9 @@ wasi_environ_get(wasm_exec_env_t exec_env,
|
||||
char **environs;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
err = wasmtime_ssp_environ_sizes_get(argv_environ,
|
||||
&environ_count, &environ_buf_size);
|
||||
if (err)
|
||||
@ -234,6 +249,9 @@ wasi_environ_sizes_get(wasm_exec_env_t exec_env,
|
||||
size_t environ_count, environ_buf_size;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(environ_count_app, sizeof(uint32))
|
||||
|| !validate_native_addr(environ_buf_size_app, sizeof(uint32)))
|
||||
return (wasi_errno_t)-1;
|
||||
@ -259,6 +277,9 @@ wasi_fd_prestat_get(wasm_exec_env_t exec_env,
|
||||
wasi_prestat_t prestat;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(prestat_app, sizeof(wasi_prestat_app_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -279,6 +300,9 @@ wasi_fd_prestat_dir_name(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_prestat_dir_name(prestats,
|
||||
fd, path, path_len);
|
||||
}
|
||||
@ -291,6 +315,9 @@ wasi_fd_close(wasm_exec_env_t exec_env, wasi_fd_t fd)
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_close(curfds, prestats, fd);
|
||||
}
|
||||
|
||||
@ -301,6 +328,9 @@ wasi_fd_datasync(wasm_exec_env_t exec_env, wasi_fd_t fd)
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_datasync(curfds, fd);
|
||||
}
|
||||
|
||||
@ -319,6 +349,9 @@ wasi_fd_pread(wasm_exec_env_t exec_env,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)iovs_len;
|
||||
if (!validate_native_addr(nread_app, (uint32)sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -371,6 +404,9 @@ wasi_fd_pwrite(wasm_exec_env_t exec_env,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)iovs_len;
|
||||
if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -423,6 +459,9 @@ wasi_fd_read(wasm_exec_env_t exec_env,
|
||||
int32 mem;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)iovs_len;
|
||||
if (!validate_native_addr(nread_app, (uint32)sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -468,6 +507,9 @@ wasi_fd_renumber(wasm_exec_env_t exec_env, wasi_fd_t from, wasi_fd_t to)
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_renumber(curfds, prestats, from, to);
|
||||
}
|
||||
|
||||
@ -480,6 +522,9 @@ wasi_fd_seek(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -494,6 +539,9 @@ wasi_fd_tell(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -510,6 +558,9 @@ wasi_fd_fdstat_get(wasm_exec_env_t exec_env,
|
||||
wasi_fdstat_t fdstat;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(fdstat_app, sizeof(wasi_fdstat_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -529,6 +580,9 @@ wasi_fd_fdstat_set_flags(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_fdstat_set_flags(curfds, fd, flags);
|
||||
}
|
||||
|
||||
@ -542,6 +596,9 @@ wasi_fd_fdstat_set_rights(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_fdstat_set_rights(curfds, fd,
|
||||
fs_rights_base, fs_rights_inheriting);
|
||||
}
|
||||
@ -553,6 +610,9 @@ wasi_fd_sync(wasm_exec_env_t exec_env, wasi_fd_t fd)
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_sync(curfds, fd);
|
||||
}
|
||||
|
||||
@ -571,6 +631,9 @@ wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)iovs_len;
|
||||
if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -619,6 +682,9 @@ wasi_fd_advise(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_advise(curfds, fd, offset, len, advice);
|
||||
}
|
||||
|
||||
@ -632,6 +698,9 @@ wasi_fd_allocate(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_allocate(curfds, fd, offset, len);
|
||||
}
|
||||
|
||||
@ -643,6 +712,9 @@ wasi_path_create_directory(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_create_directory(curfds, fd,
|
||||
path, path_len);
|
||||
}
|
||||
@ -660,6 +732,9 @@ wasi_path_link(wasm_exec_env_t exec_env,
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_link(curfds, prestats,
|
||||
old_fd, old_flags, old_path, old_path_len,
|
||||
new_fd, new_path, new_path_len);
|
||||
@ -682,6 +757,9 @@ wasi_path_open(wasm_exec_env_t exec_env,
|
||||
wasi_fd_t fd = -1; /* set fd_app -1 if path open failed */
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(fd_app, sizeof(wasi_fd_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -711,6 +789,9 @@ wasi_fd_readdir(wasm_exec_env_t exec_env,
|
||||
size_t bufused;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(bufused_app, sizeof(uint32)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -736,6 +817,9 @@ wasi_path_readlink(wasm_exec_env_t exec_env,
|
||||
size_t bufused;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(bufused_app, sizeof(uint32)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -758,6 +842,9 @@ wasi_path_rename(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_rename(curfds,
|
||||
old_fd, old_path, old_path_len,
|
||||
new_fd, new_path, new_path_len);
|
||||
@ -771,6 +858,9 @@ wasi_fd_filestat_get(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(filestat, sizeof(wasi_filestat_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -788,6 +878,9 @@ wasi_fd_filestat_set_times(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_filestat_set_times(curfds, fd,
|
||||
st_atim, st_mtim, fstflags);
|
||||
}
|
||||
@ -801,6 +894,9 @@ wasi_fd_filestat_set_size(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_filestat_set_size(curfds, fd, st_size);
|
||||
}
|
||||
|
||||
@ -815,6 +911,9 @@ wasi_path_filestat_get(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(filestat, sizeof(wasi_filestat_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -835,6 +934,9 @@ wasi_path_filestat_set_times(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_filestat_set_times(curfds, fd,
|
||||
flags, path, path_len,
|
||||
st_atim, st_mtim, fstflags);
|
||||
@ -850,6 +952,9 @@ wasi_path_symlink(wasm_exec_env_t exec_env,
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_symlink(curfds, prestats,
|
||||
old_path, old_path_len, fd,
|
||||
new_path, new_path_len);
|
||||
@ -863,6 +968,9 @@ wasi_path_unlink_file(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_unlink_file(curfds, fd, path, path_len);
|
||||
}
|
||||
|
||||
@ -874,6 +982,9 @@ wasi_path_remove_directory(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_remove_directory(curfds, fd, path, path_len);
|
||||
}
|
||||
|
||||
@ -888,6 +999,9 @@ wasi_poll_oneoff(wasm_exec_env_t exec_env,
|
||||
size_t nevents;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr((void*)in, sizeof(wasi_subscription_t))
|
||||
|| !validate_native_addr(out, sizeof(wasi_event_t))
|
||||
|| !validate_native_addr(nevents_app, sizeof(uint32)))
|
||||
@ -943,6 +1057,9 @@ wasi_sock_recv(wasm_exec_env_t exec_env,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)ri_data_len;
|
||||
if (!validate_native_addr(ro_datalen_app, (uint32)sizeof(uint32))
|
||||
|| !validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t))
|
||||
@ -1000,6 +1117,9 @@ wasi_sock_send(wasm_exec_env_t exec_env,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)si_data_len;
|
||||
if (!validate_native_addr(so_datalen_app, sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -1046,6 +1166,9 @@ wasi_sock_shutdown(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_sock_shutdown(curfds, sock, how);
|
||||
}
|
||||
|
||||
|
||||
523
core/iwasm/libraries/thread-mgr/thread_manager.c
Normal file
523
core/iwasm/libraries/thread-mgr/thread_manager.c
Normal file
@ -0,0 +1,523 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "thread_manager.h"
|
||||
|
||||
typedef struct {
|
||||
bh_list_link l;
|
||||
|
||||
void (*destroy_cb)(WASMCluster *);
|
||||
} DestroyCallBackNode;
|
||||
|
||||
static bh_list destroy_callback_list_head;
|
||||
static bh_list *const destroy_callback_list = &destroy_callback_list_head;
|
||||
|
||||
static bh_list cluster_list_head;
|
||||
static bh_list *const cluster_list = &cluster_list_head;
|
||||
static korp_mutex cluster_list_lock;
|
||||
|
||||
typedef void (*list_visitor)(void *, void *);
|
||||
|
||||
static uint32 cluster_max_thread_num = CLUSTER_MAX_THREAD_NUM;
|
||||
|
||||
/* Set the maximum thread number, if this function is not called,
|
||||
the max thread num is defined by CLUSTER_MAX_THREAD_NUM */
|
||||
void
|
||||
wasm_cluster_set_max_thread_num(uint32 num)
|
||||
{
|
||||
cluster_max_thread_num = num;
|
||||
}
|
||||
|
||||
bool
|
||||
thread_manager_init()
|
||||
{
|
||||
if (bh_list_init(cluster_list) != 0)
|
||||
return false;
|
||||
if (os_mutex_init(&cluster_list_lock) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
thread_manager_destroy()
|
||||
{
|
||||
WASMCluster *cluster = bh_list_first_elem(cluster_list);
|
||||
WASMCluster *next;
|
||||
while (cluster) {
|
||||
next = bh_list_elem_next(cluster);
|
||||
wasm_cluster_destroy(cluster);
|
||||
cluster = next;
|
||||
}
|
||||
wasm_cluster_cancel_all_callbacks();
|
||||
os_mutex_destroy(&cluster_list_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
traverse_list(bh_list *l, list_visitor visitor, void *user_data)
|
||||
{
|
||||
void *next, *node = bh_list_first_elem(l);
|
||||
while (node) {
|
||||
next = bh_list_elem_next(node);
|
||||
visitor(node, user_data);
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
allocate_aux_stack(WASMCluster *cluster, uint32 *start, uint32 *size)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
/* If the module doesn't have aux stack info,
|
||||
it can't create any threads */
|
||||
if (!cluster->stack_segment_occupied)
|
||||
return false;
|
||||
|
||||
os_mutex_lock(&cluster->lock);
|
||||
for (i = 0; i < cluster_max_thread_num; i++) {
|
||||
if (!cluster->stack_segment_occupied[i]) {
|
||||
if (start)
|
||||
*start = cluster->stack_tops[i];
|
||||
if (size)
|
||||
*size = cluster->stack_size;
|
||||
cluster->stack_segment_occupied[i] = true;
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
free_aux_stack(WASMCluster *cluster, uint32 start)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < cluster_max_thread_num; i++) {
|
||||
if (start == cluster->stack_tops[i]) {
|
||||
os_mutex_lock(&cluster->lock);
|
||||
cluster->stack_segment_occupied[i] = false;
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
WASMCluster *
|
||||
wasm_cluster_create(WASMExecEnv *exec_env)
|
||||
{
|
||||
WASMCluster *cluster;
|
||||
uint64 total_size;
|
||||
uint32 aux_stack_start, aux_stack_size, i;
|
||||
|
||||
bh_assert(exec_env->cluster == NULL);
|
||||
if (!(cluster = wasm_runtime_malloc(sizeof(WASMCluster)))) {
|
||||
LOG_ERROR("thread manager error: failed to allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
memset(cluster, 0, sizeof(WASMCluster));
|
||||
|
||||
exec_env->cluster = cluster;
|
||||
|
||||
bh_list_init(&cluster->exec_env_list);
|
||||
bh_list_insert(&cluster->exec_env_list, exec_env);
|
||||
if (os_mutex_init(&cluster->lock) != 0) {
|
||||
wasm_runtime_free(cluster);
|
||||
LOG_ERROR("thread manager error: failed to init mutex");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Prepare the aux stack top and size for every thread */
|
||||
if (!wasm_exec_env_get_aux_stack(exec_env,
|
||||
&aux_stack_start,
|
||||
&aux_stack_size)) {
|
||||
LOG_VERBOSE("No aux stack info for this module, can't create thread");
|
||||
|
||||
/* If the module don't have aux stack info, don't throw error here,
|
||||
but remain stack_tops and stack_segment_occupied as NULL */
|
||||
os_mutex_lock(&cluster_list_lock);
|
||||
if (bh_list_insert(cluster_list, cluster) != 0) {
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
goto fail;
|
||||
}
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
cluster->stack_size = aux_stack_size / (cluster_max_thread_num + 1);
|
||||
if (cluster->stack_size == 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set initial aux stack top to the instance and
|
||||
aux stack boundary to the main exec_env */
|
||||
if (!wasm_exec_env_set_aux_stack(exec_env, aux_stack_start,
|
||||
cluster->stack_size))
|
||||
goto fail;
|
||||
|
||||
if (cluster_max_thread_num != 0) {
|
||||
total_size = cluster_max_thread_num * sizeof(uint32);
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(cluster->stack_tops =
|
||||
wasm_runtime_malloc((uint32)total_size))) {
|
||||
goto fail;
|
||||
}
|
||||
memset(cluster->stack_tops, 0, (uint32)total_size);
|
||||
|
||||
if (!(cluster->stack_segment_occupied =
|
||||
wasm_runtime_malloc(cluster_max_thread_num * sizeof(bool)))) {
|
||||
goto fail;
|
||||
}
|
||||
memset(cluster->stack_segment_occupied, 0,
|
||||
cluster_max_thread_num * sizeof(bool));
|
||||
|
||||
/* Reserve space for main instance */
|
||||
aux_stack_start -= cluster->stack_size;
|
||||
|
||||
for (i = 0; i < cluster_max_thread_num; i++) {
|
||||
cluster->stack_tops[i] = aux_stack_start - cluster->stack_size * i;
|
||||
}
|
||||
}
|
||||
|
||||
os_mutex_lock(&cluster_list_lock);
|
||||
if (bh_list_insert(cluster_list, cluster) != 0) {
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
goto fail;
|
||||
}
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
|
||||
return cluster;
|
||||
|
||||
fail:
|
||||
if (cluster)
|
||||
wasm_cluster_destroy(cluster);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_cluster_visitor(void *node, void *user_data)
|
||||
{
|
||||
DestroyCallBackNode *destroy_node = (DestroyCallBackNode *)node;
|
||||
WASMCluster *cluster = (WASMCluster *)user_data;
|
||||
|
||||
destroy_node->destroy_cb(cluster);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_destroy(WASMCluster *cluster)
|
||||
{
|
||||
traverse_list(destroy_callback_list,
|
||||
destroy_cluster_visitor, (void *)cluster);
|
||||
|
||||
/* Remove the cluster from the cluster list */
|
||||
os_mutex_lock(&cluster_list_lock);
|
||||
bh_list_remove(cluster_list, cluster);
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
|
||||
os_mutex_destroy(&cluster->lock);
|
||||
|
||||
if (cluster->stack_tops)
|
||||
wasm_runtime_free(cluster->stack_tops);
|
||||
if (cluster->stack_segment_occupied)
|
||||
wasm_runtime_free(cluster->stack_segment_occupied);
|
||||
wasm_runtime_free(cluster);
|
||||
}
|
||||
|
||||
static void
|
||||
free_node_visitor(void *node, void *user_data)
|
||||
{
|
||||
wasm_runtime_free(node);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_cancel_all_callbacks()
|
||||
{
|
||||
traverse_list(destroy_callback_list, free_node_visitor, NULL);
|
||||
}
|
||||
|
||||
WASMCluster *
|
||||
wasm_exec_env_get_cluster(WASMExecEnv *exec_env)
|
||||
{
|
||||
return exec_env->cluster;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
exec_env->cluster = cluster;
|
||||
|
||||
os_mutex_lock(&cluster->lock);
|
||||
if (bh_list_insert(&cluster->exec_env_list, exec_env) != 0)
|
||||
ret = false;
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
|
||||
{
|
||||
bool ret = true;
|
||||
bh_assert(exec_env->cluster == cluster);
|
||||
os_mutex_lock(&cluster->lock);
|
||||
if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0)
|
||||
ret = false;
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
|
||||
if (cluster->exec_env_list.len == 0) {
|
||||
/* exec_env_list empty, destroy the cluster */
|
||||
wasm_cluster_destroy(cluster);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* start routine of thread manager */
|
||||
static void*
|
||||
thread_manager_start_routine(void *arg)
|
||||
{
|
||||
void *ret;
|
||||
WASMExecEnv *exec_env = (WASMExecEnv *)arg;
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster != NULL);
|
||||
|
||||
exec_env->handle = os_self_thread();
|
||||
ret = exec_env->thread_start_routine(exec_env);
|
||||
|
||||
/* Routine exit */
|
||||
/* Free aux stack space */
|
||||
free_aux_stack(cluster,
|
||||
exec_env->aux_stack_boundary + cluster->stack_size);
|
||||
/* Detach the native thread here to ensure the resources are freed */
|
||||
wasm_cluster_detach_thread(exec_env);
|
||||
/* Remove and destroy exec_env */
|
||||
wasm_cluster_del_exec_env(cluster, exec_env);
|
||||
wasm_exec_env_destroy_internal(exec_env);
|
||||
|
||||
os_thread_exit(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32
|
||||
wasm_cluster_create_thread(WASMExecEnv *exec_env,
|
||||
wasm_module_inst_t module_inst,
|
||||
void* (*thread_routine)(void *),
|
||||
void *arg)
|
||||
{
|
||||
WASMCluster *cluster;
|
||||
WASMExecEnv *new_exec_env;
|
||||
uint32 aux_stack_start, aux_stack_size;
|
||||
korp_tid tid;
|
||||
|
||||
cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster);
|
||||
|
||||
new_exec_env = wasm_exec_env_create_internal(
|
||||
module_inst, exec_env->wasm_stack_size);
|
||||
if (!new_exec_env)
|
||||
return -1;
|
||||
|
||||
if (!allocate_aux_stack(cluster, &aux_stack_start, &aux_stack_size)) {
|
||||
LOG_ERROR("thread manager error: "
|
||||
"failed to allocate aux stack space for new thread");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* Set aux stack for current thread */
|
||||
if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start,
|
||||
aux_stack_size)) {
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
|
||||
goto fail2;
|
||||
|
||||
new_exec_env->thread_start_routine = thread_routine;
|
||||
new_exec_env->thread_arg = arg;
|
||||
|
||||
if (0 != os_thread_create(&tid, thread_manager_start_routine,
|
||||
(void *)new_exec_env,
|
||||
APP_THREAD_STACK_SIZE_DEFAULT)) {
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
wasm_cluster_del_exec_env(cluster, new_exec_env);
|
||||
fail2:
|
||||
/* free the allocated aux stack space */
|
||||
free_aux_stack(cluster, aux_stack_start);
|
||||
fail1:
|
||||
wasm_exec_env_destroy(new_exec_env);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32
|
||||
wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val)
|
||||
{
|
||||
return os_thread_join(exec_env->handle, ret_val);
|
||||
}
|
||||
|
||||
int32
|
||||
wasm_cluster_detach_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
return os_thread_detach(exec_env->handle);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
|
||||
{
|
||||
WASMCluster *cluster;
|
||||
|
||||
cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster);
|
||||
|
||||
/* App exit the thread, free the resources before exit native thread */
|
||||
/* Free aux stack space */
|
||||
free_aux_stack(cluster,
|
||||
exec_env->aux_stack_boundary + cluster->stack_size);
|
||||
/* Detach the native thread here to ensure the resources are freed */
|
||||
wasm_cluster_detach_thread(exec_env);
|
||||
/* Remove and destroy exec_env */
|
||||
wasm_cluster_del_exec_env(cluster, exec_env);
|
||||
wasm_exec_env_destroy_internal(exec_env);
|
||||
|
||||
os_thread_exit(retval);
|
||||
}
|
||||
|
||||
int32
|
||||
wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
/* Set the termination flag */
|
||||
exec_env->suspend_flags |= 0x01;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
terminate_thread_visitor(void *node, void *user_data)
|
||||
{
|
||||
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
|
||||
WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
|
||||
|
||||
if (curr_exec_env == exec_env)
|
||||
return;
|
||||
|
||||
wasm_cluster_cancel_thread(curr_exec_env);
|
||||
wasm_cluster_join_thread(curr_exec_env, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_terminate_all(WASMCluster *cluster)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list,
|
||||
terminate_thread_visitor, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_terminate_all_except_self(WASMCluster *cluster,
|
||||
WASMExecEnv *exec_env)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list,
|
||||
terminate_thread_visitor, (void *)exec_env);
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *))
|
||||
{
|
||||
DestroyCallBackNode *node;
|
||||
|
||||
if (!(node = wasm_runtime_malloc(sizeof(DestroyCallBackNode)))) {
|
||||
LOG_ERROR("thread manager error: failed to allocate memory");
|
||||
return false;
|
||||
}
|
||||
node->destroy_cb = callback;
|
||||
bh_list_insert(destroy_callback_list, node);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
/* Set the suspend flag */
|
||||
exec_env->suspend_flags |= 0x02;
|
||||
}
|
||||
|
||||
static void
|
||||
suspend_thread_visitor(void *node, void *user_data)
|
||||
{
|
||||
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
|
||||
WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
|
||||
|
||||
if (curr_exec_env == exec_env)
|
||||
return;
|
||||
|
||||
wasm_cluster_suspend_thread(curr_exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_all(WASMCluster *cluster)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list,
|
||||
suspend_thread_visitor, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
|
||||
WASMExecEnv *exec_env)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list,
|
||||
suspend_thread_visitor, (void *)exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_resume_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
exec_env->suspend_flags &= ~0x02;
|
||||
}
|
||||
|
||||
static void
|
||||
resume_thread_visitor(void *node, void *user_data)
|
||||
{
|
||||
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
|
||||
|
||||
wasm_cluster_resume_thread(curr_exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_resume_all(WASMCluster *cluster)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list, resume_thread_visitor, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
set_exception_visitor(void *node, void *user_data)
|
||||
{
|
||||
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
|
||||
WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
|
||||
WASMModuleInstanceCommon *module_inst = get_module_inst(exec_env);
|
||||
WASMModuleInstanceCommon *curr_module_inst =
|
||||
get_module_inst(curr_exec_env);
|
||||
const char *exception = wasm_runtime_get_exception(module_inst);
|
||||
/* skip "Exception: " */
|
||||
exception += 11;
|
||||
|
||||
if (curr_exec_env != exec_env) {
|
||||
curr_module_inst = get_module_inst(curr_exec_env);
|
||||
wasm_runtime_set_exception(curr_module_inst, exception);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_spread_exception(WASMExecEnv *exec_env)
|
||||
{
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
|
||||
traverse_list(&cluster->exec_env_list, set_exception_visitor, exec_env);
|
||||
}
|
||||
116
core/iwasm/libraries/thread-mgr/thread_manager.h
Normal file
116
core/iwasm/libraries/thread-mgr/thread_manager.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _THREAD_MANAGER_H
|
||||
#define _THREAD_MANAGER_H
|
||||
|
||||
#include "bh_common.h"
|
||||
#include "bh_log.h"
|
||||
#include "wasm_export.h"
|
||||
#include "../interpreter/wasm.h"
|
||||
#include "../common/wasm_runtime_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct WASMCluster
|
||||
{
|
||||
struct WASMCluster *next;
|
||||
|
||||
korp_mutex lock;
|
||||
bh_list exec_env_list;
|
||||
|
||||
/* The aux stack of a module with shared memory will be
|
||||
divided into several segments. This array store the
|
||||
stack top of different segments */
|
||||
uint32 *stack_tops;
|
||||
/* Size of every stack segment */
|
||||
uint32 stack_size;
|
||||
/* Record which segments are occupied */
|
||||
bool *stack_segment_occupied;
|
||||
} WASMCluster;
|
||||
|
||||
void wasm_cluster_set_max_thread_num(uint32 num);
|
||||
|
||||
bool
|
||||
thread_manager_init();
|
||||
|
||||
void
|
||||
thread_manager_destroy();
|
||||
|
||||
/* Create cluster */
|
||||
WASMCluster *
|
||||
wasm_cluster_create(WASMExecEnv *exec_env);
|
||||
|
||||
/* Destroy cluster */
|
||||
void
|
||||
wasm_cluster_destroy(WASMCluster *cluster);
|
||||
|
||||
/* Get the cluster of the current exec_env */
|
||||
WASMCluster*
|
||||
wasm_exec_env_get_cluster(WASMExecEnv *exec_env);
|
||||
|
||||
int32
|
||||
wasm_cluster_create_thread(WASMExecEnv *exec_env,
|
||||
wasm_module_inst_t module_inst,
|
||||
void* (*thread_routine)(void *),
|
||||
void *arg);
|
||||
|
||||
int32
|
||||
wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val);
|
||||
|
||||
int32
|
||||
wasm_cluster_detach_thread(WASMExecEnv *exec_env);
|
||||
|
||||
int32
|
||||
wasm_cluster_cancel_thread(WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval);
|
||||
|
||||
bool
|
||||
wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *));
|
||||
|
||||
void
|
||||
wasm_cluster_cancel_all_callbacks();
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_all(WASMCluster *cluster);
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
|
||||
WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_thread(WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_resume_thread(WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_resume_all(WASMCluster *cluster);
|
||||
|
||||
void
|
||||
wasm_cluster_terminate_all(WASMCluster *cluster);
|
||||
|
||||
void
|
||||
wasm_cluster_terminate_all_except_self(WASMCluster *cluster,
|
||||
WASMExecEnv *exec_env);
|
||||
|
||||
bool
|
||||
wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env);
|
||||
|
||||
bool
|
||||
wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_spread_exception(WASMExecEnv *exec_env);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* end of _THREAD_MANAGER_H */
|
||||
13
core/iwasm/libraries/thread-mgr/thread_mgr.cmake
Normal file
13
core/iwasm/libraries/thread-mgr/thread_mgr.cmake
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
set (THREAD_MGR_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_definitions (-DWASM_ENABLE_THREAD_MGR=1)
|
||||
|
||||
include_directories(${THREAD_MGR_DIR})
|
||||
|
||||
file (GLOB source_all ${THREAD_MGR_DIR}/*.c)
|
||||
|
||||
set (THREAD_MGR_SOURCE ${source_all})
|
||||
|
||||
@ -242,16 +242,16 @@ os_mutex_destroy(korp_mutex *mutex)
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
os_mutex_lock(korp_mutex *mutex)
|
||||
{
|
||||
aos_mutex_lock(mutex, AOS_WAIT_FOREVER);
|
||||
return aos_mutex_lock(mutex, AOS_WAIT_FOREVER);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
os_mutex_unlock(korp_mutex *mutex)
|
||||
{
|
||||
aos_mutex_unlock(mutex);
|
||||
return aos_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@ -19,10 +19,12 @@ typedef struct {
|
||||
static void *os_thread_wrapper(void *arg)
|
||||
{
|
||||
thread_wrapper_arg * targ = arg;
|
||||
thread_start_routine_t start_func = targ->start;
|
||||
void *thread_arg = targ->arg;
|
||||
printf("THREAD CREATE %p\n", &targ);
|
||||
targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff);
|
||||
targ->start(targ->arg);
|
||||
BH_FREE(targ);
|
||||
start_func(thread_arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -114,7 +116,7 @@ int os_mutex_destroy(korp_mutex *mutex)
|
||||
locking the mutex indicates some logic error present in
|
||||
the program somewhere.
|
||||
Don't try to recover error for an existing unknown error.*/
|
||||
void os_mutex_lock(korp_mutex *mutex)
|
||||
int os_mutex_lock(korp_mutex *mutex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -124,13 +126,14 @@ void os_mutex_lock(korp_mutex *mutex)
|
||||
printf("vm mutex lock failed (ret=%d)!\n", ret);
|
||||
exit(-1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returned error (EINVAL, EAGAIN and EPERM) from
|
||||
unlocking the mutex indicates some logic error present
|
||||
in the program somewhere.
|
||||
Don't try to recover error for an existing unknown error.*/
|
||||
void os_mutex_unlock(korp_mutex *mutex)
|
||||
int os_mutex_unlock(korp_mutex *mutex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -140,6 +143,7 @@ void os_mutex_unlock(korp_mutex *mutex)
|
||||
printf("vm mutex unlock failed (ret=%d)!\n", ret);
|
||||
exit(-1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int os_cond_init(korp_cond *cond)
|
||||
@ -221,6 +225,16 @@ int os_thread_join(korp_tid thread, void **value_ptr)
|
||||
return pthread_join(thread, value_ptr);
|
||||
}
|
||||
|
||||
int os_thread_detach(korp_tid thread)
|
||||
{
|
||||
return pthread_detach(thread);
|
||||
}
|
||||
|
||||
void os_thread_exit(void *retval)
|
||||
{
|
||||
return pthread_exit(retval);
|
||||
}
|
||||
|
||||
uint8 *os_thread_get_stack_boundary()
|
||||
{
|
||||
pthread_t self = pthread_self();
|
||||
|
||||
@ -68,6 +68,22 @@ int os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start,
|
||||
*/
|
||||
int os_thread_join(korp_tid thread, void **retval);
|
||||
|
||||
/**
|
||||
* Detach the thread specified by thread
|
||||
*
|
||||
* @param thread the thread to detach
|
||||
*
|
||||
* @return return 0 if success
|
||||
*/
|
||||
int os_thread_detach(korp_tid);
|
||||
|
||||
/**
|
||||
* Exit current thread
|
||||
*
|
||||
* @param retval the return value of the current thread
|
||||
*/
|
||||
void os_thread_exit(void *retval);
|
||||
|
||||
/**
|
||||
* Suspend execution of the calling thread for (at least)
|
||||
* usec microseconds
|
||||
|
||||
@ -82,9 +82,9 @@ int os_mutex_init(korp_mutex *mutex);
|
||||
|
||||
int os_mutex_destroy(korp_mutex *mutex);
|
||||
|
||||
void os_mutex_lock(korp_mutex *mutex);
|
||||
int os_mutex_lock(korp_mutex *mutex);
|
||||
|
||||
void os_mutex_unlock(korp_mutex *mutex);
|
||||
int os_mutex_unlock(korp_mutex *mutex);
|
||||
|
||||
|
||||
/**************************************************
|
||||
|
||||
@ -24,14 +24,14 @@ int os_mutex_destroy(korp_mutex *mutex)
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
void os_mutex_lock(korp_mutex *mutex)
|
||||
int os_mutex_lock(korp_mutex *mutex)
|
||||
{
|
||||
sgx_thread_mutex_lock(mutex);
|
||||
return sgx_thread_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
void os_mutex_unlock(korp_mutex *mutex)
|
||||
int os_mutex_unlock(korp_mutex *mutex)
|
||||
{
|
||||
sgx_thread_mutex_unlock(mutex);
|
||||
return sgx_thread_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
int os_cond_init(korp_cond *cond)
|
||||
|
||||
@ -350,14 +350,14 @@ int os_mutex_destroy(korp_mutex *mutex)
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
void os_mutex_lock(korp_mutex *mutex)
|
||||
int os_mutex_lock(korp_mutex *mutex)
|
||||
{
|
||||
k_mutex_lock(mutex, K_FOREVER);
|
||||
return k_mutex_lock(mutex, K_FOREVER);
|
||||
}
|
||||
|
||||
void os_mutex_unlock(korp_mutex *mutex)
|
||||
int os_mutex_unlock(korp_mutex *mutex)
|
||||
{
|
||||
k_mutex_unlock(mutex);
|
||||
return k_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
int os_cond_init(korp_cond *cond)
|
||||
|
||||
Reference in New Issue
Block a user