Skip to content

Commit 3f95447

Browse files
authored
thread-mgr: Fix spread "wasi proc exit" exception and atomic.wait issues (bytecodealliance#1988)
Raising "wasi proc exit" exception, spreading it to other threads and then clearing it in all threads may result in unexpected behavior: the sub thread may end first, handle the "wasi proc exit" exception and clear exceptions of other threads, including the main thread. And when main thread's exception is cleared, it may continue to run and throw "unreachable" exception. This also leads to some assertion failed. Ignore exception spreading for "wasi proc exit" and don't clear exception of other threads to resolve the issue. And add suspend flag check after atomic wait since the atomic wait may be notified by other thread when exception occurs.
1 parent 6eb581f commit 3f95447

File tree

8 files changed

+84
-19
lines changed

8 files changed

+84
-19
lines changed

core/iwasm/common/wasm_runtime_common.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,8 +1880,10 @@ clear_wasi_proc_exit_exception(WASMModuleInstanceCommon *module_inst_comm)
18801880
if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
18811881
/* The "wasi proc exit" exception is thrown by native lib to
18821882
let wasm app exit, which is a normal behavior, we clear
1883-
the exception here. */
1884-
wasm_set_exception(module_inst, NULL);
1883+
the exception here. And just clear the exception of current
1884+
thread, don't call `wasm_set_exception(module_inst, NULL)`
1885+
which will clear the exception of all threads. */
1886+
module_inst->cur_exception[0] = '\0';
18851887
return true;
18861888
}
18871889
return false;

core/iwasm/compilation/aot_emit_function.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,14 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
999999
}
10001000
#endif
10011001

1002+
#if WASM_ENABLE_THREAD_MGR != 0
1003+
/* Insert suspend check point */
1004+
if (comp_ctx->enable_thread_mgr) {
1005+
if (!check_suspend_flags(comp_ctx, func_ctx))
1006+
goto fail;
1007+
}
1008+
#endif
1009+
10021010
ret = true;
10031011
fail:
10041012
if (param_types)
@@ -1645,6 +1653,14 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
16451653
}
16461654
#endif
16471655

1656+
#if WASM_ENABLE_THREAD_MGR != 0
1657+
/* Insert suspend check point */
1658+
if (comp_ctx->enable_thread_mgr) {
1659+
if (!check_suspend_flags(comp_ctx, func_ctx))
1660+
goto fail;
1661+
}
1662+
#endif
1663+
16481664
ret = true;
16491665

16501666
fail:

core/iwasm/compilation/aot_emit_memory.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "aot_emit_exception.h"
88
#include "../aot/aot_runtime.h"
99
#include "aot_intrinsic.h"
10+
#include "aot_emit_control.h"
1011

1112
#define BUILD_ICMP(op, left, right, res, name) \
1213
do { \
@@ -1344,7 +1345,7 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
13441345
return false;
13451346
}
13461347

1347-
BUILD_ICMP(LLVMIntSGT, ret_value, I32_ZERO, cmp, "atomic_wait_ret");
1348+
BUILD_ICMP(LLVMIntNE, ret_value, I32_NEG_ONE, cmp, "atomic_wait_ret");
13481349

13491350
ADD_BASIC_BLOCK(wait_fail, "atomic_wait_fail");
13501351
ADD_BASIC_BLOCK(wait_success, "wait_success");
@@ -1368,6 +1369,14 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
13681369

13691370
PUSH_I32(ret_value);
13701371

1372+
#if WASM_ENABLE_THREAD_MGR != 0
1373+
/* Insert suspend check point */
1374+
if (comp_ctx->enable_thread_mgr) {
1375+
if (!check_suspend_flags(comp_ctx, func_ctx))
1376+
return false;
1377+
}
1378+
#endif
1379+
13711380
return true;
13721381
fail:
13731382
return false;

core/iwasm/interpreter/wasm_interp_classic.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3422,6 +3422,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
34223422
if (ret == (uint32)-1)
34233423
goto got_exception;
34243424

3425+
#if WASM_ENABLE_THREAD_MGR != 0
3426+
CHECK_SUSPEND_FLAGS();
3427+
#endif
3428+
34253429
PUSH_I32(ret);
34263430
break;
34273431
}
@@ -3442,6 +3446,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
34423446
if (ret == (uint32)-1)
34433447
goto got_exception;
34443448

3449+
#if WASM_ENABLE_THREAD_MGR != 0
3450+
CHECK_SUSPEND_FLAGS();
3451+
#endif
3452+
34453453
PUSH_I32(ret);
34463454
break;
34473455
}
@@ -3894,10 +3902,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
38943902
PUSH_CSP(LABEL_TYPE_FUNCTION, 0, cell_num, frame_ip_end - 1);
38953903

38963904
wasm_exec_env_set_cur_frame(exec_env, frame);
3905+
}
38973906
#if WASM_ENABLE_THREAD_MGR != 0
3898-
CHECK_SUSPEND_FLAGS();
3907+
CHECK_SUSPEND_FLAGS();
38993908
#endif
3900-
}
39013909
HANDLE_OP_END();
39023910
}
39033911

core/iwasm/interpreter/wasm_interp_fast.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3266,6 +3266,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
32663266
if (ret == (uint32)-1)
32673267
goto got_exception;
32683268

3269+
#if WASM_ENABLE_THREAD_MGR != 0
3270+
CHECK_SUSPEND_FLAGS();
3271+
#endif
3272+
32693273
PUSH_I32(ret);
32703274
break;
32713275
}
@@ -3286,6 +3290,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
32863290
if (ret == (uint32)-1)
32873291
goto got_exception;
32883292

3293+
#if WASM_ENABLE_THREAD_MGR != 0
3294+
CHECK_SUSPEND_FLAGS();
3295+
#endif
3296+
32893297
PUSH_I32(ret);
32903298
break;
32913299
}
@@ -3826,6 +3834,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
38263834

38273835
wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)frame);
38283836
}
3837+
#if WASM_ENABLE_THREAD_MGR != 0
3838+
CHECK_SUSPEND_FLAGS();
3839+
#endif
38293840
HANDLE_OP_END();
38303841
}
38313842

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ wasm_cluster_create(WASMExecEnv *exec_env)
225225
/* Prepare the aux stack top and size for every thread */
226226
if (!wasm_exec_env_get_aux_stack(exec_env, &aux_stack_start,
227227
&aux_stack_size)) {
228+
#if WASM_ENABLE_LIB_WASI_THREADS == 0
228229
LOG_VERBOSE("No aux stack info for this module, can't create thread");
230+
#endif
229231

230232
/* If the module don't have aux stack info, don't throw error here,
231233
but remain stack_tops and stack_segment_occupied as NULL */
@@ -1131,9 +1133,14 @@ set_exception_visitor(void *node, void *user_data)
11311133
WASMModuleInstance *curr_wasm_inst =
11321134
(WASMModuleInstance *)get_module_inst(curr_exec_env);
11331135

1134-
bh_memcpy_s(curr_wasm_inst->cur_exception,
1135-
sizeof(curr_wasm_inst->cur_exception),
1136-
wasm_inst->cur_exception, sizeof(wasm_inst->cur_exception));
1136+
/* Only spread non "wasi proc exit" exception */
1137+
if (!strstr(wasm_inst->cur_exception, "wasi proc exit")) {
1138+
bh_memcpy_s(curr_wasm_inst->cur_exception,
1139+
sizeof(curr_wasm_inst->cur_exception),
1140+
wasm_inst->cur_exception,
1141+
sizeof(wasm_inst->cur_exception));
1142+
}
1143+
11371144
/* Terminate the thread so it can exit from dead loops */
11381145
set_thread_cancel_flags(curr_exec_env);
11391146
}
@@ -1203,4 +1210,4 @@ bool
12031210
wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env)
12041211
{
12051212
return (exec_env->suspend_flags.flags & 0x01) ? true : false;
1206-
}
1213+
}

samples/wasi-threads/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ $ ./iwasm wasm-apps/exception_propagation.wasm
2626
## Run samples in AOT mode
2727
```shell
2828
$ ../../../wamr-compiler/build/wamrc \
29+
--enable-multi-thread \
2930
-o wasm-apps/no_pthread.aot wasm-apps/no_pthread.wasm
3031
$ ./iwasm wasm-apps/no_pthread.aot
3132
```

samples/wasi-threads/wasm-apps/thread_termination.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@
1515

1616
#include "wasi_thread_start.h"
1717

18-
#define TEST_TERMINATION_BY_TRAP 0 // Otherwise test `proc_exit` termination
19-
#define TEST_TERMINATION_IN_MAIN_THREAD 1
18+
#define BUSY_WAIT 0
19+
#define ATOMIC_WAIT 1
20+
#define POLL_ONEOFF 2
21+
22+
/* Change parameters here to modify the sample behavior */
23+
#define TEST_TERMINATION_BY_TRAP 0 /* Otherwise `proc_exit` termination */
24+
#define TEST_TERMINATION_IN_MAIN_THREAD 1 /* Otherwise in spawn thread */
25+
#define LONG_TASK_IMPL ATOMIC_WAIT
2026

2127
#define TIMEOUT_SECONDS 10
2228
#define NUM_THREADS 3
@@ -30,23 +36,28 @@ typedef struct {
3036
void
3137
run_long_task()
3238
{
33-
// Busy waiting to be interruptible by trap or `proc_exit`
39+
#if LONG_TASK_IMPL == BUSY_WAIT
3440
for (int i = 0; i < TIMEOUT_SECONDS; i++)
3541
sleep(1);
42+
#elif LONG_TASK_IMPL == ATOMIC_WAIT
43+
__builtin_wasm_memory_atomic_wait32(0, 0, -1);
44+
#else
45+
sleep(TIMEOUT_SECONDS);
46+
#endif
3647
}
3748

3849
void
3950
start_job()
4051
{
4152
sem_post(&sem);
42-
run_long_task(); // Wait to be interrupted
53+
run_long_task(); /* Wait to be interrupted */
4354
assert(false && "Unreachable");
4455
}
4556

4657
void
4758
terminate_process()
4859
{
49-
// Wait for all other threads (including main thread) to be ready
60+
/* Wait for all other threads (including main thread) to be ready */
5061
printf("Waiting before terminating\n");
5162
for (int i = 0; i < NUM_THREADS; i++)
5263
sem_wait(&sem);
@@ -55,7 +66,7 @@ terminate_process()
5566
#if TEST_TERMINATION_BY_TRAP == 1
5667
__builtin_trap();
5768
#else
58-
__wasi_proc_exit(1);
69+
__wasi_proc_exit(33);
5970
#endif
6071
}
6172

@@ -86,14 +97,14 @@ main(int argc, char **argv)
8697
}
8798

8899
for (i = 0; i < NUM_THREADS; i++) {
89-
// No graceful memory free to simplify the example
100+
/* No graceful memory free to simplify the example */
90101
if (!start_args_init(&data[i].base)) {
91102
printf("Failed to allocate thread's stack\n");
92103
return EXIT_FAILURE;
93104
}
94105
}
95106

96-
// Create a thread that forces termination through trap or `proc_exit`
107+
/* Create a thread that forces termination through trap or `proc_exit` */
97108
#if TEST_TERMINATION_IN_MAIN_THREAD == 1
98109
data[0].throw_exception = false;
99110
#else
@@ -105,7 +116,7 @@ main(int argc, char **argv)
105116
return EXIT_FAILURE;
106117
}
107118

108-
// Create two additional threads to test exception propagation
119+
/* Create two additional threads to test exception propagation */
109120
data[1].throw_exception = false;
110121
thread_id = __wasi_thread_spawn(&data[1]);
111122
if (thread_id < 0) {
@@ -128,4 +139,4 @@ main(int argc, char **argv)
128139
start_job();
129140
#endif /* TEST_TERMINATION_IN_MAIN_THREAD */
130141
return EXIT_SUCCESS;
131-
}
142+
}

0 commit comments

Comments
 (0)