Skip to content

Commit 03ba3a3

Browse files
committed
Replace call_once usage in libc++ with atomics
This avoid a dependency on pthread API (which are used to implement call_once under the hood) which makes libc++ much more usable from Wasm Workers (there pthreads are not available). The downside here is that when thread race to be first one to use a given facet we would "leak" an ID which could cause the `facets_` vector to become more spare that it otherwise would be. IIUC this `facets_` vector can already be sparse so it not clear to me what impact this would have in practice. We could make this change only for the Wasm Workers build of libc++ but I'd like to get as much test coverage of it as I can. See: #26375
1 parent 3051725 commit 03ba3a3

File tree

4 files changed

+22
-1
lines changed

4 files changed

+22
-1
lines changed

system/lib/libcxx/include/__locale

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ private:
146146
};
147147

148148
class _LIBCPP_EXPORTED_FROM_ABI locale::id {
149+
#if !defined(__EMSCRIPTEN__) || !defined(__EMSCRIPTEN_WASM_WORKERS__)
149150
once_flag __flag_;
151+
#endif
150152
int32_t __id_;
151153

152154
static int32_t __next_id;

system/lib/libcxx/src/locale.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,24 @@ void locale::facet::__on_zero_shared() noexcept { delete this; }
589589
constinit int32_t locale::id::__next_id = 0;
590590

591591
long locale::id::__get() {
592+
#if defined(__EMSCRIPTEN__) && defined(__EMSCRIPTEN_WASM_WORKERS__)
593+
// Avoid `call_once` under Emscripten since we want to avoid the pthread
594+
// dependenency that it comes with.
595+
// TODO(https://github.com/emscripten-core/emscripten/issues/26426):
596+
// Remove this patch once we have some kind of locking primitive
597+
// in Wasm Worker that can be used to implement call_once (or
598+
// __libcpp_mutex_t/__libcpp_condvar_t).
599+
if (__libcpp_atomic_load(&__id_) == 0) {
600+
int32_t proposed_id = __libcpp_atomic_add(&__next_id, 1);
601+
int32_t expected = 0;
602+
// If we race with another thread here the CAS will fail and
603+
// the proposed_id will be leaked, but __id_ will be non-zero
604+
// in either case.
605+
__libcpp_atomic_compare_exchange(&__id_, &expected, proposed_id);
606+
}
607+
#else
592608
call_once(__flag_, [&] { __id_ = __libcpp_atomic_add(&__next_id, 1); });
609+
#endif
593610
return __id_ - 1;
594611
}
595612

test/codesize/hello_libcxx.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,3 @@ int main() {
99
std::cout << "hello, world!" << std::endl;
1010
return 0;
1111
}
12-

test/test_other.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13537,6 +13537,9 @@ def test_wasm_worker_pthread_api_usage(self):
1353713537
def test_wasm_worker_cxx_init(self):
1353813538
self.do_run_in_out_file_test('wasm_worker/wasm_worker_cxx_init.cpp', cflags=['-sWASM_WORKERS'])
1353913539

13540+
def test_wasm_worker_hello_libcxx(self):
13541+
self.do_runf('codesize/hello_libcxx.cpp', 'hello, world!\n', cflags=['-sWASM_WORKERS'])
13542+
1354013543
@parameterized({
1354113544
# we will warn here since -O2 runs the optimizer and -g enables DWARF
1354213545
'O2_g': (True, ['-O2', '-g']),

0 commit comments

Comments
 (0)