Enable shared memory && add pthread support (#282)

This commit is contained in:
Xu Jun 2020-06-15 19:04:04 +08:00 committed by GitHub
parent f4d4d69736
commit d98ab63e5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 3081 additions and 289 deletions

View File

@ -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.

View File

@ -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")

View File

@ -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})

View File

@ -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_ */

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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(&registered_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(&registered_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(&registered_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(&registered_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()
*/

View File

@ -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.
*

View 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 */

View 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 */

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View 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})

View 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);
}

View File

@ -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 },

View File

@ -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);
}

View 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);
}

View 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 */

View 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})

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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);
/**************************************************

View File

@ -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)

View File

@ -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)

View File

@ -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
View 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.

View File

@ -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();

View 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)

View 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)

View 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;
}

View 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 */

View File

@ -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