diff --git a/src/library_pthread.js b/src/library_pthread.js index 6e360a2fb64df..45d26a71eac8b 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -951,42 +951,6 @@ var LibraryPThread = { return 0; }, - // Returns the number of threads (>= 0) woken up, or the value -EINVAL on error. - // Pass count == INT_MAX to wake up all threads. - emscripten_futex_wake: function(addr, count) { - if (addr <= 0 || addr > HEAP8.length || addr&3 != 0 || count < 0) return -{{{ cDefine('EINVAL') }}}; - if (count == 0) return 0; - // Waking (at least) INT_MAX waiters is defined to mean wake all callers. - // For Atomics.notify() API Infinity is to be passed in that case. - if (count >= {{{ cDefine('INT_MAX') }}}) count = Infinity; - - // See if main thread is waiting on this address? If so, wake it up by resetting its wake location to zero. - // Note that this is not a fair procedure, since we always wake main thread first before any workers, so - // this scheme does not adhere to real queue-based waiting. - var mainThreadWaitAddress = Atomics.load(HEAP32, __emscripten_main_thread_futex >> 2); - var mainThreadWoken = 0; - if (mainThreadWaitAddress == addr) { -#if ASSERTIONS - // We only use __emscripten_main_thread_futex on the main browser thread, where we - // cannot block while we wait. Therefore we should only see it set from - // other threads, and not on the main thread itself. In other words, the - // main thread must never try to wake itself up! - assert(!ENVIRONMENT_IS_WEB); -#endif - var loadedAddr = Atomics.compareExchange(HEAP32, __emscripten_main_thread_futex >> 2, mainThreadWaitAddress, 0); - if (loadedAddr == mainThreadWaitAddress) { - --count; - mainThreadWoken = 1; - if (count <= 0) return 1; - } - } - - // Wake any workers waiting on this address. - var ret = Atomics.notify(HEAP32, addr >> 2, count); - if (ret >= 0) return ret + mainThreadWoken; - throw 'Atomics.notify returned an unexpected value ' + ret; - }, - __atomic_is_lock_free: function(size, ptr) { return size <= 4 && (size & (size-1)) == 0 && (ptr&(size-1)) == 0; }, diff --git a/system/lib/pthread/emscripten_futex_wake.c b/system/lib/pthread/emscripten_futex_wake.c new file mode 100644 index 0000000000000..82aa10a0653fa --- /dev/null +++ b/system/lib/pthread/emscripten_futex_wake.c @@ -0,0 +1,52 @@ +/* + * Copyright 2021 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include + +int _emscripten_thread_supports_atomics_wait(void); + +// Stores the memory address that the main thread is waiting on, if any. If +// the main thread is waiting, we wake it up before waking up any workers. +void* _emscripten_main_thread_futex; + +// Returns the number of threads (>= 0) woken up, or the value -EINVAL on error. +// Pass count == INT_MAX to wake up all threads. +int emscripten_futex_wake(volatile void *addr, int count) { + if (!addr || (((intptr_t)addr) & 3) != 0 || count < 0) { + return -EINVAL; + } + if (count == 0) { + return 0; + } + + // See if main thread is waiting on this address? If so, wake it up by resetting its wake location to zero. + // Note that this is not a fair procedure, since we always wake main thread first before any workers, so + // this scheme does not adhere to real queue-based waiting. + int main_thread_woken = 0; + if (a_cas_p(&_emscripten_main_thread_futex, (void*)addr, 0) == addr) { + // We only use __emscripten_main_thread_futex on the main browser thread, + // where we cannot block while we wait. Therefore we should only see it set + // from other threads (that should always support waiting), and not on the + // main thread itself. In other words, the main thread must never try to + // wake itself up! + assert(_emscripten_thread_supports_atomics_wait()); + --count; + main_thread_woken = 1; + if (count <= 0) { + return 1; + } + } + + // Wake any workers waiting on this address. + int ret = __builtin_wasm_memory_atomic_notify((int*)addr, count); + assert(ret >= 0); + return ret + main_thread_woken; +} diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 3d5051f04d41d..612e697d7690f 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -831,10 +831,6 @@ int emscripten_dispatch_to_thread_async_(pthread_t target_thread, return ret; } -// Stores the memory address that the main thread is waiting on, if any. If -// the main thread is waiting, we wake it up before waking up any workers. -EMSCRIPTEN_KEEPALIVE void* _emscripten_main_thread_futex; - void __emscripten_init_main_thread_js(void* tb); static void *dummy_tsd[1] = { 0 }; diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports index ec14750b14e10..2f772401a8105 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports @@ -8,7 +8,7 @@ G H I J -K +p q r s diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs index 0bf6b1a35efed..3e11b4dc44aa5 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs @@ -33,6 +33,7 @@ $emscripten_async_run_in_main_thread $emscripten_current_thread_process_queued_calls $emscripten_dispatch_to_thread_ $emscripten_futex_wait +$emscripten_futex_wake $emscripten_main_thread_process_queued_calls $emscripten_proxy_main $emscripten_run_in_main_runtime_thread_js diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports index 259d8061349ff..fcc5923256f40 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports @@ -13,4 +13,3 @@ a.l a.m a.n a.o -a.p diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.jssize b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.jssize index 0c6ec3070618c..df1eaef8152a5 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.jssize +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.jssize @@ -1 +1 @@ -49636 +48861 diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent index b03757ea914f6..f8c295c135e5d 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent @@ -13,4 +13,3 @@ l m n o -p diff --git a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.size b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.size index cf57ed0da71b9..e3a0ea2be52db 100644 --- a/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.size +++ b/tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.size @@ -1 +1 @@ -16846 +16911 diff --git a/tools/system_libs.py b/tools/system_libs.py index e947b76be68e5..83bd39a86622a 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -828,6 +828,7 @@ def get_files(self): 'emscripten_proxy_main.c', 'emscripten_thread_state.S', 'emscripten_futex_wait.c', + 'emscripten_futex_wake.c', ]) else: ignore += ['thread']