Skip to content

Commit bab2402

Browse files
authored
Fix atomic.wait, get wasi_ctx exit code and thread mgr issues (#2024)
- Remove notify_stale_threads_on_exception and change atomic.wait to be interruptible by keep waiting and checking every one second, like the implementation of poll_oneoff in libc-wasi - Wait all other threads exit and then get wasi exit_code to avoid getting invalid value - Inherit suspend_flags of parent thread while creating new thread to avoid terminated flag isn't set for new thread - Fix wasi-threads test case update_shared_data_and_alloc_heap - Add "Lib wasi-threads enabled" prompt for cmake - Fix aot get exception, use aot_copy_exception instead
1 parent 2de2458 commit bab2402

8 files changed

Lines changed: 95 additions & 81 deletions

File tree

build-scripts/config_common.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ endif ()
223223
if (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE EQUAL 1)
224224
message (" Lib pthread semaphore enabled")
225225
endif ()
226+
if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
227+
message (" Lib wasi-threads enabled")
228+
endif ()
226229
if (WAMR_BUILD_LIBC_EMCC EQUAL 1)
227230
message (" Libc emcc enabled")
228231
endif ()

core/iwasm/aot/aot_runtime.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,8 +1321,9 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
13211321
uint16 result_count = func_type->result_count;
13221322
const uint8 *types = func_type->types;
13231323
#ifdef BH_PLATFORM_WINDOWS
1324-
const char *exce;
13251324
int result;
1325+
bool has_exception;
1326+
char exception[EXCEPTION_BUF_LEN];
13261327
#endif
13271328
bool ret;
13281329

@@ -1356,14 +1357,14 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
13561357
void (*NativeFunc)(WASMExecEnv *, uint32) =
13571358
(void (*)(WASMExecEnv *, uint32))func_ptr;
13581359
NativeFunc(exec_env, argv[0]);
1359-
ret = aot_get_exception(module_inst) ? false : true;
1360+
ret = aot_copy_exception(module_inst, NULL) ? false : true;
13601361
}
13611362
else if (result_count == 1
13621363
&& types[param_count] == VALUE_TYPE_I32) {
13631364
uint32 (*NativeFunc)(WASMExecEnv *, uint32) =
13641365
(uint32(*)(WASMExecEnv *, uint32))func_ptr;
13651366
argv_ret[0] = NativeFunc(exec_env, argv[0]);
1366-
ret = aot_get_exception(module_inst) ? false : true;
1367+
ret = aot_copy_exception(module_inst, NULL) ? false : true;
13671368
}
13681369
else {
13691370
ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type,
@@ -1377,8 +1378,8 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
13771378
argv_ret);
13781379
}
13791380
#ifdef BH_PLATFORM_WINDOWS
1380-
if ((exce = aot_get_exception(module_inst))
1381-
&& strstr(exce, "native stack overflow")) {
1381+
has_exception = aot_copy_exception(module_inst, exception);
1382+
if (has_exception && strstr(exception, "native stack overflow")) {
13821383
/* After a stack overflow, the stack was left
13831384
in a damaged state, let the CRT repair it */
13841385
result = _resetstkoflw();
@@ -1541,7 +1542,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
15411542
func_type, NULL, NULL, argv, argc, argv);
15421543

15431544
#if WASM_ENABLE_DUMP_CALL_STACK != 0
1544-
if (aot_get_exception(module_inst)) {
1545+
if (aot_copy_exception(module_inst, NULL)) {
15451546
if (aot_create_call_stack(exec_env)) {
15461547
aot_dump_call_stack(exec_env, true, NULL, 0);
15471548
}
@@ -1552,7 +1553,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
15521553
aot_free_frame(exec_env);
15531554
#endif
15541555

1555-
return ret && !aot_get_exception(module_inst) ? true : false;
1556+
return ret && !aot_copy_exception(module_inst, NULL) ? true : false;
15561557
}
15571558
}
15581559

@@ -1611,6 +1612,14 @@ aot_get_exception(AOTModuleInstance *module_inst)
16111612
return wasm_get_exception(module_inst);
16121613
}
16131614

1615+
bool
1616+
aot_copy_exception(AOTModuleInstance *module_inst, char *exception_buf)
1617+
{
1618+
/* The field offsets of cur_exception in AOTModuleInstance and
1619+
WASMModuleInstance are the same */
1620+
return wasm_copy_exception(module_inst, exception_buf);
1621+
}
1622+
16141623
static bool
16151624
execute_malloc_function(AOTModuleInstance *module_inst,
16161625
AOTFunctionInstance *malloc_func,

core/iwasm/aot/aot_runtime.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,15 @@ aot_set_exception_with_id(AOTModuleInstance *module_inst, uint32 id);
415415
const char *
416416
aot_get_exception(AOTModuleInstance *module_inst);
417417

418+
/**
419+
* @brief Copy exception in buffer passed as parameter. Thread-safe version of
420+
* `aot_get_exception()`
421+
* @note Buffer size must be no smaller than EXCEPTION_BUF_LEN
422+
* @return true if exception found, false otherwise
423+
*/
424+
bool
425+
aot_copy_exception(AOTModuleInstance *module_inst, char *exception_buf);
426+
418427
uint32
419428
aot_module_malloc(AOTModuleInstance *module_inst, uint32 size,
420429
void **p_native_addr);

core/iwasm/common/wasm_runtime_common.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2331,12 +2331,6 @@ wasm_set_exception(WASMModuleInstance *module_inst, const char *exception)
23312331
if (exec_env) {
23322332
wasm_cluster_spread_exception(exec_env, exception ? false : true);
23332333
}
2334-
#if WASM_ENABLE_SHARED_MEMORY
2335-
if (exception) {
2336-
notify_stale_threads_on_exception(
2337-
(WASMModuleInstanceCommon *)module_inst);
2338-
}
2339-
#endif
23402334
#else
23412335
(void)exec_env;
23422336
#endif
@@ -3144,6 +3138,21 @@ uint32_t
31443138
wasm_runtime_get_wasi_exit_code(WASMModuleInstanceCommon *module_inst)
31453139
{
31463140
WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst);
3141+
#if WASM_ENABLE_THREAD_MGR != 0
3142+
WASMCluster *cluster;
3143+
WASMExecEnv *exec_env;
3144+
3145+
exec_env = wasm_runtime_get_exec_env_singleton(module_inst);
3146+
if (exec_env && (cluster = wasm_exec_env_get_cluster(exec_env))) {
3147+
/**
3148+
* The main thread may exit earlier than other threads, and
3149+
* the exit_code of wasi_ctx may be changed by other thread
3150+
* when it runs into wasi_proc_exit, here we wait until all
3151+
* other threads exit to avoid getting invalid exit_code.
3152+
*/
3153+
wasm_cluster_wait_for_all_except_self(cluster, exec_env);
3154+
}
3155+
#endif
31473156
return wasi_ctx->exit_code;
31483157
}
31493158

core/iwasm/common/wasm_shared_memory.c

Lines changed: 41 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -106,61 +106,6 @@ search_module(WASMModuleCommon *module)
106106
return NULL;
107107
}
108108

109-
static void
110-
wait_map_address_count_callback(void *key, void *value,
111-
void *p_total_elem_count)
112-
{
113-
*(uint32 *)p_total_elem_count = *(uint32 *)p_total_elem_count + 1;
114-
}
115-
116-
static void
117-
create_list_of_waiter_addresses(void *key, void *value, void *user_data)
118-
{
119-
AtomicWaitAddressArgs *data = (AtomicWaitAddressArgs *)user_data;
120-
data->addr[data->index++] = key;
121-
}
122-
123-
void
124-
notify_stale_threads_on_exception(WASMModuleInstanceCommon *module_inst)
125-
{
126-
AtomicWaitAddressArgs args = { 0 };
127-
uint32 i = 0, total_elem_count = 0;
128-
uint64 total_elem_count_size = 0;
129-
130-
os_mutex_lock(&wait_map_lock); /* Make the two traversals atomic */
131-
132-
/* count number of addresses in wait_map */
133-
bh_hash_map_traverse(wait_map, wait_map_address_count_callback,
134-
(void *)&total_elem_count);
135-
136-
if (!total_elem_count) {
137-
os_mutex_unlock(&wait_map_lock);
138-
return;
139-
}
140-
141-
/* allocate memory */
142-
total_elem_count_size = (uint64)sizeof(void *) * total_elem_count;
143-
if (total_elem_count_size >= UINT32_MAX
144-
|| !(args.addr = wasm_runtime_malloc((uint32)total_elem_count_size))) {
145-
LOG_ERROR(
146-
"failed to allocate memory for list of atomic wait addresses");
147-
os_mutex_unlock(&wait_map_lock);
148-
return;
149-
}
150-
151-
/* set values in list of addresses */
152-
bh_hash_map_traverse(wait_map, create_list_of_waiter_addresses, &args);
153-
os_mutex_unlock(&wait_map_lock);
154-
155-
/* notify */
156-
for (i = 0; i < args.index; i++) {
157-
wasm_runtime_atomic_notify(module_inst, args.addr[i], UINT32_MAX);
158-
}
159-
160-
/* free memory allocated to args data */
161-
wasm_runtime_free(args.addr);
162-
}
163-
164109
WASMSharedMemNode *
165110
wasm_module_get_shared_memory(WASMModuleCommon *module)
166111
{
@@ -413,7 +358,9 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
413358
AtomicWaitInfo *wait_info;
414359
AtomicWaitNode *wait_node;
415360
WASMSharedMemNode *node;
361+
#if WASM_ENABLE_THREAD_MGR != 0
416362
WASMExecEnv *exec_env;
363+
#endif
417364
bool check_ret, is_timeout, no_wait;
418365

419366
bh_assert(module->module_type == Wasm_Module_Bytecode
@@ -489,14 +436,47 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
489436
/* condition wait start */
490437
os_mutex_lock(&wait_node->wait_lock);
491438

492-
if (!no_wait
439+
if (!no_wait) {
440+
/* unit of timeout is nsec, convert it to usec */
441+
uint64 timeout_left = (uint64)timeout / 1000, timeout_wait;
442+
uint64 timeout_1sec = 1e6;
443+
444+
while (1) {
445+
if (timeout < 0) {
446+
/* wait forever until it is notified or terminatied
447+
here we keep waiting and checking every second */
448+
os_cond_reltimedwait(&wait_node->wait_cond,
449+
&wait_node->wait_lock,
450+
(uint64)timeout_1sec);
451+
if (wait_node->status
452+
== S_NOTIFIED /* notified by atomic.notify */
453+
#if WASM_ENABLE_THREAD_MGR != 0
454+
/* terminated by other thread */
455+
|| wasm_cluster_is_thread_terminated(exec_env)
456+
#endif
457+
) {
458+
break;
459+
}
460+
/* continue to wait */
461+
}
462+
else {
463+
timeout_wait =
464+
timeout_left < timeout_1sec ? timeout_left : timeout_1sec;
465+
os_cond_reltimedwait(&wait_node->wait_cond,
466+
&wait_node->wait_lock, timeout_wait);
467+
if (wait_node->status
468+
== S_NOTIFIED /* notified by atomic.notify */
469+
|| timeout_left <= timeout_wait /* time out */
493470
#if WASM_ENABLE_THREAD_MGR != 0
494-
&& !wasm_cluster_is_thread_terminated(exec_env)
471+
/* terminated by other thread */
472+
|| wasm_cluster_is_thread_terminated(exec_env)
495473
#endif
496-
) {
497-
os_cond_reltimedwait(&wait_node->wait_cond, &wait_node->wait_lock,
498-
timeout < 0 ? BHT_WAIT_FOREVER
499-
: (uint64)timeout / 1000);
474+
) {
475+
break;
476+
}
477+
timeout_left -= timeout_wait;
478+
}
479+
}
500480
}
501481

502482
is_timeout = wait_node->status == S_WAITING ? true : false;

core/iwasm/common/wasm_shared_memory.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#define _WASM_SHARED_MEMORY_H
88

99
#include "bh_common.h"
10-
#include "wasm_exec_env.h"
1110
#if WASM_ENABLE_INTERP != 0
1211
#include "wasm_runtime.h"
1312
#endif
@@ -40,9 +39,6 @@ wasm_shared_memory_init();
4039
void
4140
wasm_shared_memory_destroy();
4241

43-
void
44-
notify_stale_threads_on_exception(WASMModuleInstanceCommon *module);
45-
4642
WASMSharedMemNode *
4743
wasm_module_get_shared_memory(WASMModuleCommon *module);
4844

core/iwasm/libraries/lib-wasi-threads/test/update_shared_data_and_alloc_heap.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ __wasi_thread_start_C(int thread_id, int *start_arg)
4141
for (int i = 0; i < NUM_ITER; i++)
4242
__atomic_fetch_add(data->count, 1, __ATOMIC_SEQ_CST);
4343

44-
pthread_mutex_lock(&mutex); /* malloc is not thread-safe in wasi-libc */
45-
vals[data->iteration] = malloc(sizeof(int));
46-
pthread_mutex_unlock(&mutex);
4744
*vals[data->iteration] = data->iteration;
4845

4946
__atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST);
@@ -60,6 +57,11 @@ main(int argc, char **argv)
6057
assert(count != NULL && "Failed to call calloc");
6158
assert(pthread_mutex_init(&mutex, NULL) == 0 && "Failed to init mutex");
6259

60+
for (int i = 0; i < NUM_THREADS; i++) {
61+
vals[i] = malloc(sizeof(int));
62+
assert(vals[i] != NULL && "Failed to call calloc");
63+
}
64+
6365
for (int i = 0; i < NUM_THREADS; i++) {
6466
assert(start_args_init(&data[i].base)
6567
&& "Stack allocation for thread failed");

core/iwasm/libraries/thread-mgr/thread_manager.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,9 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
525525
goto fail4;
526526
}
527527

528+
/* Inherit suspend_flags of parent thread */
529+
new_exec_env->suspend_flags.flags = exec_env->suspend_flags.flags;
530+
528531
if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
529532
goto fail4;
530533

@@ -674,6 +677,9 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env,
674677
new_exec_env->aux_stack_bottom.bottom = UINT32_MAX;
675678
}
676679

680+
/* Inherit suspend_flags of parent thread */
681+
new_exec_env->suspend_flags.flags = exec_env->suspend_flags.flags;
682+
677683
if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
678684
goto fail3;
679685

0 commit comments

Comments
 (0)