From c4bc21aabe1e035cc654b5d0c7e3c9ca926d63c1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 16 Sep 2020 17:16:56 -0700 Subject: [PATCH 1/2] fix --- system/include/emscripten/threading.h | 3 +++ system/lib/pthread/library_pthread.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/system/include/emscripten/threading.h b/system/include/emscripten/threading.h index aaf02b0b2bb23..9e605da5f3894 100644 --- a/system/include/emscripten/threading.h +++ b/system/include/emscripten/threading.h @@ -152,6 +152,9 @@ typedef struct em_queued_call // after it has been executed. If false, the caller is in control of the // memory. int calleeDelete; + + // The thread on which to perform the call. + void* targetThread; } em_queued_call; void emscripten_sync_run_in_main_thread(em_queued_call *call); diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 6af1da45d6379..ec0f11a757626 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -174,6 +174,7 @@ static em_queued_call* em_queued_call_malloc() { call->operationDone = 0; call->functionPtr = 0; call->satelliteData = 0; + call->targetThread = 0; } return call; } @@ -420,6 +421,9 @@ EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call* call, double timeou while (!done && now < waitEndTime) { r = emscripten_futex_wait(&call->operationDone, 0, waitEndTime - now); done = emscripten_atomic_load_u32(&call->operationDone); + if (!done) { + _emscripten_notify_thread_queue(call->targetThread, emscripten_main_browser_thread_id()); + } now = emscripten_get_now(); } emscripten_set_current_thread_status(EM_THREAD_STATUS_RUNNING); @@ -754,6 +758,7 @@ EMSCRIPTEN_KEEPALIVE double emscripten_run_in_main_runtime_thread_js(int index, c->calleeDelete = 1-sync; c->functionEnum = EM_PROXIED_JS_FUNCTION; c->functionPtr = (void*)index; + c->targetThread = emscripten_main_browser_thread_id(); // We write out the JS doubles into args[], which must be of appropriate size - JS will assume that. assert(sizeof(em_variant_val) == sizeof(double)); assert(num_args+1 <= EM_QUEUED_JS_CALL_MAX_ARGS); @@ -781,6 +786,7 @@ void emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* f return; q->functionEnum = sig; q->functionPtr = func_ptr; + q->targetThread = emscripten_main_browser_thread_id(); EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK; va_list args; @@ -818,6 +824,7 @@ em_queued_call* emscripten_async_waitable_run_in_main_runtime_thread_( return NULL; q->functionEnum = sig; q->functionPtr = func_ptr; + q->targetThread = emscripten_main_browser_thread_id(); EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK; va_list args; @@ -864,6 +871,7 @@ int EMSCRIPTEN_KEEPALIVE _emscripten_call_on_thread( q->functionEnum = sig; q->functionPtr = func_ptr; q->satelliteData = satellite; + q->targetThread = targetThread; EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK; va_list args; From 62fbac8d89a8ca28ca61272605ba9d63b7dd16f3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 16 Sep 2020 17:23:04 -0700 Subject: [PATCH 2/2] fix --- system/lib/pthread/library_pthread.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index ec0f11a757626..e3c1a8de6bd15 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -412,7 +412,7 @@ static CallQueue* GetOrAllocateQueue( EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call* call, double timeoutMSecs) { int r; - + int notifiedThread = 0; int done = emscripten_atomic_load_u32(&call->operationDone); if (!done) { double now = emscripten_get_now(); @@ -421,8 +421,15 @@ EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call* call, double timeou while (!done && now < waitEndTime) { r = emscripten_futex_wait(&call->operationDone, 0, waitEndTime - now); done = emscripten_atomic_load_u32(&call->operationDone); - if (!done) { + if (!done && !notifiedThread) { + // If we are not done even after the wait, notify the target thread, + // which in a race condition may have finished handling its event queue + // just after we added our event. (We could also notify it once right + // after adding the event to the queue, but that could lead to a lot of + // unnecessary postMessages, so just do it when we are sure it needs to + // be woken up. _emscripten_notify_thread_queue(call->targetThread, emscripten_main_browser_thread_id()); + notifiedThread = 1; } now = emscripten_get_now(); }