From a2fd1bcc6bff8c69ac11f7b7ee8df61449ca4e84 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 29 Sep 2021 14:04:49 -0700 Subject: [PATCH 1/2] Fix flaky test_pthread_c11_threads I tracked down this issue to a deadlock between the detached thread calling `printf()` (calling proxied write call while hold the stdout lock) and the main thread trying to shut down the runtime by (calling `fflush(0`)). The problem could be addressed if we allowed nested calls to `emscripten_current_thread_process_queued_calls`. Fixes: #14579 --- src/library_pthread.js | 5 ++++- tests/pthread/test_pthread_c11_threads.c | 22 ++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/library_pthread.js b/src/library_pthread.js index 3432e1d347fb8..593c620d39b67 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -1259,6 +1259,10 @@ var LibraryPThread = { #endif }, + // This function is call by a pthread to signal that exit() was called and + // that the entire process should exit. + // This function is always called form a pthread, but is executaed on the + // main thread due the __proxy attribute. $exitOnMainThread__deps: ['exit', #if !MINIMAL_RUNTIME '$handleException', @@ -1266,7 +1270,6 @@ var LibraryPThread = { ], $exitOnMainThread__proxy: 'async', $exitOnMainThread: function(returnCode) { - // A pthread has requested to exit the whole application process (runtime). #if PTHREADS_DEBUG err('exitOnMainThread'); #endif diff --git a/tests/pthread/test_pthread_c11_threads.c b/tests/pthread/test_pthread_c11_threads.c index d4d112a0ff3f3..fc2fde1cafa01 100644 --- a/tests/pthread/test_pthread_c11_threads.c +++ b/tests/pthread/test_pthread_c11_threads.c @@ -18,14 +18,13 @@ void do_once(void) { } int thread_main(void* arg) { - printf("in thread_main %p\n", thrd_current()); - tss_set(key, thrd_current()); + printf("in thread_main %p\n", (void*)thrd_current()); + tss_set(key, (void*)thrd_current()); call_once(&flag, do_once); mtx_lock(&mutex); thread_counter--; cnd_signal(&cond); mtx_unlock(&mutex); - printf("done thread_main\n"); return 42; } @@ -35,14 +34,14 @@ int run_with_exit(void* arg) { } void destructor(void* val) { - printf("destructor: %p\n", thrd_current()); - assert(val == thrd_current()); + printf("destructor: %p\n", (void*)thrd_current()); + assert(val == (void*)thrd_current()); destructor_counter++; } int main(int argc, char* argv[]) { int result = 0; - printf("thrd_current: %p\n", thrd_current()); + printf("thrd_current: %p\n", (void*)thrd_current()); assert(tss_create(&key, destructor) == thrd_success); @@ -89,8 +88,19 @@ int main(int argc, char* argv[]) { // Test thrd_detach thrd_t t6; assert(thrd_create(&t6, thread_main, NULL) == thrd_success); + thread_counter++; assert(thrd_detach(t6) == thrd_success); + // Wait for the thread to at least be done printing before exiting + // the process. + // We shouldn't need to do this but there is a bug in emscripten + // where a deadlock can occur between main thread calling fflush() + // during exitRuntime and the detached thread calling print (and + // therefore holding the stdout lock). + // See https://github.com/emscripten-core/emscripten/issues/14579. + while (thread_counter) + assert(cnd_wait(&cond, &mutex) == thrd_success); + printf("done!\n"); return 0; } From 6674c135dc4ae67be2c966921fec78bcb5da54a8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 29 Sep 2021 15:55:17 -0700 Subject: [PATCH 2/2] Update src/library_pthread.js Co-authored-by: Alon Zakai --- src/library_pthread.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_pthread.js b/src/library_pthread.js index 593c620d39b67..5d76dd806cd5d 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -1261,7 +1261,7 @@ var LibraryPThread = { // This function is call by a pthread to signal that exit() was called and // that the entire process should exit. - // This function is always called form a pthread, but is executaed on the + // This function is always called from a pthread, but is executed on the // main thread due the __proxy attribute. $exitOnMainThread__deps: ['exit', #if !MINIMAL_RUNTIME