mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2024-11-26 07:21:54 +00:00
Enable shared memory && add pthread support (#282)
This commit is contained in:
parent
f4d4d69736
commit
d98ab63e5c
|
@ -33,6 +33,7 @@ iwasm VM core
|
|||
- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions)
|
||||
- [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops)
|
||||
- [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations)
|
||||
- [Shared memmory](https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#shared-linear-memory)
|
||||
|
||||
### Performance and memory usage
|
||||
The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page.
|
||||
|
|
|
@ -140,6 +140,18 @@ if (WAMR_BUILD_BULK_MEMORY EQUAL 1)
|
|||
else ()
|
||||
add_definitions (-DWASM_ENABLE_BULK_MEMORY=0)
|
||||
endif ()
|
||||
if (WAMR_BUILD_SHARED_MEMORY EQUAL 1)
|
||||
add_definitions (-DWASM_ENABLE_SHARED_MEMORY=1)
|
||||
message (" Shared memory enabled")
|
||||
else ()
|
||||
add_definitions (-DWASM_ENABLE_SHARED_MEMORY=0)
|
||||
endif ()
|
||||
if (WAMR_BUILD_THREAD_MGR EQUAL 1)
|
||||
message (" Thread manager enabled")
|
||||
endif ()
|
||||
if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
|
||||
message (" Lib pthread enabled")
|
||||
endif ()
|
||||
if (WAMR_BUILD_MINI_LOADER EQUAL 1)
|
||||
add_definitions (-DWASM_ENABLE_MINI_LOADER=1)
|
||||
message (" WASM mini loader enabled")
|
||||
|
|
|
@ -69,6 +69,18 @@ if (WAMR_BUILD_LIBC_WASI EQUAL 1)
|
|||
include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake)
|
||||
endif ()
|
||||
|
||||
if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
|
||||
include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake)
|
||||
# Enable the dependent feature if lib pthread is enabled
|
||||
set (WAMR_BUILD_THREAD_MGR 1)
|
||||
set (WAMR_BUILD_BULK_MEMORY 1)
|
||||
set (WAMR_BUILD_SHARED_MEMORY 1)
|
||||
endif ()
|
||||
|
||||
if (WAMR_BUILD_THREAD_MGR EQUAL 1)
|
||||
include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake)
|
||||
endif ()
|
||||
|
||||
####################### Common sources #######################
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \
|
||||
-Wall -Wno-unused-parameter -Wno-pedantic")
|
||||
|
@ -106,6 +118,8 @@ set (source_all
|
|||
${WASM_APP_LIB_SOURCE_ALL}
|
||||
${NATIVE_INTERFACE_SOURCE}
|
||||
${APP_MGR_SOURCE}
|
||||
${LIB_PTHREAD_SOURCE}
|
||||
${THREAD_MGR_SOURCE}
|
||||
)
|
||||
|
||||
set (WAMR_RUNTIME_LIB_SOURCE ${source_all})
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -57,6 +57,16 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the
|
|||
- **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set
|
||||
Note: the mini loader doesn't check the integrity of the WASM binary file, user must ensure that the WASM file is not mal-formed.
|
||||
|
||||
#### **Enable shared memory feature**
|
||||
- **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set
|
||||
|
||||
#### **Enable thread manager**
|
||||
- **WAMR_BUILD_THREAD_MGR**=1/0, default to disable if not set
|
||||
|
||||
#### **Enable Lib-pthread**
|
||||
- **WAMR_BUILD_LIB_PTHREAD**=1/0, default to disable if not set
|
||||
> Note: The dependent feature of lib pthread such as the `shared memory` and `thread manager` will be enabled automatically.
|
||||
|
||||
**Combination of configurations:**
|
||||
|
||||
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:
|
||||
|
|
157
doc/pthread_library.md
Normal file
157
doc/pthread_library.md
Normal file
|
@ -0,0 +1,157 @@
|
|||
# WAMR pthread library
|
||||
|
||||
WAMR provides a built-in library to support pthread APIs. You can call pthread APIs in your application source code.
|
||||
|
||||
## Build and run
|
||||
Suppose you have written a C program calling pthread_create() to create a thread, and the file name is main.c
|
||||
``` C
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
void *thread_routine(void *arg)
|
||||
{
|
||||
printf("Enter thread\n");
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
if (0 != pthread_create(&tid, NULL, thread_routine, NULL)) {
|
||||
printf("Failed to create thread\n");
|
||||
}
|
||||
|
||||
if (0 != pthread_join(tid, NULL)) {
|
||||
printf("Failed to join thread %d.\n", tid);
|
||||
}
|
||||
|
||||
printf("Exit\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
**Build with libc-builtin**
|
||||
|
||||
To build this C program into WebAssembly app with libc-builtin, you can use this command:
|
||||
``` bash
|
||||
/opt/wasi-sdk/bin/clang --target=wasm32 \
|
||||
--sysroot=${WAMR_ROOT}/wamr-sdk/app/libc-builtin-sysroot \
|
||||
-O3 -pthread -nostdlib -z stack-size=32768 \
|
||||
-Wl,--shared-memory \
|
||||
-Wl,--initial-memory=131072,--max-memory=131072 \
|
||||
-Wl,--allow-undefined-file=${WAMR_ROOT}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt \
|
||||
-Wl,--no-entry -Wl,--export=main \
|
||||
-Wl,--export=__heap_base,--export=__data_end \
|
||||
-Wl,--export=__wasm_call_ctors \
|
||||
main.c -o test.wasm
|
||||
# -pthread: it will enable some dependent WebAssembly features for thread
|
||||
# -nostdlib: disable the WASI standard library as we only support libc-builtin currently
|
||||
# -z stack-size=: specify the total aux stack size
|
||||
# -Wl,--export=__heap_base,--export=__data_end: export these globals so the runtime can resolve the total aux stack size and the start offset of the stack top
|
||||
# -Wl,--export=__wasm_call_ctors: export the init function to initialize the passive data segments
|
||||
```
|
||||
|
||||
**Build with libc-WASI**
|
||||
|
||||
You can also build this program with WASI, but we need to make some changes to wasi-sysroot:
|
||||
|
||||
1. disable malloc / free of wasi as they don't support shared memory
|
||||
``` bash
|
||||
/opt/wasi-sdk/bin/llvm-ar -d /opt/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi/libc.a dlmalloc.o
|
||||
```
|
||||
2. copy the pthread.h to wasi-sysroot so the compiler can find it:
|
||||
``` bash
|
||||
cp ${WAMR_ROOT}/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h /opt/wasi-sdk/share/wasi-sysroot/include
|
||||
```
|
||||
> Note: </br>
|
||||
>1. Remember to back up the original sysroot files
|
||||
>2. wasi-sdk 9.0 or above are not supported, please use 7.0 or 8.0
|
||||
|
||||
Then build the program with this command:
|
||||
``` bash
|
||||
/opt/wasi-sdk/bin/clang -pthread -O3 \
|
||||
-Wl,--shared-memory,--max-memory=196608 \
|
||||
-Wl,--allow-undefined,--no-check-features \
|
||||
-Wl,--export=__heap_base,--export=__data_end \
|
||||
main.c -o test.wasm
|
||||
# -Wl,--no-check-features: the errno.o in wasi-sysroot is not compatible with pthread feature, pass this option to avoid errors
|
||||
```
|
||||
|
||||
Currently WAMR disables pthread library by default. To run the module with pthread support, please build the runtime with `-DWAMR_BUILD_LIB_PTHREAD=1`
|
||||
``` bash
|
||||
cd ${WAMR_ROOT}/product-mini/platforms/linux
|
||||
mkdir build && cd build
|
||||
cmake .. -DWAMR_BUILD_LIB_PTHREAD=1
|
||||
make
|
||||
# Then you can run the wasm module above:
|
||||
./iwasm test.wasm
|
||||
```
|
||||
|
||||
> Note: Currently pthread library is not supported in AoT mode.
|
||||
|
||||
[Here](../samples/multi-thread) is also a sample to show how wasm-apps use pthread APIs to create threads, and how to build it with cmake. You can build this sample and have a try:
|
||||
``` bash
|
||||
cd ${WAMR_ROOT}/samples/multi-thread
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make
|
||||
# Run wasm application
|
||||
./iwasm wasm-apps/test.wasm
|
||||
```
|
||||
|
||||
|
||||
## Aux stack seperation
|
||||
The compiler may use some spaces in the linear memory as an auxiliary stack. When pthread is enabled, every thread should have its own aux stack space, so the total aux stack space reserved by the compiler will be divided into N + 1 parts, where N is the maximum number of threads that can be created by the user code.
|
||||
|
||||
The default value of N is 4, which means you can create 4 threads at most. This value can be changed by an option if you are using product-mini:
|
||||
``` bash
|
||||
./iwasm --max-threads=n test.wasm
|
||||
```
|
||||
If you are going to develop your own runtime product, you can use the API `wasm_runtime_set_max_thread_num` to set the value, or you can change the macro `CLUSTER_MAX_THREAD_NUM` in [config.h](../core/config.h),
|
||||
|
||||
> Note: the total size of aux stack reserved by compiler can be set with `-z stack-size` option during compilation. If you need to create more threads, please set a larger value, otherwise it is easy to cause aux stack overflow.
|
||||
|
||||
## Supported APIs
|
||||
``` C
|
||||
/* Thread APIs */
|
||||
int pthread_create(pthread_t *thread, const void *attr,
|
||||
void *(*start_routine) (void *), void *arg);
|
||||
|
||||
int pthread_join(pthread_t thread, void **retval);
|
||||
|
||||
int pthread_detach(pthread_t thread);
|
||||
|
||||
int pthread_cancel(pthread_t thread);
|
||||
|
||||
pthread_t pthread_self(void);
|
||||
|
||||
void pthread_exit(void *retval);
|
||||
|
||||
/* Mutex APIs */
|
||||
int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr);
|
||||
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex);
|
||||
|
||||
/* Cond APIs */
|
||||
int pthread_cond_init(pthread_cond_t *cond, const void *attr);
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
unsigned int useconds);
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cond);
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond);
|
||||
```
|
||||
|
||||
## Known limits
|
||||
- `pthread_attr_t`, `pthread_mutexattr_t` and `pthread_condattr_t` are not supported yet, so please pass `NULL` as the second argument of `pthread_create`, `pthread_mutex_init` and `pthread_cond_init`.
|
||||
- The `errno.o` in wasi-sysroot is not compatible with this feature, so using errno in multi-thread may cause unexpected behavior.
|
||||
- Currently `struct timespec` is not supported, so the prototype of `pthread_cond_timedwait` is different from the native one, it takes an unsigned int argument `useconds` to indicate the waiting time.
|
|
@ -44,6 +44,9 @@ print_help()
|
|||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
printf(" --module-path= Indicate a module search path. default is current\n"
|
||||
" directory('./')\n");
|
||||
#endif
|
||||
#if WASM_ENABLE_LIB_PTHREAD != 0
|
||||
printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
@ -125,6 +128,10 @@ app_instance_repl(wasm_module_inst_t module_inst)
|
|||
else
|
||||
cmd[n - 1] = '\0';
|
||||
}
|
||||
if (!strcmp(cmd, "__exit__")) {
|
||||
printf("exit repl mode\n");
|
||||
break;
|
||||
}
|
||||
app_argv = split_string(cmd, &app_argc);
|
||||
if (app_argv == NULL) {
|
||||
LOG_ERROR("Wasm prepare param failed: split string failed.\n");
|
||||
|
@ -300,6 +307,13 @@ main(int argc, char *argv[])
|
|||
return print_help();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if WASM_ENABLE_LIB_PTHREAD != 0
|
||||
else if (!strncmp(argv[0], "--max-threads=", 14)) {
|
||||
if (argv[0][14] == '\0')
|
||||
return print_help();
|
||||
wasm_runtime_set_max_thread_num(atoi(argv[0] + 14));
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return print_help();
|
||||
|
|
47
samples/multi-thread/CMakeLists.txt
Normal file
47
samples/multi-thread/CMakeLists.txt
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
project(pthread)
|
||||
|
||||
################ runtime settings ################
|
||||
set(WAMR_BUILD_PLATFORM "linux")
|
||||
|
||||
# Resetdefault linker flags
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
# WAMR features switch
|
||||
set(WAMR_BUILD_TARGET "X86_64")
|
||||
set(WAMR_BUILD_INTERP 1)
|
||||
set(WAMR_BUILD_AOT 0)
|
||||
set(WAMR_BUILD_JIT 0)
|
||||
set(WAMR_BUILD_LIBC_BUILTIN 1)
|
||||
set(WAMR_BUILD_FAST_INTERP 1)
|
||||
set(WAMR_BUILD_LIB_PTHREAD 1)
|
||||
|
||||
# compiling and linking flags
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security")
|
||||
|
||||
# build out vmlib
|
||||
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
|
||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
|
||||
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
|
||||
################################################
|
||||
|
||||
|
||||
################ wasm application ################
|
||||
add_subdirectory(wasm-apps)
|
||||
|
||||
################ wamr runtime ################
|
||||
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
|
||||
|
||||
set (RUNTIME_SOURCE_ALL
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../product-mini/platforms/linux/main.c
|
||||
${UNCOMMON_SHARED_SOURCE}
|
||||
)
|
||||
add_executable (iwasm ${RUNTIME_SOURCE_ALL})
|
||||
target_link_libraries(iwasm vmlib -lpthread -lm)
|
||||
|
34
samples/multi-thread/wasm-apps/CMakeLists.txt
Normal file
34
samples/multi-thread/wasm-apps/CMakeLists.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
project(wasm-apps)
|
||||
|
||||
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR wasm32)
|
||||
set (CMAKE_SYSROOT ${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot)
|
||||
|
||||
if (NOT DEFINED WASI_SDK_DIR)
|
||||
set (WASI_SDK_DIR "/opt/wasi-sdk")
|
||||
endif ()
|
||||
|
||||
set (CMAKE_C_FLAGS "-nostdlib -pthread -Qunused-arguments")
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -z stack-size=32768")
|
||||
set (CMAKE_C_COMPILER_TARGET "wasm32")
|
||||
set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang")
|
||||
|
||||
set (DEFINED_SYMBOLS
|
||||
"${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt")
|
||||
|
||||
set (CMAKE_EXE_LINKER_FLAGS
|
||||
"-Wl,--shared-memory,--max-memory=131072, \
|
||||
-Wl,--no-entry,--strip-all,--export=main, \
|
||||
-Wl,--export=__heap_base,--export=__data_end \
|
||||
-Wl,--export=__wasm_call_ctors \
|
||||
-Wl,--allow-undefined-file=${DEFINED_SYMBOLS}"
|
||||
)
|
||||
|
||||
add_executable(test.wasm main.c)
|
||||
target_link_libraries(test.wasm)
|
69
samples/multi-thread/wasm-apps/main.c
Normal file
69
samples/multi-thread/wasm-apps/main.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t mutex;
|
||||
static pthread_cond_t cond;
|
||||
|
||||
static void *thread(void *arg)
|
||||
{
|
||||
int *num = (int *)arg;
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
printf("thread start \n");
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
*num = *num + 1;
|
||||
printf("num: %d\n", *num);
|
||||
}
|
||||
|
||||
pthread_cond_signal(&cond);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
printf("thread exit \n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pthread_t tid;
|
||||
int num = 0, ret = -1;
|
||||
|
||||
if (pthread_mutex_init(&mutex, NULL) != 0) {
|
||||
printf("Failed to init mutex.\n");
|
||||
return -1;
|
||||
}
|
||||
if (pthread_cond_init(&cond, NULL) != 0) {
|
||||
printf("Failed to init cond.\n");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
if (pthread_create(&tid, NULL, thread, &num) != 0) {
|
||||
printf("Failed to create thread.\n");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
printf("cond wait start\n");
|
||||
pthread_cond_wait(&cond, &mutex);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
printf("cond wait success.\n");
|
||||
|
||||
if (pthread_join(tid, NULL) != 0) {
|
||||
printf("Failed to join thread.\n");
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
fail2:
|
||||
pthread_cond_destroy(&cond);
|
||||
fail1:
|
||||
pthread_mutex_destroy(&mutex);
|
||||
|
||||
return ret;
|
||||
}
|
49
wamr-sdk/app/libc-builtin-sysroot/include/pthread.h
Normal file
49
wamr-sdk/app/libc-builtin-sysroot/include/pthread.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _WAMR_LIB_PTHREAD_H
|
||||
#define _WAMR_LIB_PTHREAD_H
|
||||
|
||||
/* Data type define of pthread, mutex and cond */
|
||||
typedef unsigned int pthread_t;
|
||||
typedef unsigned int pthread_mutex_t;
|
||||
typedef unsigned int pthread_cond_t;
|
||||
|
||||
/* Thread APIs */
|
||||
int pthread_create(pthread_t *thread, const void *attr,
|
||||
void *(*start_routine) (void *), void *arg);
|
||||
|
||||
int pthread_join(pthread_t thread, void **retval);
|
||||
|
||||
int pthread_detach(pthread_t thread);
|
||||
|
||||
int pthread_cancel(pthread_t thread);
|
||||
|
||||
pthread_t pthread_self(void);
|
||||
|
||||
void pthread_exit(void *retval);
|
||||
|
||||
/* Mutex APIs */
|
||||
int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr);
|
||||
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex);
|
||||
|
||||
/* Cond APIs */
|
||||
int pthread_cond_init(pthread_cond_t *cond, const void *attr);
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
unsigned int useconds);
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cond);
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond);
|
||||
|
||||
#endif /* end of _WAMR_LIB_PTHREAD_H */
|
|
@ -62,3 +62,18 @@ isxdigit
|
|||
tolower
|
||||
toupper
|
||||
isalnum
|
||||
pthread_create
|
||||
pthread_join
|
||||
pthread_detach
|
||||
pthread_cancel
|
||||
pthread_self
|
||||
pthread_exit
|
||||
pthread_mutex_init
|
||||
pthread_mutex_lock
|
||||
pthread_mutex_unlock
|
||||
pthread_mutex_destroy
|
||||
pthread_cond_init
|
||||
pthread_cond_wait
|
||||
pthread_cond_timedwait
|
||||
pthread_cond_signal
|
||||
pthread_cond_destroy
|
||||
|
|
Loading…
Reference in New Issue
Block a user