-
Notifications
You must be signed in to change notification settings - Fork 628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
handle a return from wasi _start function correctly #2529
handle a return from wasi _start function correctly #2529
Conversation
this fixes a few test cases in wasi-threads testsuite like wasi_threads_return_main_block. also, move the special handling for wasi proc exit to a more appropriate place.
9b77116
to
935f055
Compare
extracted from #2516 |
if (ret) { | ||
wasm_runtime_set_exception(module_inst, wasi_proc_exit_exception); | ||
/* exit_code is zero-initialized */ | ||
ret = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why need to set wasi_proc_exit_exception
here? If ret is true, there should be no exception thrown and wasi_exit_code was already initialized as 0, seems we can do nothing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to propagate it to other threads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the main thread will wait until all other threads exit in wasm_exec_env_destroy, it doesn't meet the "wasi proc exit" exception, seems no need to propagate "wasi proc exit" for other threads to exit early? Or other threads may not finish their jobs normally, also other threads may fail to throw exception if they continue to run?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- a return from _start should behave as exit(0) because it's what wasi-libc expects.
- exit(0) should terminate other threads.
wasm_runtime_set_exception here is just a convenient way to terminate other threads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I my concern is, suppose the sub thread is doing an important job, e.g. do some calculation, output important data to a file, can we terminate it from the main thread? Is it better to wait until the sub threads exit? In fact, there is API wasm_cluster_wait_for_all_except_self in thread manager.
Not sure whether there is reference about "a return from _start should behave as exit(0)" in wasi-libc?
@loganek What's your opinion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not sure if i understand your concern.
the importance of the job is something apps should consider. not runtime.
Not sure whether there is reference about "a return from _start should behave as exit(0)" in wasi-libc?
- a return from main() is an equivalent of exit(). (C standard)
- wasi-libc maps a return from main() to a return from
_start
when the exit code is 0. https://github.com/WebAssembly/wasi-libc/blob/ec4566beae84e54952637f0bf61bee4b4cacc087/libc-bottom-half/crt/crt1-command.c#L48-L52
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not very sure whether it is a good behavior that the main thread terminates all others thread instead of waiting for them. But if you want to do that, can we just call the API wasm_cluster_terminate_all_except_self
of thread manager:
#if WASM_ENABLE_THREAD_MGR != 0
if (ret) {
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
wasm_cluster_terminate_all_except_self(cluster, exec_env);
}
#endif
It also sets the terminate flag for other threads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i chose to use wasm_runtime_set_exception because:
- what i want to do here is to mimic wasi proc_exit, which uses wasm_runtime_set_exception.
- wasm_cluster_terminate_all_except_self seems unused (thus untested) and broken. (cluster->lock vs cluster_list_lock locking order issue.)
- we don't need to join threads here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, if to use wasm_runtime_set_exception, could you please add comments to mention somewhat like we want to mimic wasi proc_exit and to terminate other threads? It is not very easy to understand the code :)
And could you wrap the code with #if WASM_ENABLE_THREAD_MGR != 0 .. #endif
, it is only for multi-threading?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, if to use wasm_runtime_set_exception, could you please add comments to mention somewhat like we want to mimic wasi proc_exit and to terminate other threads? It is not very easy to understand the code :) And could you wrap the code with
#if WASM_ENABLE_THREAD_MGR != 0 .. #endif
, it is only for multi-threading?
i prefer less #ifdef in general. but ok. done.
} | ||
return false; | ||
if (new_argv != argv) { | ||
wasm_runtime_free(new_argv); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clear_wasi_proc_exit_exception
is only applied after calling wasi _start
function now, is it a general handling of wasi? Will developer call other functions in wasi mode and then wasm_proc_exit
occurs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i guess it's a gray area.
proc_exit is supposed to terminate the "process".
the concept of "process" only makes sense in the context of a wasi command.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable, maybe we can apply the changes first, and modify if needed in the future.
} | ||
/* report wasm proc exit as a success */ | ||
WASMModuleInstance *inst = (WASMModuleInstance *)module_inst; | ||
if (!ret && strstr(inst->cur_exception, wasi_proc_exit_exception)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems both L117 and L115 make if
in L121 always true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's false if (ret == false and cur_exception == some other exception).
@@ -107,7 +107,22 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) | |||
the actual main function. Directly calling main function | |||
may cause exception thrown. */ | |||
if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) { | |||
return wasm_runtime_call_wasm(exec_env, func, 0, NULL); | |||
const char *wasi_proc_exit_exception = "wasi proc exit"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it better if we use a global variable or macro to represent the string "wasi proc exit"? It is a very import constant string now。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ideally we should stop using strings i guess.
also, make some code conditional on WASM_ENABLE_THREAD_MGR
LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I know we already had this conversation with @yamt, but with these changes, should we update trap_after_main_thread_finishes.c to have 0 as exit code and to replace the trap here with an assert? And even change the name of the tests and put some comments to describe the expected behavior. I could do it as a separate PR if it makes sense. Or we drop the test completely since it has some overlapping with https://github.com/WebAssembly/wasi-threads/blob/main/test/testsuite/wasi_threads_exit_main_block.wat. Because the test had another goal initially, to make sure the spawned threads kept running and its trap error code was propagated to the runtime. Now the implemented behavior is different instead. So I think we should update the test or drop it (it doesn't make much sense to me to keep it as it is). |
i'm not sure if i understand what updates you are suggesting.
it's also fine for me. |
@eloparco I understand that the main thread already returns 0 and no need to change it. Changing buildin_trap to assert is that buildin_trap will throw exception in spawned thread, while assert (assume we use assert(true statement)) won't throw exception and the spawned thread exits normally. I think it is a good case and had better not change it. A possible issue is that after main function returns and runtime set_exception("wasi proc exit") to the spawned thread, and then before the spawned thread handles the exception and terminate flag, it runs into the builtin_trap, throws unreachable exception and ends first. That means the main thread returns 0 while sub thread throws exception (and it may spread to the main thread then), not sure whether we should handle it? @yamt |
wrt racing multiple traps/exit, i plan to prevent wasm_runtime_set_exception from overwriting existing trap/exit. (not within this PR though) |
Got it, great, thanks! |
On posix-like platforms, the rest of wasi-threads tests should pass after the recent changes including the following PRs: bytecodealliance#2516 bytecodealliance#2524 bytecodealliance#2529
On posix-like platforms, the rest of wasi-threads tests should pass after the recent changes including the following PRs: bytecodealliance#2516 bytecodealliance#2524 bytecodealliance#2529
On posix-like platforms, the rest of wasi-threads tests should pass after the recent changes including the following PRs: bytecodealliance#2516 bytecodealliance#2524 bytecodealliance#2529
On posix-like platforms, the rest of wasi-threads tests should pass after the recent changes including the following PRs: bytecodealliance#2516 bytecodealliance#2524 bytecodealliance#2529
…#2529) This fixes a few test cases in wasi-threads testsuite like wasi_threads_return_main_block. And also move the special handling for "wasi proc exit" to a more appropriate place.
On posix-like platforms, the rest of wasi-threads tests should pass after the recent changes including the following PRs: bytecodealliance#2516, bytecodealliance#2524, bytecodealliance#2529, bytecodealliance#2571, bytecodealliance#2576 and bytecodealliance#2582.
this fixes a few test cases in wasi-threads testsuite like wasi_threads_return_main_block.
also, move the special handling for wasi proc exit to a more appropriate place.