Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/lib/libcore.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ addToLibrary({
#if PTHREADS
'$exitOnMainThread',
#endif
#if PROXY_TO_PTHREAD
'$proxiedMainDone',
#endif
#if PTHREADS_DEBUG || ASSERTIONS
'$runtimeKeepaliveCounter',
#endif
Expand All @@ -132,6 +135,10 @@ addToLibrary({
#endif
#if PTHREADS_DEBUG
dbg(`Pthread ${ptrToString(_pthread_self())} called exit(${status}), posting exitOnMainThread.`);
#endif
#if PROXY_TO_PTHREAD
// Forget a waiting main return.
proxiedMainDone = false;
#endif
// When running in a pthread we propagate the exit back to the main thread
// where it can decide if the whole process should be shut down or not.
Expand Down Expand Up @@ -2169,6 +2176,11 @@ addToLibrary({
#if PTHREADS
'_emscripten_thread_exit',
#endif
#if PROXY_TO_PTHREAD
'$proxiedMainDone',
'$proxiedMainExitCode',
'$exitOnMainThread',
#endif
#if RUNTIME_DEBUG >= 2
'$runtimeKeepaliveCounter',
#endif
Expand All @@ -2192,6 +2204,14 @@ addToLibrary({
// exit the current thread, but only if there is one active.
// TODO(https://github.com/emscripten-core/emscripten/issues/25076):
// Unify this check with the runtimeExited check above
#if PROXY_TO_PTHREAD && EXIT_RUNTIME
// Run a waiting main return once.
if (proxiedMainDone) {
proxiedMainDone = false;
exitOnMainThread(proxiedMainExitCode);
return;
}
#endif
if (_pthread_self()) __emscripten_thread_exit(EXITSTATUS);
return;
}
Expand Down
23 changes: 23 additions & 0 deletions src/lib/libpthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,20 @@ var LibraryPThread = {
_exit(returnCode);
},

#if PROXY_TO_PTHREAD
// Main's return, saved for maybeExit.
$proxiedMainDone__internal: true,
$proxiedMainDone: false,
$proxiedMainExitCode__internal: true,
$proxiedMainExitCode: 0,

__emscripten_proxied_main_done__deps: ['$proxiedMainDone', '$proxiedMainExitCode'],
__emscripten_proxied_main_done: (status) => {
proxiedMainDone = true;
proxiedMainExitCode = status;
},
#endif

#if MEMORY64
// Calls proxyToMainThread but returns a bigint rather than a number
$proxyToMainThreadPtr__deps: ['$proxyToMainThread'],
Expand Down Expand Up @@ -1144,6 +1158,10 @@ var LibraryPThread = {
#if !MINIMAL_RUNTIME
'$keepRuntimeAlive',
'$runtimeKeepaliveCounter',
#endif
#if PROXY_TO_PTHREAD
'$proxiedMainDone',
'$proxiedMainExitCode',
#endif
],
$invokeEntryPoint: {{{ asyncIf(ASYNCIFY == 2) }}}(ptr, arg) => {
Expand All @@ -1166,6 +1184,11 @@ var LibraryPThread = {
noExitRuntime = 0;
#endif
#endif
#if PROXY_TO_PTHREAD
// No main return waiting yet.
proxiedMainDone = false;
proxiedMainExitCode = 0;
#endif

#if MAIN_MODULE
// Before we call the thread entry point, make sure any shared libraries
Expand Down
2 changes: 2 additions & 0 deletions system/lib/libc/crt1_proxy_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ static void* _main_thread(void* param) {
if (!emscripten_runtime_keepalive_check()) {
exit(rtn);
}
// Wait for keepalives, then exit with main's status.
__emscripten_proxied_main_done(rtn);
return NULL;
}

Expand Down
2 changes: 2 additions & 0 deletions system/lib/pthread/threading_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ void _emscripten_init_main_thread_js(void* tb);
void _emscripten_thread_profiler_enable();
void _emscripten_thread_cleanup(pthread_t thread);

void __emscripten_proxied_main_done(int status);

hidden void* _emscripten_tls_init(void);
hidden void _emscripten_tls_free(void);

Expand Down
47 changes: 47 additions & 0 deletions test/other/test_proxied_main_keepalive_exit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Proxied main must exit with its status after keepalives run.
#include <emscripten.h>
#include <emscripten/eventloop.h>
#include <stdio.h>
#include <stdlib.h>

void at_exit(void) { printf("done\n"); }

#ifdef MODE_CLEARED
int long_id;

void never(void* arg) {
printf("cleared callback ran\n");
abort();
}
#endif

void fired(void* arg) {
printf("fired\n");
#ifdef MODE_CLEARED
emscripten_clear_timeout(long_id);
#elif defined(MODE_FORCE_EXIT)
// exit() beats a waiting return.
emscripten_force_exit(7);
#elif defined(MODE_EXIT)
exit(7);
#endif
}

int main(void) {
#ifdef MODE_NEGATIVE
// Check the value, not just the code.
MAIN_THREAD_EM_ASM({ Module['onExit'] = (c) => { out('exited:' + c); }; });
#else
MAIN_THREAD_EM_ASM({ Module['onExit'] = () => { out('exited'); }; });
#endif
atexit(at_exit);
#ifdef MODE_CLEARED
long_id = emscripten_set_timeout(never, 10000, NULL);
#endif
emscripten_set_timeout(fired, 10, NULL);
#ifdef MODE_NEGATIVE
return -1;
#else
return 3;
#endif
}
15 changes: 15 additions & 0 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -11603,6 +11603,21 @@ def test_proxy_to_pthread_stack(self):
'-sSTACK_SIZE=128kb', '-sEXIT_RUNTIME',
'--profiling-funcs'])

@requires_pthreads
@parameterized({
'': ([], 3, 'fired\ndone\nexited\n'),
'cleared': (['-DMODE_CLEARED'], 3, 'fired\ndone\nexited\n'),
'force_exit': (['-DMODE_FORCE_EXIT'], 7, 'fired\ndone\nexited\n'),
'exit': (['-DMODE_EXIT'], 7, 'fired\ndone\nexited\n'),
'negative': (['-DMODE_NEGATIVE'], NON_ZERO, 'fired\ndone\nexited:-1\n'),
})
def test_proxied_main_keepalive_exit(self, cflags, returncode, expected):
# See https://github.com/emscripten-core/emscripten/issues/27721
# Proxied main that returns with a keepalive must exit with its status.
self.do_runf('other/test_proxied_main_keepalive_exit.c', expected,
cflags=['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'] + cflags,
assert_returncode=returncode)

@crossplatform
@no_windows('ptys and select are not available on windows')
def test_color_diagnostics(self):
Expand Down