diff --git a/system/lib/libc/musl/src/thread/__timedwait.c b/system/lib/libc/musl/src/thread/__timedwait.c index bdf18716e0ce3..c143ac8887c7e 100644 --- a/system/lib/libc/musl/src/thread/__timedwait.c +++ b/system/lib/libc/musl/src/thread/__timedwait.c @@ -5,7 +5,6 @@ #include #include #include -#include "pthread_impl.h" #else #include "futex.h" #endif @@ -61,6 +60,10 @@ int __timedwait_cp(volatile int *addr, int val, #ifdef __EMSCRIPTEN__ double msecsToSleep = top ? (top->tv_sec * 1000 + top->tv_nsec / 1000000.0) : INFINITY; int is_runtime_thread = emscripten_is_main_runtime_thread(); + + // Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive. + double max_ms_slice_to_sleep = is_runtime_thread ? 1 : 100; + // cp suffix in the function name means "cancellation point", so this wait can be cancelled // by the users unless current threads cancelability is set to PTHREAD_CANCEL_DISABLE // which may be either done by the user of __timedwait() function. @@ -77,16 +80,17 @@ int __timedwait_cp(volatile int *addr, int val, } // Assist other threads by executing proxied operations that are effectively singlethreaded. if (is_runtime_thread) emscripten_main_thread_process_queued_calls(); - // Must wait in slices in case this thread is cancelled in between. - double waitMsecs = sleepUntilTime - emscripten_get_now(); - if (waitMsecs <= 0) { + + msecsToSleep = sleepUntilTime - emscripten_get_now(); + if (msecsToSleep <= 0) { r = ETIMEDOUT; break; } - if (waitMsecs > 100) waitMsecs = 100; // non-main threads can sleep in longer slices. - if (is_runtime_thread && waitMsecs > 1) waitMsecs = 1; // the runtime thread may need to run proxied calls, so sleep in very small slices to be responsive. - r = -emscripten_futex_wait((void*)addr, val, waitMsecs); - } while(r == 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); diff --git a/system/lib/libc/musl/src/thread/__wait.c b/system/lib/libc/musl/src/thread/__wait.c index 712f6b9a49e8f..2966ee221254f 100644 --- a/system/lib/libc/musl/src/thread/__wait.c +++ b/system/lib/libc/musl/src/thread/__wait.c @@ -16,9 +16,12 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv) if (waiters) a_inc(waiters); #ifdef __EMSCRIPTEN__ int is_runtime_thread = emscripten_is_main_runtime_thread(); + + // Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive. + double max_ms_slice_to_sleep = is_runtime_thread ? 1 : 100; + while (*addr==val) { if (is_runtime_thread || pthread_self()->cancelasync == PTHREAD_CANCEL_ASYNCHRONOUS) { - // Must wait in slices in case this thread is cancelled in between. int e; do { if (pthread_self()->cancel) { @@ -27,10 +30,9 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv) } // Assist other threads by executing proxied operations that are effectively singlethreaded. if (is_runtime_thread) emscripten_main_thread_process_queued_calls(); - // Main thread waits in _very_ small slices so that it stays responsive to assist proxied - // pthread calls. - e = emscripten_futex_wait((void*)addr, val, is_runtime_thread ? 1 : 100); - } while(e == -ETIMEDOUT); + // Must wait in slices in case this thread is cancelled in between. + e = emscripten_futex_wait((void*)addr, val, max_ms_slice_to_sleep); + } while (e == -ETIMEDOUT); } else { // Can wait in one go. emscripten_futex_wait((void*)addr, val, INFINITY); diff --git a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c index af2dde2eb247d..4ba11d579bd9a 100644 --- a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c +++ b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c @@ -93,12 +93,11 @@ int pthread_barrier_wait(pthread_barrier_t *b) if (is_runtime_thread) { int e; do { - // Main thread waits in _very_ small slices so that it stays responsive to assist proxied - // pthread calls. + // Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive. e = emscripten_futex_wait(&inst->finished, 1, 1); // Assist other threads by executing proxied operations that are effectively singlethreaded. emscripten_main_thread_process_queued_calls(); - } while(e == -ETIMEDOUT); + } while (e == -ETIMEDOUT); } else { // Can wait in one go. emscripten_futex_wait(&inst->finished, 1, INFINITY); diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 80e3fa193c249..3da6d4290896b 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -87,10 +87,6 @@ void emscripten_thread_sleep(double msecs) { double now = emscripten_get_now(); double target = now + msecs; - __pthread_testcancel(); // pthreads spec: sleep is a cancellation point, so must test if this - // thread is cancelled during the sleep. - emscripten_current_thread_process_queued_calls(); - // If we have less than this many msecs left to wait, busy spin that instead. double min_ms_slice_to_sleep = 0.1; @@ -99,8 +95,8 @@ void emscripten_thread_sleep(double msecs) { emscripten_conditional_set_current_thread_status( EM_THREAD_STATUS_RUNNING, EM_THREAD_STATUS_SLEEPING); - now = emscripten_get_now(); - while (now < target) { + + do { // Keep processing the main loop of the calling thread. __pthread_testcancel(); // pthreads spec: sleep is a cancellation point, so must test if this // thread is cancelled during the sleep. @@ -108,14 +104,13 @@ void emscripten_thread_sleep(double msecs) { now = emscripten_get_now(); double ms_to_sleep = target - now; - if (ms_to_sleep > max_ms_slice_to_sleep) { + if (ms_to_sleep < min_ms_slice_to_sleep) + continue; + if (ms_to_sleep > max_ms_slice_to_sleep) ms_to_sleep = max_ms_slice_to_sleep; - } - if (ms_to_sleep >= min_ms_slice_to_sleep) { - emscripten_futex_wait(&dummyZeroAddress, 0, ms_to_sleep); - } + emscripten_futex_wait(&dummyZeroAddress, 0, ms_to_sleep); now = emscripten_get_now(); - }; + } while (now < target); emscripten_conditional_set_current_thread_status( EM_THREAD_STATUS_SLEEPING, EM_THREAD_STATUS_RUNNING);