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
8 changes: 4 additions & 4 deletions src/lib/libpthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know why this was PROXY_TO_PTHREAD-only before? The above comment now sounds like its needed in all cases... but there must be some reason why its not always needed? I.e. in the normal case when we have are not PROXY_TO_PTHREAD and when we do have a main why don't we need to unref when we return workers to the pool?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helps reduce code size, since previously only the "main" thread in PROXY_TO_PTHREAD mode was strongly referenced at this point, see:
https://github.com/emscripten-core/emscripten/pull/19073/changes#r1172276555

Plus, _emscripten_thread_set_strongref() is internal API, so we can be sure all non-PROXY_TO_PTHREAD workers are weakly referenced.

}
Expand Down Expand Up @@ -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
Expand Down
26 changes: 26 additions & 0 deletions test/core/pthread/test_pthread_exit_library.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <emscripten.h>
#include <emscripten/threading.h>

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);
}
3 changes: 3 additions & 0 deletions test/core/pthread/test_pthread_exit_library.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
initialized
worker starting
exiting
7 changes: 7 additions & 0 deletions test/core/pthread/test_pthread_exit_library.pre.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
let { promise, resolve } = Promise.withResolvers();
promise.then(() => console.log('exiting'));

Module['onRuntimeInitialized'] = function() {
console.log('initialized');
_create_thread_async();
};
7 changes: 7 additions & 0 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Loading