emscripten-core / emscripten-core/emscripten
Interaction between runtime exit, threads, and fetch
- Dominant language
- C++
- Stars
- 27.6k
- Forks
- 3.6k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 105
Description
There are currently several quirks regarding runtime exit, and its interaction with pthreads and the async fetch API (and similar APIs that register async work).
1) The default value of exitRuntime for pthreads is true (which is the opposite of what it is for the main thread). This is because a thread can't be `join()`-ed until its runtime exits, and there is a of course a strong expectation that threads are joinable after the thread's entry function returns or `pthread_exit()` is called.
2) functions which register asynchronous work (such as `emscripten_fetch()` and `emscripten_set_main_loop()` ) actually change the dynamic value of exitRuntime (setting it to false). This is so that the runtime doesn't die while there is still asynchronous work pending.
In isolation these decisions make some sense because usually what you want on the main thread is to return from `main` or otherwise exit with live runtime, and usually what you want on pthreads to exit and have the thread be joinable, and usually you do want your runtime to stay alive if there's pending async work. But the whole thing is hard to reason about.
Also there's currently no easy way to exit a thread's runtime when it gets set to noExitRuntime by `fetch`. (For that matter, is there an easy way to exit a pthread with a live runtime without changing the default for all threads? Is there an easy way to change the default for threads? Should there be?)
I think there are several things we should do and/or consider.
1) There's some [documentation](https://emscripten.org/docs/porting/emscripten-runtime-environment.html#emscripten-runtime-environment) about the runtime environment but it doesn't really mention the relevant issues (e.g. the behavior of C runtime such as `atexit`, or threads or async APIs). The relevant emscripten runtime functions are mostly [documented](https://emscripten.org/docs/api_reference/emscripten.h.html?highlight=exit_with_live_runtime#browser-execution-environment) but they also don't mention threads at all, nor does the pthreads [documentation](https://emscripten.org/docs/porting/pthreads.html) mention that aspect of the runtime.
We should fix all of that.
2) We should probably add a way to exit a thread's runtime (e.g. a thread-specific version of `emscripten_force_exit`)
3) Perhaps also a thread-specific `exit_with_live_runtime`?
4) Should we provide some way to control the runtime-exit behavior dynamically? Currently IIUC we only have the `noExitRuntime` JS var which is per-thread by virtue of its being JS but we might not want to make that the "official" thing. We could make up some API function and have it be per-thread (or global? would that be useful?). Another possibly nice way could be to make a pthread attr that would allow overriding the default at pthread creation time (although that might not help users of C++ `std::thread`).
5) Speaking of joining, do we currently model pthread joinability/detachment in a reasonable way?
6) We might consider changing the current interaction with async APIs like fetch to make it easier to reason about; e.g. `emscripten_fetch`, rather than silently changing the runtime-exit behavior of the current thread, could cause an error or warning to happen when a thread would exit with pending async work. This would allow the user to diagnose issues more easily.
Other ideas?
Contributor guide
Assessment
This issue has not been assessed yet.