Skip to content

Commit 3dbfca3

Browse files
authored
Move emscripten_futex_wake to native code. NFC (#15766)
This is great example of why moving stuff into native code can save on overall size: jssize: 49696 -> 48861 = -775 wasm size: 16846 -> 16928 = +82
1 parent 2e35959 commit 3dbfca3

10 files changed

+57
-45
lines changed

src/library_pthread.js

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -951,42 +951,6 @@ var LibraryPThread = {
951951
return 0;
952952
},
953953

954-
// Returns the number of threads (>= 0) woken up, or the value -EINVAL on error.
955-
// Pass count == INT_MAX to wake up all threads.
956-
emscripten_futex_wake: function(addr, count) {
957-
if (addr <= 0 || addr > HEAP8.length || addr&3 != 0 || count < 0) return -{{{ cDefine('EINVAL') }}};
958-
if (count == 0) return 0;
959-
// Waking (at least) INT_MAX waiters is defined to mean wake all callers.
960-
// For Atomics.notify() API Infinity is to be passed in that case.
961-
if (count >= {{{ cDefine('INT_MAX') }}}) count = Infinity;
962-
963-
// See if main thread is waiting on this address? If so, wake it up by resetting its wake location to zero.
964-
// Note that this is not a fair procedure, since we always wake main thread first before any workers, so
965-
// this scheme does not adhere to real queue-based waiting.
966-
var mainThreadWaitAddress = Atomics.load(HEAP32, __emscripten_main_thread_futex >> 2);
967-
var mainThreadWoken = 0;
968-
if (mainThreadWaitAddress == addr) {
969-
#if ASSERTIONS
970-
// We only use __emscripten_main_thread_futex on the main browser thread, where we
971-
// cannot block while we wait. Therefore we should only see it set from
972-
// other threads, and not on the main thread itself. In other words, the
973-
// main thread must never try to wake itself up!
974-
assert(!ENVIRONMENT_IS_WEB);
975-
#endif
976-
var loadedAddr = Atomics.compareExchange(HEAP32, __emscripten_main_thread_futex >> 2, mainThreadWaitAddress, 0);
977-
if (loadedAddr == mainThreadWaitAddress) {
978-
--count;
979-
mainThreadWoken = 1;
980-
if (count <= 0) return 1;
981-
}
982-
}
983-
984-
// Wake any workers waiting on this address.
985-
var ret = Atomics.notify(HEAP32, addr >> 2, count);
986-
if (ret >= 0) return ret + mainThreadWoken;
987-
throw 'Atomics.notify returned an unexpected value ' + ret;
988-
},
989-
990954
__atomic_is_lock_free: function(size, ptr) {
991955
return size <= 4 && (size & (size-1)) == 0 && (ptr&(size-1)) == 0;
992956
},
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2021 The Emscripten Authors. All rights reserved.
3+
* Emscripten is available under two separate licenses, the MIT license and the
4+
* University of Illinois/NCSA Open Source License. Both these licenses can be
5+
* found in the LICENSE file.
6+
*/
7+
8+
#include <assert.h>
9+
#include <errno.h>
10+
#include <limits.h>
11+
#include <atomic.h>
12+
#include <emscripten/threading.h>
13+
14+
int _emscripten_thread_supports_atomics_wait(void);
15+
16+
// Stores the memory address that the main thread is waiting on, if any. If
17+
// the main thread is waiting, we wake it up before waking up any workers.
18+
void* _emscripten_main_thread_futex;
19+
20+
// Returns the number of threads (>= 0) woken up, or the value -EINVAL on error.
21+
// Pass count == INT_MAX to wake up all threads.
22+
int emscripten_futex_wake(volatile void *addr, int count) {
23+
if (!addr || (((intptr_t)addr) & 3) != 0 || count < 0) {
24+
return -EINVAL;
25+
}
26+
if (count == 0) {
27+
return 0;
28+
}
29+
30+
// See if main thread is waiting on this address? If so, wake it up by resetting its wake location to zero.
31+
// Note that this is not a fair procedure, since we always wake main thread first before any workers, so
32+
// this scheme does not adhere to real queue-based waiting.
33+
int main_thread_woken = 0;
34+
if (a_cas_p(&_emscripten_main_thread_futex, (void*)addr, 0) == addr) {
35+
// We only use __emscripten_main_thread_futex on the main browser thread,
36+
// where we cannot block while we wait. Therefore we should only see it set
37+
// from other threads (that should always support waiting), and not on the
38+
// main thread itself. In other words, the main thread must never try to
39+
// wake itself up!
40+
assert(_emscripten_thread_supports_atomics_wait());
41+
--count;
42+
main_thread_woken = 1;
43+
if (count <= 0) {
44+
return 1;
45+
}
46+
}
47+
48+
// Wake any workers waiting on this address.
49+
int ret = __builtin_wasm_memory_atomic_notify((int*)addr, count);
50+
assert(ret >= 0);
51+
return ret + main_thread_woken;
52+
}

system/lib/pthread/library_pthread.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -831,10 +831,6 @@ int emscripten_dispatch_to_thread_async_(pthread_t target_thread,
831831
return ret;
832832
}
833833

834-
// Stores the memory address that the main thread is waiting on, if any. If
835-
// the main thread is waiting, we wake it up before waking up any workers.
836-
EMSCRIPTEN_KEEPALIVE void* _emscripten_main_thread_futex;
837-
838834
void __emscripten_init_main_thread_js(void* tb);
839835

840836
static void *dummy_tsd[1] = { 0 };

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ G
88
H
99
I
1010
J
11-
K
11+
p
1212
q
1313
r
1414
s

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ $emscripten_async_run_in_main_thread
3333
$emscripten_current_thread_process_queued_calls
3434
$emscripten_dispatch_to_thread_
3535
$emscripten_futex_wait
36+
$emscripten_futex_wake
3637
$emscripten_main_thread_process_queued_calls
3738
$emscripten_proxy_main
3839
$emscripten_run_in_main_runtime_thread_js

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,3 @@ a.l
1313
a.m
1414
a.n
1515
a.o
16-
a.p
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
49636
1+
48861

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,3 @@ l
1313
m
1414
n
1515
o
16-
p
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
16846
1+
16911

tools/system_libs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ def get_files(self):
828828
'emscripten_proxy_main.c',
829829
'emscripten_thread_state.S',
830830
'emscripten_futex_wait.c',
831+
'emscripten_futex_wake.c',
831832
])
832833
else:
833834
ignore += ['thread']

0 commit comments

Comments
 (0)