Skip to content
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

dylink: Share dynamicLibraries array across workers #19496

Merged

Conversation

kleisauke
Copy link
Collaborator

@kleisauke kleisauke commented Jun 1, 2023

To ensure that the same dynamic libraries are loaded among all workers, it remains necessary to share the dynamicLibraries array, especially when it is defined outside the module (e.g. in MODULARIZE mode).

Fixes a regression introduced in commit ceb2e28.

Resolves: #20507.

@sbc100
Copy link
Collaborator

sbc100 commented Jun 1, 2023

The idea with removing this was that pthreads all will call __emscripten_dlsync_self before they start which should load all the same libraries that the main thread loaded on startup.

However, maybe that isn't working for dynamicLibraries?

self.emcc_args += ['--pre-js', 'pre.js']
self.emcc_args += ['--extern-post-js=extern-post.js']
self.set_setting('MODULARIZE')
self.set_setting('EXPORT_NAME=ModuleFactory')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need these two settings to very that dynamicLibraries is shared do we?

@bobziuchkovski
Copy link

bobziuchkovski commented Oct 21, 2023

This is something that's hitting Godot engine builds as well (filed as #20507, related issue in godot repo: godotengine/godot#82865). I tested an emscripten-releases build from today with the changes from this PR applied and that resolves the issue.

@kleisauke
Copy link
Collaborator Author

The idea with removing this was that pthreads all will call __emscripten_dlsync_self before they start which should load all the same libraries that the main thread loaded on startup.

However, maybe that isn't working for dynamicLibraries?

Hmm, I wasn't aware of this. I thought it was controlled by loadDylibs() in receiveInstance(), which is called for all module instantiations.

loadDylibs();

Note that I also build with -sAUTOLOAD_DYLIBS=0, so Module.dynamicLibraries would be empty at that point without this PR. Perhaps commit kleisauke@38a001d makes more sense?

@@ -9510,6 +9514,9 @@ def test_Module_dynamicLibraries(self, args):
err('sharedModules: ' + Object.keys(sharedModules));
assert('liblib.so' in sharedModules);
assert(sharedModules['liblib.so'] instanceof WebAssembly.Module);

// Verify whether the main thread passes Module.dynamicLibraries to the worker
assert(Module['dynamicLibraries'].includes('liblib.so'));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you find a way to make a test case that fails, rather than verifying the contents dynamicLibraries. My understanding is that _emscripten_dlsync_self should be enough to have each new thread be in sync with the main thread, so there should be no need for dynamicLibraries on worker threads.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e. can you make a test case that fails with onmessage() captured an uncaught exception: RangeError: WebAssembly.Table.get(): invalid index [index] into funcref table of size [size] on main?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, see commit b1837ef. Though, that fails on main with Maximum call stack size exceeded, so not exactly the same error.

FWIW, in the project I'm currently working on, the error manifests as null function or function signature mismatch when trying to use a function available in the side module.

@adamscott
Copy link

@kleisauke Is your PR ready to be merged? Did you investigate why it fails CI wise?

I'm the Web lead of the Godot Engine, and I just found out about this issue, as I somehow missed godotengine/godot#82865. We're kinda stuck to use 3.1.39 for our 4.3 release.

I'll try to fork emscripten to test out your PR, if I can be of any help.

@kleisauke
Copy link
Collaborator Author

@adamscott This PR should be ready, except that I need to rebase it to resolve the conflicts. The failed CI tests seem unrelated to this PR.

FWIW, I opened a separate reproducer in #20625. wasm-vips has been cherry-picking this PR in a custom patchset for a while now: 3.1.61...kleisauke:wasm-vips-3.1.61.

To ensure that the same dynamic libraries are loaded among all
workers, it remains necessary to share the `dynamicLibraries` array,
especially when it is defined outside the module (e.g. in
`MODULARIZE` mode).

Fixes a regression introduced in commit ceb2e28.
@kleisauke kleisauke force-pushed the fix-dynamicLibraries-regression branch from b1837ef to 005a033 Compare June 11, 2024 15:59
Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not really sure why the existing shared library synchronization stuff isn't sufficient.

But if the new test fails without this change then LGTM

@adamscott
Copy link

adamscott commented Jun 11, 2024

I confirm that this PR works. I was able to build a Godot 4.3 Web template (with threads and dlink enabled) using this PR (rebased @ 3.1.62-git) and export a game with it without any issues.
If I use any version from 3.1.40 to 3.1.61, I get this following error:

Pthread 0x00c4c660 sent an error! http://localhost:8060/tmp_js_export.js:337: RangeError: WebAssembly.Table.prototype.get expects an integer less than the length of the table

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

Successfully merging this pull request may close these issues.

Possible regression in pthreads w/loadDynamicLibrary (3.1.40 through HEAD, last working 3.1.39)
4 participants