From 8c98aefb496d3728b1d480fec14c3369aea73c00 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 25 Mar 2026 16:23:40 -0700 Subject: [PATCH] Remove timeout slicing from __timedwait. NFC This removes the timeout slicing from `__timedwait` and instead relies on the existing slicing in `emscripten_futex_wait.c`. This is a followup to #26511 and #26471 (which did the same for the slicing in `__wait`). --- system/lib/libc/musl/src/thread/__timedwait.c | 37 +------------------ system/lib/pthread/emscripten_futex_wait.c | 9 ++++- .../test_codesize_minimal_pthreads.json | 16 ++++---- ...t_codesize_minimal_pthreads_memgrowth.json | 16 ++++---- 4 files changed, 25 insertions(+), 53 deletions(-) diff --git a/system/lib/libc/musl/src/thread/__timedwait.c b/system/lib/libc/musl/src/thread/__timedwait.c index 6da7dad3faaa4..9e3ccc9849257 100644 --- a/system/lib/libc/musl/src/thread/__timedwait.c +++ b/system/lib/libc/musl/src/thread/__timedwait.c @@ -58,41 +58,8 @@ int __timedwait_cp(volatile int *addr, int val, } #ifdef __EMSCRIPTEN__ - double msecsToSleep = top ? (top->tv_sec * 1000 + top->tv_nsec / 1000000.0) : INFINITY; - - // cp suffix in the function name means "cancellation point", so this wait can be cancelled - // by the user, unless current thread has cancelation disabled (which may be either done - // directly, or indirectly, for example in the __timedwait() function). - pthread_t self = pthread_self(); - - if (self->canceldisable != PTHREAD_CANCEL_DISABLE) { - double max_ms_slice_to_sleep = 100; - double sleepUntilTime = emscripten_get_now() + msecsToSleep; - do { - if (self->cancel) { - // The thread was canceled by pthread_cancel(). - // In the case of cancelasync or PTHREAD_CANCEL_ENABLE we can just call - // __pthread_testcancel(), which won't return at all. - __pthread_testcancel(); - // If __pthread_testcancel does return here it means that canceldisable - // must be set to PTHREAD_CANCEL_MASKED. In this case we emulate the - // behaviour of the futex syscall and return ECANCELLED here. - // See pthread_cond_timedwait.c for the only use of this flag. - return ECANCELED; - } - msecsToSleep = sleepUntilTime - emscripten_get_now(); - if (msecsToSleep <= 0) { - return ETIMEDOUT; - } - // Must wait in slices in case this thread is cancelled in between. - if (msecsToSleep > max_ms_slice_to_sleep) - msecsToSleep = max_ms_slice_to_sleep; - r = -emscripten_futex_wait((void*)addr, val, msecsToSleep); - } while (r == ETIMEDOUT); - } else { - // Can wait in one go. - r = -emscripten_futex_wait((void*)addr, val, msecsToSleep); - } + double msecs_to_sleep = top ? (top->tv_sec * 1000 + top->tv_nsec / 1000000.0) : INFINITY; + r = -emscripten_futex_wait((void*)addr, val, msecs_to_sleep); #else r = -__futex4_cp(addr, FUTEX_WAIT|priv, val, top); #endif diff --git a/system/lib/pthread/emscripten_futex_wait.c b/system/lib/pthread/emscripten_futex_wait.c index b74fd459634fb..3040610047ffb 100644 --- a/system/lib/pthread/emscripten_futex_wait.c +++ b/system/lib/pthread/emscripten_futex_wait.c @@ -132,7 +132,7 @@ int emscripten_futex_wait(volatile void *addr, uint32_t val, double max_wait_ms) #ifdef __EMSCRIPTEN_PTHREADS__ pthread_t self = pthread_self(); - bool cancelable = !self->canceldisable && self->cancelasync; + bool cancelable = self->canceldisable != PTHREAD_CANCEL_DISABLE; #else bool cancelable = false; #endif @@ -215,7 +215,12 @@ int emscripten_futex_wait(volatile void *addr, uint32_t val, double max_wait_ms) #ifdef __EMSCRIPTEN_PTHREADS__ if (cancelable && ret == ATOMICS_WAIT_TIMED_OUT && self->cancel) { __pthread_testcancel(); - break; + // If __pthread_testcancel does return here it means that canceldisable + // must be set to PTHREAD_CANCEL_MASKED. In this case we emulate the + // behaviour of the futex syscall and return ECANCELLED here. + // See pthread_cond_timedwait.c for the only use of this flag. + emscripten_conditional_set_current_thread_status(EM_THREAD_STATUS_WAITFUTEX, EM_THREAD_STATUS_RUNNING); + return -ECANCELED; } // If remainder_ns is negative it means we want wait forever, and we don't // need to decrement remainder_ns in that case. diff --git a/test/codesize/test_codesize_minimal_pthreads.json b/test/codesize/test_codesize_minimal_pthreads.json index d78c1fce61512..75383a2ac05a7 100644 --- a/test/codesize/test_codesize_minimal_pthreads.json +++ b/test/codesize/test_codesize_minimal_pthreads.json @@ -1,14 +1,14 @@ { "a.out.js": 7363, "a.out.js.gz": 3604, - "a.out.nodebug.wasm": 19244, - "a.out.nodebug.wasm.gz": 8919, - "total": 26607, - "total_gz": 12523, + "a.out.nodebug.wasm": 19046, + "a.out.nodebug.wasm.gz": 8822, + "total": 26409, + "total_gz": 12426, "sent": [ "a (memory)", - "b (emscripten_get_now)", - "c (exit)", + "b (exit)", + "c (emscripten_get_now)", "d (_emscripten_thread_set_strongref)", "e (_emscripten_receive_on_main_thread_js)", "f (emscripten_runtime_keepalive_check)", @@ -23,8 +23,8 @@ ], "imports": [ "a (memory)", - "b (emscripten_get_now)", - "c (exit)", + "b (exit)", + "c (emscripten_get_now)", "d (_emscripten_thread_set_strongref)", "e (_emscripten_receive_on_main_thread_js)", "f (emscripten_runtime_keepalive_check)", diff --git a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json index 65f9b3f7a2d7b..4d941efd39106 100644 --- a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json +++ b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json @@ -1,14 +1,14 @@ { "a.out.js": 7765, "a.out.js.gz": 3810, - "a.out.nodebug.wasm": 19245, - "a.out.nodebug.wasm.gz": 8920, - "total": 27010, - "total_gz": 12730, + "a.out.nodebug.wasm": 19047, + "a.out.nodebug.wasm.gz": 8823, + "total": 26812, + "total_gz": 12633, "sent": [ "a (memory)", - "b (emscripten_get_now)", - "c (exit)", + "b (exit)", + "c (emscripten_get_now)", "d (_emscripten_thread_set_strongref)", "e (_emscripten_receive_on_main_thread_js)", "f (emscripten_runtime_keepalive_check)", @@ -23,8 +23,8 @@ ], "imports": [ "a (memory)", - "b (emscripten_get_now)", - "c (exit)", + "b (exit)", + "c (emscripten_get_now)", "d (_emscripten_thread_set_strongref)", "e (_emscripten_receive_on_main_thread_js)", "f (emscripten_runtime_keepalive_check)",