Skip to content

Commit f6fa2ec

Browse files
authored
Initialize all embind bindings on all threads (#17499)
This change replaces `__embind_register_native_and_builtin_types` with `_embind_register_bindings` which calls all `EMSCRIPTEN_BINDINGS` functions. Fixes: #17372
1 parent 766763e commit f6fa2ec

File tree

5 files changed

+59
-27
lines changed

5 files changed

+59
-27
lines changed

src/worker.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,12 @@ self.onmessage = (e) => {
213213

214214
if (!initializedJS) {
215215
#if EMBIND
216+
#if ASSERTIONS
217+
err('Pthread 0x' + Module['_pthread_self']().toString(16) + ' initializing embind.');
218+
#endif
216219
// Embind must initialize itself on all threads, as it generates support JS.
217220
// We only do this once per worker since they get reused
218-
Module['___embind_register_native_and_builtin_types']();
221+
Module['__embind_initialize_bindings']();
219222
#endif // EMBIND
220223

221224
// Execute any proxied work that came in before the thread was

system/include/emscripten/bind.h

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,23 @@ void _embind_register_constant(
246246
TYPEID constantType,
247247
double value);
248248

249+
// Register an InitFunc in the global linked list of init functions.
250+
void _embind_register_bindings(struct InitFunc* f);
251+
252+
// Binding initialization functions registerd by EMSCRIPTEN_BINDINGS macro
253+
// below. Stored as linked list of static data object avoiding std containers
254+
// to avoid static contructor ordering issues.
255+
struct InitFunc {
256+
InitFunc(void (*init_func)()) : init_func(init_func) {
257+
// This the function immediately upon constructions, and also register
258+
// it so that it can be called again on each worker that starts.
259+
init_func();
260+
_embind_register_bindings(this);
261+
}
262+
void (*init_func)();
263+
InitFunc* next = nullptr;
264+
};
265+
249266
} // end extern "C"
250267

251268
} // end namespace internal
@@ -1920,15 +1937,15 @@ class enum_ {
19201937
////////////////////////////////////////////////////////////////////////////////
19211938

19221939
namespace internal {
1923-
template<typename T>
1924-
double asGenericValue(T t) {
1925-
return static_cast<double>(t);
1926-
}
19271940

1928-
template<typename T>
1929-
uintptr_t asGenericValue(T* p) {
1930-
return reinterpret_cast<uintptr_t>(p);
1931-
}
1941+
template<typename T> double asGenericValue(T t) {
1942+
return static_cast<double>(t);
1943+
}
1944+
1945+
template<typename T> uintptr_t asGenericValue(T* p) {
1946+
return reinterpret_cast<uintptr_t>(p);
1947+
}
1948+
19321949
}
19331950

19341951
template<typename ConstantType>
@@ -1941,19 +1958,17 @@ void constant(const char* name, const ConstantType& v) {
19411958
static_cast<double>(asGenericValue(BT::toWireType(v))));
19421959
}
19431960

1944-
1945-
1946-
19471961
// EMSCRIPTEN_BINDINGS creates a static struct to initialize the binding which
19481962
// will get included in the program if the translation unit in which it is
19491963
// defined gets linked into the program. Using a C++ constructor here ensures it
19501964
// occurs after any other C++ constructors in this file, which is not true for
19511965
// __attribute__((constructor)) (they run before C++ constructors in the same
19521966
// file).
19531967
#define EMSCRIPTEN_BINDINGS(name) \
1954-
static struct EmBindInit_##name { \
1955-
EmBindInit_##name(); \
1968+
static void embind_init_##name(); \
1969+
static struct EmBindInit_##name : emscripten::internal::InitFunc { \
1970+
EmBindInit_##name() : InitFunc(embind_init_##name) {} \
19561971
} EmBindInit_##name##_instance; \
1957-
EmBindInit_##name::EmBindInit_##name()
1972+
static void embind_init_##name()
19581973

19591974
} // end namespace emscripten

system/lib/embind/bind.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <vector>
1818

1919
using namespace emscripten;
20+
using namespace internal;
2021

2122
extern "C" {
2223
const char* EMSCRIPTEN_KEEPALIVE __getTypeName(const std::type_info* ti) {
@@ -47,6 +48,20 @@ const char* EMSCRIPTEN_KEEPALIVE __getTypeName(const std::type_info* ti) {
4748
return strdup(str);
4849
}
4950
}
51+
52+
static InitFunc* init_funcs = nullptr;
53+
54+
EMSCRIPTEN_KEEPALIVE void _embind_initialize_bindings() {
55+
for (auto* f = init_funcs; f; f = f->next) {
56+
f->init_func();
57+
}
58+
}
59+
60+
void _embind_register_bindings(InitFunc* f) {
61+
f->next = init_funcs;
62+
init_funcs = f;
63+
}
64+
5065
}
5166

5267
namespace {
@@ -99,13 +114,7 @@ template <typename T> static void register_memory_view(const char* name) {
99114
}
100115
} // namespace
101116

102-
extern "C" {
103-
104-
// Normal initialization, executed through a global constructor. This
105-
// happens on the main thread; pthreads will call it manually, so make
106-
// sure we also export it (via EMSCRIPTEN_KEEPALIVE).
107-
EMSCRIPTEN_KEEPALIVE __attribute__((constructor))
108-
void __embind_register_native_and_builtin_types() {
117+
EMSCRIPTEN_BINDINGS(builtin) {
109118
using namespace emscripten::internal;
110119

111120
_embind_register_void(TypeID<void>::get(), "void");
@@ -171,5 +180,3 @@ void __embind_register_native_and_builtin_types() {
171180
register_memory_view<long double>("emscripten::memory_view<long double>");
172181
#endif
173182
}
174-
175-
} // extern "C"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
15892
1+
15885

tests/test_core.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7363,8 +7363,13 @@ def test_embind(self):
73637363
''')
73647364
self.do_runf('test_embind.cpp', 'abs(-10): 10\nabs(-11): 11', emcc_args=args)
73657365

7366-
def test_embind_2(self):
7367-
self.emcc_args += ['-lembind', '--post-js', 'post.js']
7366+
@parameterized({
7367+
'': ([],),
7368+
'pthreads': (['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],),
7369+
})
7370+
@node_pthreads
7371+
def test_embind_2(self, args):
7372+
self.emcc_args += ['-lembind', '--post-js', 'post.js'] + args
73687373
create_file('post.js', '''
73697374
function printLerp() {
73707375
out('lerp ' + Module.lerp(100, 200, 66) + '.');
@@ -7374,11 +7379,13 @@ def test_embind_2(self):
73747379
#include <stdio.h>
73757380
#include <emscripten.h>
73767381
#include <emscripten/bind.h>
7382+
#include <emscripten/console.h>
73777383
using namespace emscripten;
73787384
int lerp(int a, int b, int t) {
73797385
return (100 - t) * a + t * b;
73807386
}
73817387
EMSCRIPTEN_BINDINGS(my_module) {
7388+
_emscripten_err("test bindings");
73827389
function("lerp", &lerp);
73837390
}
73847391
int main(int argc, char **argv) {

0 commit comments

Comments
 (0)