Merge branch main into dev/wasi_threads

This commit is contained in:
Wenyong Huang
2023-01-21 13:18:55 +08:00
52 changed files with 1155 additions and 345 deletions

View File

@ -1226,7 +1226,10 @@ load_import_globals(const uint8 **p_buf, const uint8 *buf_end,
}
import_globals[i].global_data_linked =
tmp_global.global_data_linked;
import_globals[i].is_linked = true;
}
#else
import_globals[i].is_linked = false;
#endif
import_globals[i].size = wasm_value_type_size(import_globals[i].type);

View File

@ -899,24 +899,6 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module,
return create_export_funcs(module_inst, module, error_buf, error_buf_size);
}
static bool
clear_wasi_proc_exit_exception(AOTModuleInstance *module_inst)
{
#if WASM_ENABLE_LIBC_WASI != 0
const char *exception = aot_get_exception(module_inst);
if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
/* The "wasi proc exit" exception is thrown by native lib to
let wasm app exit, which is a normal behavior, we clear
the exception here. */
aot_set_exception(module_inst, NULL);
return true;
}
return false;
#else
return false;
#endif
}
static bool
execute_post_inst_function(AOTModuleInstance *module_inst)
{
@ -956,7 +938,6 @@ execute_start_function(AOTModuleInstance *module_inst)
u.f(exec_env);
wasm_exec_env_destroy(exec_env);
(void)clear_wasi_proc_exit_exception(module_inst);
return !aot_get_exception(module_inst);
}
@ -976,6 +957,26 @@ execute_memory_init_function(AOTModuleInstance *module_inst)
}
#endif
static bool
check_linked_symbol(AOTModule *module, char *error_buf, uint32 error_buf_size)
{
uint32 i;
/* init_func_ptrs() will go through import functions */
for (i = 0; i < module->import_global_count; i++) {
AOTImportGlobal *global = module->import_globals + i;
if (!global->is_linked) {
set_error_buf_v(error_buf, error_buf_size,
"failed to link import global (%s, %s)",
global->module_name, global->global_name);
return false;
}
}
return true;
}
AOTModuleInstance *
aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
uint32 heap_size, char *error_buf, uint32 error_buf_size)
@ -1059,6 +1060,9 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
if (!init_func_type_indexes(module_inst, module, error_buf, error_buf_size))
goto fail;
if (!check_linked_symbol(module, error_buf, error_buf_size))
goto fail;
if (!create_exports(module_inst, module, error_buf, error_buf_size))
goto fail;
@ -1384,13 +1388,6 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
func_type, NULL, NULL, argv1, argc, argv);
if (!ret || aot_get_exception(module_inst)) {
if (clear_wasi_proc_exit_exception(module_inst))
ret = true;
else
ret = false;
}
#if WASM_ENABLE_DUMP_CALL_STACK != 0
if (!ret) {
if (aot_create_call_stack(exec_env)) {
@ -1450,9 +1447,6 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
func_type, NULL, NULL, argv, argc, argv);
if (clear_wasi_proc_exit_exception(module_inst))
ret = true;
#if WASM_ENABLE_DUMP_CALL_STACK != 0
if (aot_get_exception(module_inst)) {
if (aot_create_call_stack(exec_env)) {
@ -1493,7 +1487,7 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst,
}
}
ret = aot_call_function(exec_env, func, argc, argv);
ret = wasm_runtime_call_wasm(exec_env, func, argc, argv);
/* don't destroy the exec_env if it isn't created in this function */
if (!existing_exec_env)
@ -1764,7 +1758,9 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
AOTModuleInstanceExtra *module_inst_extra =
(AOTModuleInstanceExtra *)module_inst->e;
CApiFuncImport *c_api_func_import =
module_inst_extra->c_api_func_imports + func_idx;
module_inst_extra->c_api_func_imports
? module_inst_extra->c_api_func_imports + func_idx
: NULL;
uint32 *func_type_indexes = module_inst->func_type_indexes;
uint32 func_type_idx = func_type_indexes[func_idx];
AOTFuncType *func_type = aot_module->func_types[func_type_idx];
@ -1780,7 +1776,8 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
import_func = aot_module->import_funcs + func_idx;
if (import_func->call_conv_wasm_c_api)
func_ptr = c_api_func_import->func_ptr_linked;
func_ptr =
c_api_func_import ? c_api_func_import->func_ptr_linked : NULL;
if (!func_ptr) {
snprintf(buf, sizeof(buf),
@ -1980,9 +1977,6 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
}
fail:
if (clear_wasi_proc_exit_exception(module_inst))
return true;
#ifdef OS_ENABLE_HW_BOUND_CHECK
wasm_runtime_access_exce_check_guard_page();
#endif

View File

@ -4555,6 +4555,7 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
}
import->global_idx_rt = global_idx_rt;
import_aot_global->is_linked = true;
return true;
failed:

View File

@ -181,6 +181,9 @@ wasm_exec_env_destroy(WASMExecEnv *exec_env)
the stopped thread will be overrided by other threads */
wasm_cluster_thread_exited(exec_env);
#endif
/* We have terminated other threads, this is the only alive thread, so
* we don't acquire cluster->lock because the cluster will be destroyed
* inside this function */
wasm_cluster_del_exec_env(cluster, exec_env);
}
#endif /* end of WASM_ENABLE_THREAD_MGR */

View File

@ -1743,6 +1743,30 @@ wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
}
#endif
static bool
clear_wasi_proc_exit_exception(WASMModuleInstanceCommon *module_inst_comm)
{
#if WASM_ENABLE_LIBC_WASI != 0
const char *exception;
WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|| module_inst_comm->module_type == Wasm_Module_AoT);
exception = wasm_get_exception(module_inst);
if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
/* The "wasi proc exit" exception is thrown by native lib to
let wasm app exit, which is a normal behavior, we clear
the exception here. */
wasm_set_exception(module_inst, NULL);
return true;
}
return false;
#else
return false;
#endif
}
bool
wasm_runtime_call_wasm(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function, uint32 argc,
@ -1783,10 +1807,15 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
param_argc, new_argv);
#endif
if (!ret) {
if (new_argv != argv) {
wasm_runtime_free(new_argv);
if (clear_wasi_proc_exit_exception(exec_env->module_inst)) {
ret = true;
}
else {
if (new_argv != argv) {
wasm_runtime_free(new_argv);
}
return false;
}
return false;
}
#if WASM_ENABLE_REF_TYPES != 0
@ -2150,11 +2179,25 @@ wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst_comm)
void
wasm_set_exception(WASMModuleInstance *module_inst, const char *exception)
{
if (exception)
WASMExecEnv *exec_env = NULL;
if (exception) {
snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception),
"Exception: %s", exception);
else
}
else {
module_inst->cur_exception[0] = '\0';
}
#if WASM_ENABLE_THREAD_MGR != 0
exec_env =
wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst);
if (exec_env) {
wasm_cluster_spread_exception(exec_env, exception ? false : true);
}
#else
(void)exec_env;
#endif
}
/* clang-format off */
@ -4179,6 +4222,8 @@ bool
wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
uint32 argc, uint32 argv[])
{
bool ret = false;
if (!wasm_runtime_exec_env_check(exec_env)) {
LOG_ERROR("Invalid exec env stack info.");
return false;
@ -4190,13 +4235,18 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
#if WASM_ENABLE_INTERP != 0
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode)
return wasm_call_indirect(exec_env, 0, element_indices, argc, argv);
ret = wasm_call_indirect(exec_env, 0, element_indices, argc, argv);
#endif
#if WASM_ENABLE_AOT != 0
if (exec_env->module_inst->module_type == Wasm_Module_AoT)
return aot_call_indirect(exec_env, 0, element_indices, argc, argv);
ret = aot_call_indirect(exec_env, 0, element_indices, argc, argv);
#endif
return false;
if (!ret && clear_wasi_proc_exit_exception(exec_env->module_inst)) {
ret = true;
}
return ret;
}
static void

View File

@ -149,6 +149,7 @@ typedef struct AOTImportGlobal {
uint32 data_offset;
/* global data after linked */
WASMValue global_data_linked;
bool is_linked;
} AOTImportGlobal;
/**

View File

@ -9,6 +9,36 @@
#include "../aot/aot_intrinsic.h"
#include "../aot/aot_runtime.h"
static LLVMValueRef
call_fcmp_intrinsic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
enum AOTFloatCond cond, LLVMRealPredicate op,
LLVMValueRef lhs, LLVMValueRef rhs, LLVMTypeRef src_type,
const char *name)
{
LLVMValueRef res = NULL;
if (comp_ctx->disable_llvm_intrinsics
&& aot_intrinsic_check_capability(
comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
LLVMTypeRef param_types[3];
LLVMValueRef opcond = LLVMConstInt(I32_TYPE, cond, true);
param_types[0] = I32_TYPE;
param_types[1] = src_type;
param_types[2] = src_type;
res = aot_call_llvm_intrinsic(
comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
I32_TYPE, param_types, 3, opcond, lhs, rhs);
if (!res) {
goto fail;
}
res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
}
else {
res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, name);
}
fail:
return res;
}
static bool
trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef operand, LLVMTypeRef src_type,
@ -18,26 +48,8 @@ trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMBasicBlockRef check_nan_succ, check_overflow_succ;
LLVMValueRef is_less, is_greater, res;
if (comp_ctx->disable_llvm_intrinsics
&& aot_intrinsic_check_capability(
comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
LLVMTypeRef param_types[3];
LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_UNO, true);
param_types[0] = I32_TYPE;
param_types[1] = src_type;
param_types[2] = src_type;
res = aot_call_llvm_intrinsic(
comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
I32_TYPE, param_types, 3, opcond, operand, operand);
if (!res) {
goto fail;
}
res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
}
else {
res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, operand, operand,
"fcmp_is_nan");
}
res = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO,
operand, operand, src_type, "fcmp_is_nan");
if (!res) {
aot_set_last_error("llvm build fcmp failed.");
@ -58,54 +70,18 @@ trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
check_nan_succ)))
goto fail;
if (comp_ctx->disable_llvm_intrinsics
&& aot_intrinsic_check_capability(
comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
LLVMTypeRef param_types[3];
LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_LE, true);
param_types[0] = I32_TYPE;
param_types[1] = src_type;
param_types[2] = src_type;
is_less = aot_call_llvm_intrinsic(
comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
I32_TYPE, param_types, 3, opcond, operand, min_value);
if (!is_less) {
goto fail;
}
is_less =
LLVMBuildIntCast(comp_ctx->builder, is_less, INT1_TYPE, "bit_cast");
}
else {
is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand,
min_value, "fcmp_min_value");
}
is_less =
call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE, LLVMRealOLE, operand,
min_value, src_type, "fcmp_min_value");
if (!is_less) {
aot_set_last_error("llvm build fcmp failed.");
goto fail;
}
if (comp_ctx->disable_llvm_intrinsics
&& aot_intrinsic_check_capability(
comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
LLVMTypeRef param_types[3];
LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_GE, true);
param_types[0] = I32_TYPE;
param_types[1] = src_type;
param_types[2] = src_type;
is_greater = aot_call_llvm_intrinsic(
comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
I32_TYPE, param_types, 3, opcond, operand, max_value);
if (!is_greater) {
goto fail;
}
is_greater = LLVMBuildIntCast(comp_ctx->builder, is_greater, INT1_TYPE,
"bit_cast");
}
else {
is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand,
max_value, "fcmp_min_value");
}
is_greater =
call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE, LLVMRealOGE, operand,
max_value, src_type, "fcmp_min_value");
if (!is_greater) {
aot_set_last_error("llvm build fcmp failed.");
@ -183,8 +159,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef zero = (dest_type == I32_TYPE) ? I32_ZERO : I64_ZERO;
LLVMValueRef vmin, vmax;
if (!(res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, operand, operand,
"fcmp_is_nan"))) {
if (!(res =
call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO,
operand, operand, src_type, "fcmp_is_nan"))) {
aot_set_last_error("llvm build fcmp failed.");
goto fail;
}
@ -212,8 +189,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Start to translate check_nan_succ block */
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_nan_succ);
if (!(is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand,
min_value, "fcmp_min_value"))) {
if (!(is_less = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE,
LLVMRealOLE, operand, min_value,
src_type, "fcmp_min_value"))) {
aot_set_last_error("llvm build fcmp failed.");
goto fail;
}
@ -232,8 +210,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Start to translate check_less_succ block */
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_less_succ);
if (!(is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand,
max_value, "fcmp_max_value"))) {
if (!(is_greater = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE,
LLVMRealOGE, operand, max_value,
src_type, "fcmp_max_value"))) {
aot_set_last_error("llvm build fcmp failed.");
goto fail;
}

View File

@ -891,7 +891,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
if (!func_import->call_conv_wasm_c_api) {
native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
}
else {
else if (module_inst->e->c_api_func_imports) {
c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
native_func_pointer = c_api_func_import->func_ptr_linked;
}
@ -1041,7 +1041,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
} \
if (IS_WAMR_STOP_SIG(exec_env->current_status->signal_flag)) { \
SYNC_ALL_TO_FRAME(); \
wasm_cluster_thread_stopped(exec_env); \
wasm_cluster_thread_waiting_run(exec_env); \
} \
} while (0)
@ -1077,7 +1076,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
&& exec_env->current_status->step_count++ == 1) { \
exec_env->current_status->step_count = 0; \
SYNC_ALL_TO_FRAME(); \
wasm_cluster_thread_stopped(exec_env); \
wasm_cluster_thread_waiting_run(exec_env); \
} \
goto *handle_table[*frame_ip++]; \
@ -1094,7 +1092,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
&& exec_env->current_status->step_count++ == 2) { \
exec_env->current_status->step_count = 0; \
SYNC_ALL_TO_FRAME(); \
wasm_cluster_thread_stopped(exec_env); \
wasm_cluster_thread_waiting_run(exec_env); \
} \
continue
@ -4022,24 +4019,6 @@ fast_jit_call_func_bytecode(WASMModuleInstance *module_inst,
#endif /* end of WASM_ENABLE_FAST_JIT != 0 */
#if WASM_ENABLE_JIT != 0
static bool
clear_wasi_proc_exit_exception(WASMModuleInstance *module_inst)
{
#if WASM_ENABLE_LIBC_WASI != 0
const char *exception = wasm_get_exception(module_inst);
if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
/* The "wasi proc exit" exception is thrown by native lib to
let wasm app exit, which is a normal behavior, we clear
the exception here. */
wasm_set_exception(module_inst, NULL);
return true;
}
return false;
#else
return false;
#endif
}
static bool
llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
WASMExecEnv *exec_env,
@ -4099,14 +4078,6 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
ret = wasm_runtime_invoke_native(
exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
argv1, argc, argv);
if (!ret || wasm_get_exception(module_inst)) {
if (clear_wasi_proc_exit_exception(module_inst))
ret = true;
else
ret = false;
}
if (!ret) {
if (argv1 != argv1_buf)
wasm_runtime_free(argv1);
@ -4151,9 +4122,6 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
argv, argc, argv);
if (clear_wasi_proc_exit_exception(module_inst))
ret = true;
return ret && !wasm_get_exception(module_inst) ? true : false;
}
}

View File

@ -925,7 +925,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
if (!func_import->call_conv_wasm_c_api) {
native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
}
else {
else if (module_inst->e->c_api_func_imports) {
c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
native_func_pointer = c_api_func_import->func_ptr_linked;
}

View File

@ -1235,6 +1235,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
#if WASM_ENABLE_WAMR_COMPILER == 0
LOG_WARNING("warning: failed to link import function (%s, %s)",
func->module_name, func->field_name);
/* will throw exception only if calling */
#else
/* do nothing to avoid confused message */
#endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
@ -1250,8 +1251,10 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
return false;
#else
#if WASM_ENABLE_WAMR_COMPILER == 0
LOG_DEBUG("warning: failed to link import global (%s, %s)",
global->module_name, global->field_name);
set_error_buf_v(error_buf, error_buf_size,
"failed to link import global (%s, %s)",
global->module_name, global->field_name);
return false;
#else
/* do nothing to avoid confused message */
#endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
@ -2030,24 +2033,6 @@ wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name)
}
#endif
static bool
clear_wasi_proc_exit_exception(WASMModuleInstance *module_inst)
{
#if WASM_ENABLE_LIBC_WASI != 0
const char *exception = wasm_get_exception(module_inst);
if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
/* The "wasi proc exit" exception is thrown by native lib to
let wasm app exit, which is a normal behavior, we clear
the exception here. */
wasm_set_exception(module_inst, NULL);
return true;
}
return false;
#else
return false;
#endif
}
#ifdef OS_ENABLE_HW_BOUND_CHECK
static void
@ -2157,7 +2142,6 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
wasm_exec_env_set_thread_info(exec_env);
interp_call_wasm(module_inst, exec_env, function, argc, argv);
(void)clear_wasi_proc_exit_exception(module_inst);
return !wasm_get_exception(module_inst) ? true : false;
}
@ -2185,7 +2169,7 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
}
}
ret = wasm_call_function(exec_env, func, argc, argv);
ret = wasm_runtime_call_wasm(exec_env, func, argc, argv);
/* don't destroy the exec_env if it isn't created in this function */
if (!existing_exec_env)
@ -2455,7 +2439,6 @@ call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
interp_call_wasm(module_inst, exec_env, func_inst, argc, argv);
(void)clear_wasi_proc_exit_exception(module_inst);
return !wasm_get_exception(module_inst) ? true : false;
got_exception:
@ -2907,8 +2890,14 @@ llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
import_func = &module->import_functions[func_idx].u.function;
if (import_func->call_conv_wasm_c_api) {
c_api_func_import = module_inst->e->c_api_func_imports + func_idx;
func_ptr = c_api_func_import->func_ptr_linked;
if (module_inst->e->c_api_func_imports) {
c_api_func_import = module_inst->e->c_api_func_imports + func_idx;
func_ptr = c_api_func_import->func_ptr_linked;
}
else {
c_api_func_import = NULL;
func_ptr = NULL;
}
}
if (!func_ptr) {

View File

@ -494,7 +494,6 @@ 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];
@ -519,8 +518,7 @@ pthread_start_routine(void *arg)
if (!wasm_runtime_call_indirect(exec_env, routine_args->elem_index, 1,
argv)) {
if (wasm_runtime_get_exception(module_inst))
wasm_cluster_spread_exception(exec_env);
/* Exception has already been spread during throwing */
}
/* destroy pthread key values */

View File

@ -50,7 +50,6 @@ static void *
thread_start(void *arg)
{
wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
wasm_module_inst_t module_inst = get_module_inst(exec_env);
ThreadStartArg *thread_arg = exec_env->thread_arg;
uint32 argv[2];
@ -59,8 +58,7 @@ thread_start(void *arg)
argv[1] = thread_arg->arg;
if (!wasm_runtime_call_wasm(exec_env, thread_arg->start_func, 2, argv)) {
if (wasm_runtime_get_exception(module_inst))
wasm_cluster_spread_exception(exec_env);
/* Exception has already been spread during throwing */
}
// Routine exit

View File

@ -76,6 +76,7 @@ traverse_list(bh_list *l, list_visitor visitor, void *user_data)
}
}
/* The caller must lock cluster->lock */
static bool
allocate_aux_stack(WASMExecEnv *exec_env, uint32 *start, uint32 *size)
{
@ -99,7 +100,6 @@ allocate_aux_stack(WASMExecEnv *exec_env, uint32 *start, uint32 *size)
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)
@ -107,15 +107,15 @@ allocate_aux_stack(WASMExecEnv *exec_env, uint32 *start, uint32 *size)
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;
#endif
}
/* The caller must lock cluster->lock */
static bool
free_aux_stack(WASMExecEnv *exec_env, uint32 start)
{
@ -139,9 +139,7 @@ free_aux_stack(WASMExecEnv *exec_env, uint32 start)
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;
}
}
@ -304,14 +302,14 @@ wasm_exec_env_get_cluster(WASMExecEnv *exec_env)
return exec_env->cluster;
}
bool
/* The caller must lock cluster->lock */
static bool
wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
{
bool ret = true;
exec_env->cluster = cluster;
os_mutex_lock(&cluster->lock);
if (cluster->exec_env_list.len == cluster_max_thread_num + 1) {
LOG_ERROR("thread manager error: "
"maximum number of threads exceeded");
@ -320,10 +318,11 @@ wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
if (ret && bh_list_insert(&cluster->exec_env_list, exec_env) != 0)
ret = false;
os_mutex_unlock(&cluster->lock);
return ret;
}
/* The caller should lock cluster->lock for thread safety */
bool
wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
{
@ -346,10 +345,8 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
}
#endif
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 */
@ -419,6 +416,12 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
return NULL;
}
os_mutex_lock(&cluster->lock);
if (cluster->has_exception || cluster->processing) {
goto fail1;
}
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
stack_size =
@ -435,7 +438,7 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
if (!(new_module_inst = wasm_runtime_instantiate_internal(
module, true, stack_size, 0, NULL, 0))) {
return NULL;
goto fail1;
}
/* Set custom_data to new module instance */
@ -450,32 +453,36 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
new_exec_env = wasm_exec_env_create_internal(new_module_inst,
exec_env->wasm_stack_size);
if (!new_exec_env)
goto fail1;
goto fail2;
if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) {
LOG_ERROR("thread manager error: "
"failed to allocate aux stack space for new thread");
goto fail2;
goto fail3;
}
/* Set aux stack for current thread */
if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start,
aux_stack_size)) {
goto fail3;
goto fail4;
}
if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
goto fail3;
goto fail4;
os_mutex_unlock(&cluster->lock);
return new_exec_env;
fail3:
fail4:
/* free the allocated aux stack space */
free_aux_stack(exec_env, aux_stack_start);
fail2:
fail3:
wasm_exec_env_destroy(new_exec_env);
fail1:
fail2:
wasm_runtime_deinstantiate_internal(new_module_inst, true);
fail1:
os_mutex_unlock(&cluster->lock);
return NULL;
}
@ -488,8 +495,10 @@ wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env)
bh_assert(cluster != NULL);
/* Free aux stack space */
os_mutex_lock(&cluster->lock);
free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
wasm_cluster_del_exec_env(cluster, exec_env);
os_mutex_unlock(&cluster->lock);
wasm_exec_env_destroy_internal(exec_env);
wasm_runtime_deinstantiate_internal(module_inst, true);
@ -517,19 +526,23 @@ thread_manager_start_routine(void *arg)
#endif
/* Routine exit */
/* Free aux stack space */
free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
/* routine exit, destroy instance */
wasm_runtime_deinstantiate_internal(module_inst, true);
/* Detach the native thread here to ensure the resources are freed */
wasm_cluster_detach_thread(exec_env);
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_thread_exited(exec_env);
#endif
/* Remove and destroy exec_env */
os_mutex_lock(&cluster->lock);
/* Free aux stack space */
free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
/* routine exit, destroy instance */
wasm_runtime_deinstantiate_internal(module_inst, true);
/* Remove and exec_env */
wasm_cluster_del_exec_env(cluster, exec_env);
os_mutex_unlock(&cluster->lock);
/* destroy exec_env */
wasm_exec_env_destroy_internal(exec_env);
os_thread_exit(ret);
@ -543,33 +556,39 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env,
{
WASMCluster *cluster;
WASMExecEnv *new_exec_env;
uint32 aux_stack_start, aux_stack_size;
uint32 aux_stack_start = 0, aux_stack_size;
korp_tid tid;
cluster = wasm_exec_env_get_cluster(exec_env);
bh_assert(cluster);
os_mutex_lock(&cluster->lock);
if (cluster->has_exception || cluster->processing) {
goto fail1;
}
new_exec_env =
wasm_exec_env_create_internal(module_inst, exec_env->wasm_stack_size);
if (!new_exec_env)
return -1;
goto fail1;
if (alloc_aux_stack) {
if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) {
LOG_ERROR("thread manager error: "
"failed to allocate aux stack space for new thread");
goto fail1;
goto fail2;
}
/* Set aux stack for current thread */
if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start,
aux_stack_size)) {
goto fail2;
goto fail3;
}
}
if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
goto fail2;
goto fail3;
new_exec_env->thread_start_routine = thread_routine;
new_exec_env->thread_arg = arg;
@ -578,19 +597,24 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env,
!= os_thread_create(&tid, thread_manager_start_routine,
(void *)new_exec_env,
APP_THREAD_STACK_SIZE_DEFAULT)) {
goto fail3;
goto fail4;
}
os_mutex_unlock(&cluster->lock);
return 0;
fail3:
fail4:
wasm_cluster_del_exec_env(cluster, new_exec_env);
fail2:
fail3:
/* free the allocated aux stack space */
if (alloc_aux_stack)
free_aux_stack(exec_env, aux_stack_start);
fail1:
fail2:
wasm_exec_env_destroy(new_exec_env);
fail1:
os_mutex_unlock(&cluster->lock);
return -1;
}
@ -665,17 +689,17 @@ notify_debug_instance_exit(WASMExecEnv *exec_env)
on_thread_exit_event(cluster->debug_inst, exec_env);
}
void
wasm_cluster_thread_stopped(WASMExecEnv *exec_env)
{
exec_env->current_status->running_status = STATUS_STOP;
notify_debug_instance(exec_env);
}
void
wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env)
{
os_mutex_lock(&exec_env->wait_lock);
/* Wake up debugger thread after we get the lock, otherwise we may miss the
* signal from debugger thread, see
* https://github.com/bytecodealliance/wasm-micro-runtime/issues/1860 */
exec_env->current_status->running_status = STATUS_STOP;
notify_debug_instance(exec_env);
while (!wasm_cluster_thread_is_running(exec_env)) {
os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
}
@ -702,16 +726,20 @@ wasm_cluster_thread_exited(WASMExecEnv *exec_env)
void
wasm_cluster_thread_continue(WASMExecEnv *exec_env)
{
os_mutex_lock(&exec_env->wait_lock);
wasm_cluster_clear_thread_signal(exec_env);
exec_env->current_status->running_status = STATUS_RUNNING;
os_cond_signal(&exec_env->wait_cond);
os_mutex_unlock(&exec_env->wait_lock);
}
void
wasm_cluster_thread_step(WASMExecEnv *exec_env)
{
os_mutex_lock(&exec_env->wait_lock);
exec_env->current_status->running_status = STATUS_STEP;
os_cond_signal(&exec_env->wait_cond);
os_mutex_unlock(&exec_env->wait_lock);
}
void
@ -817,17 +845,30 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
wasm_cluster_thread_exited(exec_env);
#endif
/* App exit the thread, free the resources before exit native thread */
/* Free aux stack space */
free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
/* Detach the native thread here to ensure the resources are freed */
wasm_cluster_detach_thread(exec_env);
os_mutex_lock(&cluster->lock);
/* Free aux stack space */
free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
/* Remove and destroy exec_env */
wasm_cluster_del_exec_env(cluster, exec_env);
os_mutex_unlock(&cluster->lock);
wasm_exec_env_destroy_internal(exec_env);
os_thread_exit(retval);
}
static void
set_thread_cancel_flags(WASMExecEnv *exec_env)
{
/* Set the termination flag */
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
#else
exec_env->suspend_flags.flags |= 0x01;
#endif
}
int32
wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
{
@ -839,12 +880,8 @@ wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
}
os_mutex_unlock(&cluster_list_lock);
/* Set the termination flag */
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
#else
exec_env->suspend_flags.flags |= 0x01;
#endif
set_thread_cancel_flags(exec_env);
return 0;
}
@ -864,15 +901,31 @@ terminate_thread_visitor(void *node, void *user_data)
void
wasm_cluster_terminate_all(WASMCluster *cluster)
{
os_mutex_lock(&cluster->lock);
cluster->processing = true;
os_mutex_unlock(&cluster->lock);
traverse_list(&cluster->exec_env_list, terminate_thread_visitor, NULL);
os_mutex_lock(&cluster->lock);
cluster->processing = false;
os_mutex_unlock(&cluster->lock);
}
void
wasm_cluster_terminate_all_except_self(WASMCluster *cluster,
WASMExecEnv *exec_env)
{
os_mutex_lock(&cluster->lock);
cluster->processing = true;
os_mutex_unlock(&cluster->lock);
traverse_list(&cluster->exec_env_list, terminate_thread_visitor,
(void *)exec_env);
os_mutex_lock(&cluster->lock);
cluster->processing = false;
os_mutex_unlock(&cluster->lock);
}
static void
@ -890,15 +943,31 @@ wait_for_thread_visitor(void *node, void *user_data)
void
wams_cluster_wait_for_all(WASMCluster *cluster)
{
os_mutex_lock(&cluster->lock);
cluster->processing = true;
os_mutex_unlock(&cluster->lock);
traverse_list(&cluster->exec_env_list, wait_for_thread_visitor, NULL);
os_mutex_lock(&cluster->lock);
cluster->processing = false;
os_mutex_unlock(&cluster->lock);
}
void
wasm_cluster_wait_for_all_except_self(WASMCluster *cluster,
WASMExecEnv *exec_env)
{
os_mutex_lock(&cluster->lock);
cluster->processing = true;
os_mutex_unlock(&cluster->lock);
traverse_list(&cluster->exec_env_list, wait_for_thread_visitor,
(void *)exec_env);
os_mutex_lock(&cluster->lock);
cluster->processing = false;
os_mutex_unlock(&cluster->lock);
}
bool
@ -937,15 +1006,19 @@ suspend_thread_visitor(void *node, void *user_data)
void
wasm_cluster_suspend_all(WASMCluster *cluster)
{
os_mutex_lock(&cluster->lock);
traverse_list(&cluster->exec_env_list, suspend_thread_visitor, NULL);
os_mutex_unlock(&cluster->lock);
}
void
wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
WASMExecEnv *exec_env)
{
os_mutex_lock(&cluster->lock);
traverse_list(&cluster->exec_env_list, suspend_thread_visitor,
(void *)exec_env);
os_mutex_unlock(&cluster->lock);
}
void
@ -966,7 +1039,9 @@ resume_thread_visitor(void *node, void *user_data)
void
wasm_cluster_resume_all(WASMCluster *cluster)
{
os_mutex_lock(&cluster->lock);
traverse_list(&cluster->exec_env_list, resume_thread_visitor, NULL);
os_mutex_unlock(&cluster->lock);
}
static void
@ -975,24 +1050,46 @@ 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;
WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst;
if (curr_exec_env != exec_env) {
curr_module_inst = get_module_inst(curr_exec_env);
wasm_runtime_set_exception(curr_module_inst, exception);
WASMModuleInstance *curr_wasm_inst =
(WASMModuleInstance *)get_module_inst(curr_exec_env);
bh_memcpy_s(curr_wasm_inst->cur_exception,
sizeof(curr_wasm_inst->cur_exception),
wasm_inst->cur_exception, sizeof(wasm_inst->cur_exception));
/* Terminate the thread so it can exit from dead loops */
set_thread_cancel_flags(curr_exec_env);
}
}
static void
clear_exception_visitor(void *node, void *user_data)
{
WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
if (curr_exec_env != exec_env) {
WASMModuleInstance *curr_wasm_inst =
(WASMModuleInstance *)get_module_inst(curr_exec_env);
curr_wasm_inst->cur_exception[0] = '\0';
}
}
void
wasm_cluster_spread_exception(WASMExecEnv *exec_env)
wasm_cluster_spread_exception(WASMExecEnv *exec_env, bool clear)
{
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
bh_assert(cluster);
traverse_list(&cluster->exec_env_list, set_exception_visitor, exec_env);
os_mutex_lock(&cluster->lock);
cluster->has_exception = !clear;
traverse_list(&cluster->exec_env_list,
clear ? clear_exception_visitor : set_exception_visitor,
exec_env);
os_mutex_unlock(&cluster->lock);
}
static void
@ -1020,7 +1117,9 @@ wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst,
cluster = wasm_exec_env_get_cluster(exec_env);
bh_assert(cluster);
os_mutex_lock(&cluster->lock);
traverse_list(&cluster->exec_env_list, set_custom_data_visitor,
custom_data);
os_mutex_unlock(&cluster->lock);
}
}

View File

@ -36,6 +36,18 @@ struct WASMCluster {
#endif
/* Size of every stack segment */
uint32 stack_size;
/* When has_exception == true, this cluster should refuse any spawn thread
* requests, this flag can be cleared by calling
* wasm_runtime_clear_exception on instances of any threads of this cluster
*/
bool has_exception;
/* When processing is true, this cluster should refuse any spawn thread
* requests. This is a short-lived state, must be cleared immediately once
* the processing finished.
* This is used to avoid dead lock when one thread waiting another thread
* with lock, see wams_cluster_wait_for_all and wasm_cluster_terminate_all
*/
bool processing;
#if WASM_ENABLE_DEBUG_INTERP != 0
WASMDebugInstance *debug_inst;
#endif
@ -115,9 +127,6 @@ void
wasm_cluster_wait_for_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);
@ -125,7 +134,7 @@ WASMExecEnv *
wasm_clusters_search_exec_env(WASMModuleInstanceCommon *module_inst);
void
wasm_cluster_spread_exception(WASMExecEnv *exec_env);
wasm_cluster_spread_exception(WASMExecEnv *exec_env, bool clear);
WASMExecEnv *
wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env);
@ -168,9 +177,6 @@ wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status);
void
wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo);
void
wasm_cluster_thread_stopped(WASMExecEnv *exec_env);
void
wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env);