From 3e10aa566b8fe35e4a20a647b926b9ec80f64631 Mon Sep 17 00:00:00 2001 From: Clement Peron Date: Sat, 31 Oct 2026 08:08:19 +0000 Subject: [PATCH] Fix flakiness in test_pthread_dylink_tls_free test_pthread_dylink_tls_free, added in #28051, is flaky on the emscripten-releases bot (test_core.cores). The test compares mallinfo() before and after 100 pthread_create / pthread_join cycles and allows 200 KiB of growth. Under PROXY_TO_PTHREAD, main() runs on a pthread, and there pthread_join() doesn't free the joined thread's own block (64 KiB stack + guard + TLS + pthread struct, about 73 KiB): _emscripten_thread_cleanup() posts CMD_CLEANUP_THREAD to the main thread, which frees it later. The next pthread_create() reaches the main thread through its mailbox rather than through that message queue, so the main thread can fall several joins behind. Three not-yet-freed blocks are enough to exceed the allowance. Drop PROXY_TO_PTHREAD for this test. On the main runtime thread, _emscripten_thread_cleanup() calls cleanupThread() directly, so the joined thread's block is freed before pthread_join() returns and the measurement no longer depends on timing. The side-module TLS leak fixed in #28051 is still caught. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EuYUd1U1jgeJHaduQBgcKA --- test/core/pthread/test_pthread_dylink_tls_free.c | 8 +++++--- test/test_core.py | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/core/pthread/test_pthread_dylink_tls_free.c b/test/core/pthread/test_pthread_dylink_tls_free.c index ed2b07f2e6428..9775fc77eac95 100644 --- a/test/core/pthread/test_pthread_dylink_tls_free.c +++ b/test/core/pthread/test_pthread_dylink_tls_free.c @@ -33,9 +33,11 @@ int main() { // Each thread allocates the side module's 4 KiB TLS block on first access and // must free it when it exits. Without the fix the heap grows by one block - // per thread; with it, growth is bounded by the last thread's not-yet- - // reclaimed stack, far below NUM_THREADS blocks. NUM_THREADS is large so a - // real leak clearly exceeds that fixed slack. + // per thread. This runs on the main runtime thread (no PROXY_TO_PTHREAD) so + // that pthread_join() frees the joined thread's own block (stack, TLS, + // pthread struct) synchronously. From a pthread that free happens later on + // the main thread, which can fall several joins behind and make the + // measurement depend on timing. run_threads(10); size_t before = mallinfo().uordblks; run_threads(NUM_THREADS); diff --git a/test/test_core.py b/test/test_core.py index 56d19f889158f..b4810f185a707 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9449,7 +9449,6 @@ def test_pthread_dylink_tls_free(self): self.prep_dlfcn_main() self.set_setting('EXIT_RUNTIME') - self.set_setting('PROXY_TO_PTHREAD') self.do_runf('core/pthread/test_pthread_dylink_tls_free.c', 'done\n') @needs_dylink