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.
With
-pthread -sPROXY_TO_PTHREAD -sEXIT_RUNTIME, ifmainreturns while a runtime keepalive is held (e.g. a pendingemscripten_set_timeout),_main_threadincrt1_proxy_main.cskipsexit()and returns from the thread routine. When the keepalive later reaches 0,maybeExitcalls_emscripten_thread_exit(EXITSTATUS)on the worker, but nothing ever runsexit():atexithandlers andModule.onExitnever fire, and the process exits 0 once Node's loop drains, regardless of main's return value.emcc t.c -sEXIT_RUNTIME -pthread -sPROXY_TO_PTHREAD && node t.js; echo $?printsfiredthen0. Without-sPROXY_TO_PTHREADit printsfired,done,exitedand exits 3. Expected: the same in both modes — the proxied main thread's implicit exit should callexit(EXITSTATUS)when its keepalive drops to zero, as the direct-main path does.The skip of
exit()in_main_threadwhen the keepalive is held is correct; what's missing is the deferredexit(EXITSTATUS)when the count later reaches zero on the proxied thread, mirroringmaybeExit→_exiton the direct-main path.