Skip to content

Commit 649c96f

Browse files
committed
Align/unify wait in slices logic. NFC.
1 parent 127cc2c commit 649c96f

File tree

5 files changed

+46
-57
lines changed

5 files changed

+46
-57
lines changed

system/lib/libc/musl/src/internal/pthread_impl.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,11 @@ static inline void __futexwait(volatile void *addr, int val, int priv)
222222
if (is_runtime_thread) {
223223
int e;
224224
do {
225-
// Main runtime thread waits in _very_ small slices so that it stays responsive to assist proxied
226-
// pthread calls.
225+
// Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive.
227226
e = emscripten_futex_wait(addr, val, 1);
228227
// Assist other threads by executing proxied operations that are effectively singlethreaded.
229228
emscripten_main_thread_process_queued_calls();
230-
} while(e == -ETIMEDOUT);
229+
} while (e == -ETIMEDOUT);
231230
} else {
232231
// Can wait in one go.
233232
emscripten_futex_wait(addr, val, INFINITY);

system/lib/libc/musl/src/thread/__timedwait.c

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ int __timedwait_cp(volatile int *addr, int val,
5858
}
5959
#ifdef __EMSCRIPTEN__
6060
pthread_t self = __pthread_self();
61-
double msecsToSleep = top ? (top->tv_sec * 1000 + top->tv_nsec / 1000000.0) : INFINITY;
62-
int is_runtime_thread = emscripten_is_main_runtime_thread();
61+
double msecsToSleep = top ? (top->tv_sec * 1000.0 + top->tv_nsec / 1000000.0) : INFINITY;
62+
const int is_runtime_thread = emscripten_is_main_runtime_thread();
6363

6464
// Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive.
65-
const double maxMsecsSliceToSleep = is_runtime_thread ? 1 : 100;
65+
const double maxMsecsToSleep = is_runtime_thread ? 1 : 100;
6666

6767
// cp suffix in the function name means "cancellation point", so this wait can be cancelled
6868
// by the users unless current threads cancellability is set to PTHREAD_CANCEL_DISABLE
@@ -76,18 +76,13 @@ int __timedwait_cp(volatile int *addr, int val,
7676
// cancel execution.
7777
return ECANCELED;
7878
}
79+
// Must wait in slices in case this thread is cancelled in between.
80+
r = -emscripten_futex_wait((void*)addr, val, msecsToSleep > maxMsecsToSleep ? maxMsecsToSleep : msecsToSleep);
7981
// Assist other threads by executing proxied operations that are effectively singlethreaded.
8082
if (is_runtime_thread) emscripten_main_thread_process_queued_calls();
81-
// Must wait in slices in case this thread is cancelled in between.
82-
double waitMsecs = sleepUntilTime - emscripten_get_now();
83-
if (waitMsecs <= 0) {
84-
r = ETIMEDOUT;
85-
break;
86-
}
87-
if (waitMsecs > maxMsecsSliceToSleep)
88-
waitMsecs = maxMsecsSliceToSleep;
89-
r = -emscripten_futex_wait((void*)addr, val, waitMsecs);
90-
} while(r == ETIMEDOUT);
83+
84+
msecsToSleep = sleepUntilTime - emscripten_get_now();
85+
} while (r == ETIMEDOUT && msecsToSleep > 0);
9186
} else {
9287
// Can wait in one go.
9388
r = -emscripten_futex_wait((void*)addr, val, msecsToSleep);

system/lib/libc/musl/src/thread/__wait.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,24 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
1313
if (waiters) a_inc(waiters);
1414
#ifdef __EMSCRIPTEN__
1515
pthread_t self = __pthread_self();
16-
int is_runtime_thread = emscripten_is_main_runtime_thread();
16+
const int is_runtime_thread = emscripten_is_main_runtime_thread();
1717

1818
// Main runtime thread may need to run proxied calls, so sleep in very small slices to be responsive.
19-
const double maxMsecsSliceToSleep = is_runtime_thread ? 1 : 100;
19+
const double maxMsecsToSleep = is_runtime_thread ? 1 : 100;
2020

2121
while (*addr==val) {
2222
if (is_runtime_thread || self->cancelasync) {
23-
// Must wait in slices in case this thread is cancelled in between.
2423
int e;
2524
do {
2625
if (self->cancel) {
2726
if (waiters) a_dec(waiters);
2827
return;
2928
}
29+
// Must wait in slices in case this thread is cancelled in between.
30+
e = emscripten_futex_wait((void*)addr, val, maxMsecsToSleep);
3031
// Assist other threads by executing proxied operations that are effectively singlethreaded.
3132
if (is_runtime_thread) emscripten_main_thread_process_queued_calls();
32-
e = emscripten_futex_wait((void*)addr, val, maxMsecsSliceToSleep);
33-
} while(e == -ETIMEDOUT);
33+
} while (e == -ETIMEDOUT);
3434
} else {
3535
// Can wait in one go.
3636
emscripten_futex_wait((void*)addr, val, INFINITY);

system/lib/libc/musl/src/thread/pthread_cond_timedwait.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static inline void unlock_requeue(volatile int *l, volatile int *r, int w)
5555
// primitive is strictly not needed, since it is more like an optimization to avoid spuriously waking
5656
// all waiters, just to make them wait on another location immediately afterwards. Here we do exactly
5757
// that: wake every waiter.
58-
emscripten_futex_wake(l, 0x7FFFFFFF);
58+
emscripten_futex_wake(l, INT_MAX);
5959
#else
6060
if (w) __wake(l, 1, 1);
6161
else __syscall(SYS_futex, l, FUTEX_REQUEUE|FUTEX_PRIVATE, 0, 1, r) != -ENOSYS

system/lib/pthread/library_pthread.c

Lines changed: 30 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -69,33 +69,29 @@ void emscripten_thread_sleep(double msecs) {
6969
double now = emscripten_get_now();
7070
double target = now + msecs;
7171

72-
__pthread_testcancel(); // pthreads spec: sleep is a cancellation point, so must test if this
73-
// thread is cancelled during the sleep.
74-
emscripten_current_thread_process_queued_calls();
75-
7672
// If we have less than this many msecs left to wait, busy spin that instead.
77-
const double minimumTimeSliceToSleep = 0.1;
73+
const double minTimeSliceToSleep = 0.1;
7874

79-
// runtime thread may need to run proxied calls, so sleep in very small slices to be responsive.
75+
// Runtime thread may need to run proxied calls, so sleep in very small slices to be responsive.
8076
const double maxMsecsSliceToSleep = emscripten_is_main_runtime_thread() ? 1 : 100;
8177

8278
emscripten_conditional_set_current_thread_status(
8379
EM_THREAD_STATUS_RUNNING, EM_THREAD_STATUS_SLEEPING);
84-
now = emscripten_get_now();
85-
while (now < target) {
80+
81+
double msecsToSleep;
82+
do {
8683
// Keep processing the main loop of the calling thread.
8784
__pthread_testcancel(); // pthreads spec: sleep is a cancellation point, so must test if this
8885
// thread is cancelled during the sleep.
8986
emscripten_current_thread_process_queued_calls();
9087

91-
now = emscripten_get_now();
92-
double msecsToSleep = target - now;
93-
if (msecsToSleep > maxMsecsSliceToSleep)
94-
msecsToSleep = maxMsecsSliceToSleep;
95-
if (msecsToSleep >= minimumTimeSliceToSleep)
96-
emscripten_futex_wait(&dummyZeroAddress, 0, msecsToSleep);
97-
now = emscripten_get_now();
98-
};
88+
msecsToSleep = target - emscripten_get_now();
89+
if (msecsToSleep < minTimeSliceToSleep)
90+
continue;
91+
92+
emscripten_futex_wait(&dummyZeroAddress, 0,
93+
msecsToSleep > maxMsecsSliceToSleep ? maxMsecsSliceToSleep : msecsToSleep);
94+
} while (msecsToSleep > 0);
9995

10096
emscripten_conditional_set_current_thread_status(
10197
EM_THREAD_STATUS_SLEEPING, EM_THREAD_STATUS_RUNNING);
@@ -369,25 +365,24 @@ static CallQueue* GetOrAllocateQueue(void* target) {
369365
return q;
370366
}
371367

368+
// TODO(kleisauke): All paths call this with timeoutMSecs == INFINITY, perhaps drop this param?
372369
EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call* call, double timeoutMSecs) {
373-
int r;
374-
375370
int done = atomic_load(&call->operationDone);
376-
if (!done) {
377-
double now = emscripten_get_now();
378-
double waitEndTime = now + timeoutMSecs;
379-
emscripten_set_current_thread_status(EM_THREAD_STATUS_WAITPROXY);
380-
while (!done && now < waitEndTime) {
381-
r = emscripten_futex_wait(&call->operationDone, 0, waitEndTime - now);
382-
done = atomic_load(&call->operationDone);
383-
now = emscripten_get_now();
384-
}
385-
emscripten_set_current_thread_status(EM_THREAD_STATUS_RUNNING);
386-
}
387-
if (done)
388-
return EMSCRIPTEN_RESULT_SUCCESS;
389-
else
390-
return EMSCRIPTEN_RESULT_TIMED_OUT;
371+
if (done) return EMSCRIPTEN_RESULT_SUCCESS;
372+
373+
emscripten_set_current_thread_status(EM_THREAD_STATUS_WAITPROXY);
374+
375+
double timeoutUntilTime = emscripten_get_now() + timeoutMSecs;
376+
do {
377+
emscripten_futex_wait(&call->operationDone, 0, timeoutMSecs);
378+
done = atomic_load(&call->operationDone);
379+
380+
timeoutMSecs = timeoutUntilTime - emscripten_get_now();
381+
} while (!done && timeoutMSecs > 0);
382+
383+
emscripten_set_current_thread_status(EM_THREAD_STATUS_RUNNING);
384+
385+
return done ? EMSCRIPTEN_RESULT_SUCCESS : EMSCRIPTEN_RESULT_TIMED_OUT;
391386
}
392387

393388
EMSCRIPTEN_RESULT emscripten_wait_for_call_i(
@@ -444,7 +439,7 @@ int _emscripten_do_dispatch_to_thread(pthread_t target_thread, em_queued_call* c
444439
// If queue of the main browser thread is full, then we wait. (never drop messages for the main
445440
// browser thread)
446441
if (target_thread == emscripten_main_browser_thread_id()) {
447-
emscripten_futex_wait((void*)&q->call_queue_head, head, INFINITY);
442+
emscripten_futex_wait((void *)&q->call_queue_head, head, INFINITY);
448443
pthread_mutex_lock(&call_queue_lock);
449444
head = q->call_queue_head;
450445
tail = q->call_queue_tail;
@@ -624,7 +619,7 @@ void emscripten_current_thread_process_queued_calls() {
624619
pthread_mutex_unlock(&call_queue_lock);
625620

626621
// If the queue was full and we had waiters pending to get to put data to queue, wake them up.
627-
emscripten_futex_wake((void*)&q->call_queue_head, 0x7FFFFFFF);
622+
emscripten_futex_wake((void *)&q->call_queue_head, INT_MAX);
628623

629624
thread_is_processing_queued_calls = false;
630625
}

0 commit comments

Comments
 (0)