PROXY_TO_PTHREAD: runtime never exits when the proxied main thread's keepalive drops to 0 after main returns
With -pthread -sPROXY_TO_PTHREAD -sEXIT_RUNTIME, if main returns while a runtime keepalive is held (e.g. a pending emscripten_set_timeout), _main_thread in crt1_proxy_main.c skips exit() and returns from the thread routine. When the keepalive later reaches 0, maybeExit calls _emscripten_thread_exit(EXITSTATUS) on the worker, but nothing ever runs exit(): atexit handlers and Module.onExit never fire, and the process exits 0 once Node's loop drains, regardless of main's return value.
#include <stdio.h>
#include <stdlib.h>
#include <emscripten.h>
#include <emscripten/eventloop.h>
void fired(void* a) { printf("fired\n"); }
void at_exit(void) { printf("done\n"); }
int main() {
MAIN_THREAD_EM_ASM({ Module['onExit'] = () => out('exited'); });
atexit(at_exit);
emscripten_set_timeout(fired, 10, 0);
return 3;
}emcc t.c -sEXIT_RUNTIME -pthread -sPROXY_TO_PTHREAD && node t.js; echo $? prints fired then 0. Without -sPROXY_TO_PTHREAD it prints fired, done, exited and exits 3. Expected: the same in both modes — the proxied main thread's implicit exit should call exit(EXITSTATUS) when its keepalive drops to zero, as the direct-main path does.
The skip of exit() in _main_thread when the keepalive is held is correct; what's missing is the deferred exit(EXITSTATUS) when the count later reaches zero on the proxied thread, mirroring maybeExit → _exit on the direct-main path.
Source: emscripten-core/emscripten