diff --git a/src/lib/libpthread.js b/src/lib/libpthread.js index 0ad90f9cd68dc..c60fed2271f20 100644 --- a/src/lib/libpthread.js +++ b/src/lib/libpthread.js @@ -208,11 +208,11 @@ var LibraryPThread = { // worker pool as an unused worker. worker.pthread_ptr = 0; -#if ENVIRONMENT_MAY_BE_NODE && PROXY_TO_PTHREAD +#if ENVIRONMENT_MAY_BE_NODE && (PROXY_TO_PTHREAD || !HAS_MAIN) if (ENVIRONMENT_IS_NODE) { - // Once the proxied main thread has finished, mark it as weakly + // Once the worker is returned to the pool, mark it as weakly // referenced so that its existence does not prevent Node.js from - // exiting. This has no effect if the worker is already weakly + // exiting. This has no effect if the worker is already weakly // referenced. worker.unref(); } @@ -687,7 +687,7 @@ var LibraryPThread = { msg.moduleCanvasId = threadParams.moduleCanvasId; msg.offscreenCanvases = threadParams.offscreenCanvases; #endif -#if ENVIRONMENT_MAY_BE_NODE +#if ENVIRONMENT_MAY_BE_NODE && HAS_MAIN if (ENVIRONMENT_IS_NODE) { // Mark worker as weakly referenced once we start executing a pthread, // so that its existence does not prevent Node.js from exiting. This diff --git a/test/core/pthread/test_pthread_exit_library.c b/test/core/pthread/test_pthread_exit_library.c new file mode 100644 index 0000000000000..73f7f3b454401 --- /dev/null +++ b/test/core/pthread/test_pthread_exit_library.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include +#include + +void* worker(void* arg) { + printf("worker starting\n"); + fflush(stdout); + emscripten_thread_sleep(100); + + // proxy back to the main thread + MAIN_THREAD_ASYNC_EM_ASM({ + resolve(); + }); + return NULL; +} + +EMSCRIPTEN_KEEPALIVE +void create_thread_async() { + pthread_t thread; + int rc = pthread_create(&thread, NULL, worker, NULL); + assert(rc == 0); + pthread_detach(thread); +} diff --git a/test/core/pthread/test_pthread_exit_library.out b/test/core/pthread/test_pthread_exit_library.out new file mode 100644 index 0000000000000..74b439c12c36e --- /dev/null +++ b/test/core/pthread/test_pthread_exit_library.out @@ -0,0 +1,3 @@ +initialized +worker starting +exiting diff --git a/test/core/pthread/test_pthread_exit_library.pre.js b/test/core/pthread/test_pthread_exit_library.pre.js new file mode 100644 index 0000000000000..ab185ae8750b7 --- /dev/null +++ b/test/core/pthread/test_pthread_exit_library.pre.js @@ -0,0 +1,7 @@ +let { promise, resolve } = Promise.withResolvers(); +promise.then(() => console.log('exiting')); + +Module['onRuntimeInitialized'] = function() { + console.log('initialized'); + _create_thread_async(); +}; diff --git a/test/test_core.py b/test/test_core.py index b0a64a4940c7c..2aad268fbea65 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9164,6 +9164,13 @@ def test_pthread_keepalive(self): def test_pthread_weak_ref(self): self.do_core_test('pthread/test_pthread_weak_ref.c') + @no_asan('asan exits the runtime') + @requires_pthreads + def test_pthread_exit_library(self): + # Test that Node.js doesn't exit while there are still pthreads running when there is no main function. + self.cflags += ['--pre-js', test_file('core/pthread/test_pthread_exit_library.pre.js')] + self.do_core_test('pthread/test_pthread_exit_library.c') + @requires_pthreads def test_pthread_exit_main(self): self.do_core_test('pthread/test_pthread_exit_main.c')