Skip to content

embind cannot be initialized correctly in a thread created in static constructor #19849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ufolyah opened this issue Jul 12, 2023 · 6 comments · May be fixed by #24322
Open

embind cannot be initialized correctly in a thread created in static constructor #19849

ufolyah opened this issue Jul 12, 2023 · 6 comments · May be fixed by #24322
Labels

Comments

@ufolyah
Copy link

ufolyah commented Jul 12, 2023

I found this bug because I created a thread in wasmfs_before_preload(), which has __attribute__((init_priority(100))).

When the thread runs, embind has not been fully initialized in main thread. So Module['__embind_initialize_bindings'] did not register the types for me, but set initializedJS to true.

I did not use embind in thread created in wasmfs_before_preload, but the worker is reused in another thread, and in that thread embind does not work, caused a crash in my app.

I hope we can have a way to ensure wasm_init_ctors are completed, or embind inited, when spawnthread get called.

@ufolyah ufolyah changed the title embind cannot initialized correctly in a thread created in static constructor embind cannot be initialized correctly in a thread created in static constructor Jul 12, 2023
@sbc100
Copy link
Collaborator

sbc100 commented Jul 12, 2023

@brendandahl

@sbc100
Copy link
Collaborator

sbc100 commented Jul 12, 2023

When the thread runs, embind has not been fully initialized in main thread. So Module['__embind_initialize_bindings'] did not register the types for me, but set initializedJS to true.

I'm curious about this statement. Why does running __embind_initialize_bindings in a new thread depend on it having already run on the main thread? Doesn't embind_initialize_bindings work independently on each thread that calls it?

@ufolyah
Copy link
Author

ufolyah commented Jul 12, 2023

I'm curious about this statement. Why does running __embind_initialize_bindings in a new thread depend on it having already run on the main thread? Doesn't embind_initialize_bindings work independently on each thread that calls it?

From my investigation, EMSCRIPTEN_BINDINGS macro works based on static constructors. when it contructs, the embind declare function are registered to init_func, which get called in other thread.

@brendandahl
Copy link
Collaborator

A small example the reproduces the issue would be helpful.

@sbc100
Copy link
Collaborator

sbc100 commented Jul 12, 2023

I'm curious about this statement. Why does running __embind_initialize_bindings in a new thread depend on it having already run on the main thread? Doesn't embind_initialize_bindings work independently on each thread that calls it?

From my investigation, EMSCRIPTEN_BINDINGS macro works based on static constructors. when it contructs, the embind declare function are registered to init_func, which get called in other thread.

Ah yes, embind_initialize_bindings must be called only after all the EMSCRIPTEN_BINDINGS static constructors have run.

@ufolyah
Copy link
Author

ufolyah commented Jul 12, 2023

//Build with: emcc example.cpp -lembind -sWASMFS=1 -sUSE_PTHREADS=1 -g -O0 -s PTHREAD_POOL_SIZE=2 -o example.html

#include <emscripten.h>
#include <emscripten/wasmfs.h>
#include <emscripten/bind.h>
#include <thread>

void EMSCRIPTEN_KEEPALIVE wasmfs_before_preload(void) {
    // remove next 3 lines to work.
    std::thread([](){
        emscripten_log(EM_LOG_CONSOLE| EM_LOG_ERROR, "thread 1");
    }).detach();
    
    //block the wasm_init_ctors for a while.
    auto start = emscripten_get_now();
    while (emscripten_get_now() - start < 500) {}
}

using namespace emscripten;

class Foo{
public:
    int onInfo(std::string a) {
        auto object = val::object();
        object.set("a", a);
        EM_ASM({
            console.log(Emval.toValue($0));
        }, object.as_handle());
        return 0;
    }
};

int EMSCRIPTEN_KEEPALIVE main() {
    auto start = emscripten_get_now();
    while (emscripten_get_now() - start < 1000) {}
    std::thread([](){
        std::thread([](){
            Foo f;
            f.onInfo("thread 2");
        }).detach();
    }).detach();
    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants