Add/reorganize locks for thread synchronization (#1995)
Attempt to fix data races when using threads. - Protect access (from multiple threads) to exception and memory - Fix shared memory lock usage
This commit is contained in:
@ -8,6 +8,7 @@
|
||||
#include "wasm_runtime.h"
|
||||
#include "wasm_opcode.h"
|
||||
#include "wasm_loader.h"
|
||||
#include "wasm_memory.h"
|
||||
#include "../common/wasm_exec_env.h"
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
#include "../common/wasm_shared_memory.h"
|
||||
@ -954,7 +955,7 @@ fast_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
||||
WASMFunctionInstance *cur_func = module_inst->e->functions + func_idx;
|
||||
|
||||
wasm_interp_call_func_native(module_inst, exec_env, cur_func, prev_frame);
|
||||
return wasm_get_exception(module_inst) ? false : true;
|
||||
return wasm_copy_exception(module_inst, NULL) ? false : true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1023,7 +1024,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||
exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
|
||||
|
||||
/* transfer exception if it is thrown */
|
||||
if (wasm_get_exception(sub_module_inst)) {
|
||||
if (wasm_copy_exception(sub_module_inst, NULL)) {
|
||||
bh_memcpy_s(module_inst->cur_exception,
|
||||
sizeof(module_inst->cur_exception),
|
||||
sub_module_inst->cur_exception,
|
||||
@ -1126,14 +1127,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame)
|
||||
{
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
|
||||
#else
|
||||
void *node = NULL;
|
||||
#endif
|
||||
|
||||
WASMMemoryInstance *memory = wasm_get_default_memory(module);
|
||||
uint8 *global_data = module->global_data;
|
||||
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|
||||
|| WASM_ENABLE_BULK_MEMORY != 0
|
||||
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
|
||||
uint32 num_bytes_per_page =
|
||||
memory ? wasm_get_num_bytes_per_page(memory, node) : 0;
|
||||
uint32 linear_mem_size =
|
||||
memory ? num_bytes_per_page * memory->cur_page_count : 0;
|
||||
memory ? wasm_get_linear_memory_size(memory, node) : 0;
|
||||
#endif
|
||||
WASMType **wasm_types = module->module->types;
|
||||
WASMGlobalInstance *globals = module->e->globals, *global;
|
||||
@ -1157,11 +1166,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
uint32 cache_index, type_index, param_cell_num, cell_num;
|
||||
uint8 value_type;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
uint8 *frame_ip_orig = NULL;
|
||||
WASMDebugInstance *debug_instance = wasm_exec_env_get_instance(exec_env);
|
||||
@ -3859,7 +3863,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
if (memory)
|
||||
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
||||
#endif
|
||||
if (wasm_get_exception(module))
|
||||
if (wasm_copy_exception(module, NULL))
|
||||
goto got_exception;
|
||||
}
|
||||
else {
|
||||
@ -4002,7 +4006,7 @@ fast_jit_call_func_bytecode(WASMModuleInstance *module_inst,
|
||||
module_inst->fast_jit_func_ptrs[func_idx_non_import]);
|
||||
bh_assert(action == JIT_INTERP_ACTION_NORMAL
|
||||
|| (action == JIT_INTERP_ACTION_THROWN
|
||||
&& wasm_runtime_get_exception(exec_env->module_inst)));
|
||||
&& wasm_runtime_copy_exception(exec_env->module_inst, NULL)));
|
||||
|
||||
/* Get the return values form info.out.ret */
|
||||
if (func_type->result_count) {
|
||||
@ -4137,7 +4141,7 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
|
||||
exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
|
||||
argv, argc, argv);
|
||||
|
||||
return ret && !wasm_get_exception(module_inst) ? true : false;
|
||||
return ret && !wasm_copy_exception(module_inst, NULL) ? true : false;
|
||||
}
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_JIT != 0 */
|
||||
@ -4157,6 +4161,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
|
||||
unsigned i;
|
||||
bool copy_argv_from_frame = true;
|
||||
char exception[EXCEPTION_BUF_LEN];
|
||||
|
||||
if (argc < function->param_cell_num) {
|
||||
char buf[128];
|
||||
@ -4267,7 +4272,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
}
|
||||
|
||||
/* Output the return value to the caller */
|
||||
if (!wasm_get_exception(module_inst)) {
|
||||
if (!wasm_copy_exception(module_inst, NULL)) {
|
||||
if (copy_argv_from_frame) {
|
||||
for (i = 0; i < function->ret_cell_num; i++) {
|
||||
argv[i] = *(frame->sp + i - function->ret_cell_num);
|
||||
@ -4280,7 +4285,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
|
||||
}
|
||||
#endif
|
||||
LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst));
|
||||
wasm_copy_exception(module_inst, exception);
|
||||
LOG_DEBUG("meet an exception %s", exception);
|
||||
}
|
||||
|
||||
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include "wasm_runtime.h"
|
||||
#include "wasm_opcode.h"
|
||||
#include "wasm_loader.h"
|
||||
#include "wasm_memory.h"
|
||||
#include "../common/wasm_exec_env.h"
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
#include "../common/wasm_shared_memory.h"
|
||||
@ -1042,7 +1043,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||
exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
|
||||
|
||||
/* transfer exception if it is thrown */
|
||||
if (wasm_get_exception(sub_module_inst)) {
|
||||
if (wasm_copy_exception(sub_module_inst, NULL)) {
|
||||
bh_memcpy_s(module_inst->cur_exception,
|
||||
sizeof(module_inst->cur_exception),
|
||||
sub_module_inst->cur_exception,
|
||||
@ -1154,13 +1155,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame)
|
||||
{
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
|
||||
#else
|
||||
void *node = NULL;
|
||||
#endif
|
||||
|
||||
WASMMemoryInstance *memory = wasm_get_default_memory(module);
|
||||
|
||||
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|
||||
|| WASM_ENABLE_BULK_MEMORY != 0
|
||||
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
|
||||
uint32 num_bytes_per_page =
|
||||
memory ? wasm_get_num_bytes_per_page(memory, node) : 0;
|
||||
uint32 linear_mem_size =
|
||||
memory ? num_bytes_per_page * memory->cur_page_count : 0;
|
||||
memory ? wasm_get_linear_memory_size(memory, node) : 0;
|
||||
#endif
|
||||
uint8 *global_data = module->global_data;
|
||||
WASMGlobalInstance *globals = module->e ? module->e->globals : NULL;
|
||||
@ -1186,11 +1196,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
uint32 local_idx, local_offset, global_idx;
|
||||
uint8 opcode, local_type, *global_addr;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LABELS_AS_VALUES != 0
|
||||
#define HANDLE_OPCODE(op) &&HANDLE_##op
|
||||
DEFINE_GOTO_TABLE(const void *, handle_table);
|
||||
@ -3797,7 +3802,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
if (memory)
|
||||
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
||||
#endif
|
||||
if (wasm_get_exception(module))
|
||||
if (wasm_copy_exception(module, NULL))
|
||||
goto got_exception;
|
||||
}
|
||||
else {
|
||||
@ -3908,6 +3913,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
/* This frame won't be used by JITed code, so only allocate interp
|
||||
frame here. */
|
||||
unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
|
||||
char exception[EXCEPTION_BUF_LEN];
|
||||
|
||||
if (argc < function->param_cell_num) {
|
||||
char buf[128];
|
||||
@ -3973,7 +3979,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
}
|
||||
|
||||
/* Output the return value to the caller */
|
||||
if (!wasm_get_exception(module_inst)) {
|
||||
if (!wasm_copy_exception(module_inst, NULL)) {
|
||||
for (i = 0; i < function->ret_cell_num; i++)
|
||||
argv[i] = *(frame->lp + i);
|
||||
}
|
||||
@ -3983,7 +3989,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
|
||||
}
|
||||
#endif
|
||||
LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst));
|
||||
wasm_copy_exception(module_inst, exception);
|
||||
LOG_DEBUG("meet an exception %s", exception);
|
||||
}
|
||||
|
||||
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
|
||||
|
||||
@ -2243,6 +2243,8 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
const char *exce;
|
||||
int result;
|
||||
bool has_exception;
|
||||
char exception[EXCEPTION_BUF_LEN];
|
||||
#endif
|
||||
bool ret = true;
|
||||
|
||||
@ -2275,14 +2277,14 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
|
||||
#else
|
||||
__try {
|
||||
wasm_interp_call_wasm(module_inst, exec_env, function, argc, argv);
|
||||
} __except (wasm_get_exception(module_inst)
|
||||
} __except (wasm_copy_exception(module_inst, NULL)
|
||||
? EXCEPTION_EXECUTE_HANDLER
|
||||
: EXCEPTION_CONTINUE_SEARCH) {
|
||||
/* exception was thrown in wasm_exception_handler */
|
||||
ret = false;
|
||||
}
|
||||
if ((exce = wasm_get_exception(module_inst))
|
||||
&& strstr(exce, "native stack overflow")) {
|
||||
has_exception = wasm_copy_exception(module_inst, exception);
|
||||
if (has_exception && strstr(exception, "native stack overflow")) {
|
||||
/* After a stack overflow, the stack was left
|
||||
in a damaged state, let the CRT repair it */
|
||||
result = _resetstkoflw();
|
||||
@ -2336,7 +2338,7 @@ 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);
|
||||
return !wasm_get_exception(module_inst) ? true : false;
|
||||
return !wasm_copy_exception(module_inst, NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2509,6 +2511,12 @@ wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr)
|
||||
return;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node = wasm_module_get_shared_memory(
|
||||
(WASMModuleCommon *)module_inst->module);
|
||||
if (node)
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
#endif
|
||||
addr = memory->memory_data + ptr;
|
||||
|
||||
if (memory->heap_handle && memory->heap_data <= addr
|
||||
@ -2521,6 +2529,10 @@ wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr)
|
||||
execute_free_function(module_inst, module_inst->e->free_function,
|
||||
ptr);
|
||||
}
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (node)
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -2633,7 +2645,7 @@ call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
|
||||
|
||||
interp_call_wasm(module_inst, exec_env, func_inst, argc, argv);
|
||||
|
||||
return !wasm_get_exception(module_inst) ? true : false;
|
||||
return !wasm_copy_exception(module_inst, NULL);
|
||||
|
||||
got_exception:
|
||||
return false;
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EXCEPTION_BUF_LEN 128
|
||||
|
||||
typedef struct WASMModuleInstance WASMModuleInstance;
|
||||
typedef struct WASMFunctionInstance WASMFunctionInstance;
|
||||
typedef struct WASMMemoryInstance WASMMemoryInstance;
|
||||
@ -282,7 +284,7 @@ struct WASMModuleInstance {
|
||||
DefPointer(WASMExportTabInstance *, export_tables);
|
||||
|
||||
/* The exception buffer of wasm interpreter for current thread. */
|
||||
char cur_exception[128];
|
||||
char cur_exception[EXCEPTION_BUF_LEN];
|
||||
|
||||
/* The WASM module or AOT module, for AOTModuleInstance,
|
||||
it denotes `AOTModule *` */
|
||||
@ -444,6 +446,15 @@ wasm_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id);
|
||||
const char *
|
||||
wasm_get_exception(WASMModuleInstance *module);
|
||||
|
||||
/**
|
||||
* @brief Copy exception in buffer passed as parameter. Thread-safe version of
|
||||
* `wasm_get_exception()`
|
||||
* @note Buffer size must be no smaller than EXCEPTION_BUF_LEN
|
||||
* @return true if exception found
|
||||
*/
|
||||
bool
|
||||
wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf);
|
||||
|
||||
uint32
|
||||
wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
|
||||
void **p_native_addr);
|
||||
|
||||
Reference in New Issue
Block a user