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

Multi-threading on web #1022

Open
necrashter opened this issue Jan 31, 2023 · 1 comment
Open

Multi-threading on web #1022

necrashter opened this issue Jan 31, 2023 · 1 comment
Labels
feature Adds functionality to the library help wanted status: upstream Issue that originates in an upstream project and can't be dealt with here.

Comments

@necrashter
Copy link

necrashter commented Jan 31, 2023

Background

Although Godot documentation says that multi-threading is not supported with GDNative, progress has been made since then. In particular, tracking issue for dynamic linking + pthreads has been closed in Emscripten repository because:

I think this is is largely complete. We still warn about it being experimental, but it should work % bugs. We can open specific bugs if/when they are found.

Therefore, we should be able to use multi-threading on web, even if it's limited.

Instructions

This section will describe how I built a GDNative Rust library with threads for web. It can serve as a starting point for those who want to work on this.

First, make sure that you can build your library without threads using the instructions in the book.

Compile the Godot web export template with both threads_enabled=yes and gdnative_enabled=yes:

scons platform=javascript tools=no threads_enabled=yes gdnative_enabled=yes target=release

Update .cargo/config.toml:

[target.wasm32-unknown-emscripten]
rustflags = [
  "-Clink-arg=-sSIDE_MODULE=2", # build a side module that Godot can load
  "-Zlink-native-libraries=no", # workaround for a wasm-ld error during linking
  "-Cpanic=abort", # workaround for a runtime error related to dyncalls
# Additional flags to enable pthreads:
  "-Clink-arg=-pthread",
  "-Clink-arg=-sUSE_PTHREADS=1",
  "-Ctarget-feature=+atomics,+bulk-memory",
]

Other flags you may try: "-Ctarget-feature=+atomics,+bulk-memory,+mutable-globals", "-Clink-arg=-sWASM_WORKERS".

The standard library must be recompiled with these flags as well. To do this, add -Z build-std=panic_abort,std to your build command:

source "/home/ilker/Programming/emsdk/emsdk_env.sh"
export C_INCLUDE_PATH=$EMSDK/upstream/emscripten/cache/sysroot/include

cargo +nightly build -Z build-std=panic_abort,std --target=wasm32-unknown-emscripten --release

NOTE: Multi-threaded web apps depend on SharedArrayBuffer, which is only available if the webpage is cross-origin isolated. Here is a Python script (python3 -m http.server replacement) for serving a cross-origin isolated webpages. Use it to test your exported game.

Problems

Following the instructions above leads to the following compile error (tested on 2023-01-31):

   --> /home/ilker/.cargo/registry/src/github.com-1ecc6299db9ec823/parking_lot_core-0.9.6/src/parking_lot.rs:202:5
    |
202 |     thread_local!(static THREAD_DATA: ThreadData = ThreadData::new());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     could not find `__FastLocalKeyInner` in `thread`
    |     help: a struct with a similar name exists: `__StaticLocalKeyInner`
    |
    = note: this error originates in the macro `$crate::__thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)

The same error is repeated for all usages of thread_local! macro in parking_lot.

In order to quickly check whether it works without thread_local, I removed the parking_lot dependency and one other usage of thread_local! in gdnative-core/src/export/emplace.rs. I don't share the changes I made because it was quite hacky and ugly. For example, there's no try_lock_for(duration) method for mutexes in standard library. So I replaced them with lock().

With these changes, compile succeeds, and the library works correctly until a new thread is spawned. Spawning a new thread causes the following runtime error:

Uncaught RuntimeError: null function or function signature mismatch

Thanks to chitoyuu for helping on Discord.

We haven't confirmed whether multi-threaded C/C++ GDNative build works on web yet. I failed to compile the simple tutorial plugin provided in official Godot docs for the web, let alone a multi-threaded one.

@necrashter necrashter added the feature Adds functionality to the library label Jan 31, 2023
@chitoyuu chitoyuu added help wanted status: upstream Issue that originates in an upstream project and can't be dealt with here. labels Jan 31, 2023
@chitoyuu
Copy link
Contributor

chitoyuu commented Jan 31, 2023

Thanks for the detailed writeup! Threading on the web is a niche feature, and as stated in the issue, unsupported yet by the upstream Godot engine. There is also a good chance that the issue presented here has its root causes in emscripten or the Rust standard library, both highly complex projects. As such, we'll mostly have to rely on motivated contributors for a possible solution to the problem.

Some potential starting points are:

  • Why is the std internal __FastLocalKeyInner unavailable on the wasm32-unknown-emscripten target, and whether it can be fixed.
  • What is this null / mismatching function that thread::spawn (presumably) is trying to call.

If you're interested in helping out, please let us know in this issue, or reach out to us on Discord.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Adds functionality to the library help wanted status: upstream Issue that originates in an upstream project and can't be dealt with here.
Projects
None yet
Development

No branches or pull requests

2 participants