-
Notifications
You must be signed in to change notification settings - Fork 55
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
Allow running the smoldot wasm node from multiple threads #494
Conversation
I was actually completely mistaken. The worker immediately panics, after which the main thread takes the relay, which led me to believe that everything worked. But actually no, things are very racy. This is because none of the per-thread "magic variables" that the libc and Rust compiler use are initialized properly, so the threads write on each other's stacks. It turns out that their plan is to add a new host function named |
Closing due to too many conflicts. See #91 (comment) |
This substantial PR refactors the execution model of the wasm-node in order to allow executing it from multiple different threads at the same time.
cc #91
In terms of API, it is rather simple: a new
Client.createBackgroundRunnable
function has been added, which return an opaque object. The user can then send this object to a worker (doing so is entirely their responsibility), then doimport { run } from 'smoldot/worker'
, then callrun(object)
. This runs the CPU-heavy tasks of smoldot from within that worker.Note that there's no obligation to actually call
run
from within a worker.run
doesn't assume that it is running in a worker, instead it simply doesn't assume that it can access the networking.Unfortunately, since we're using a
SharedArrayBuffer
, this comes with some restrictions: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirementsIt is unclear to me how this actually interacts with content scripts of browser extensions.
This branch has been tested on both NodeJS and the browser, and overall works surprisingly flawlessly (provided we replace
rand::random()
with constants, as explained below).Implementation
It is implemented pretty much as described in #91:
Platform
trait or something similar.advance_execution
function in a loop, rather than automatically whenever any function is called by the JS.advance_execution
takes as input two flags indicating whether to run networking tasks and whether to run non-networking tasks. When in a worker, we run only non-networking tasks. When outside of a worker, we run networking tasks and also maybe non-networking tasks depending on whether a worker exists.json_rpc_responses_peek
has been refactored to useAtomics.wait
in order to detect when a response arrives. This makes it possible to notify of a response from within a background thread.Overall, this refactoring considerably simplifies the general flow of the code, especially thanks to the use of
Atomics.waitAsync
which is unfortunately not stable yet on Firefox.This branch has the following caveats:
rand::random()
(which usesthread_rng
) with hardcoded values in order to make it work. This could however realistically be fixed by manually using a PRNG and seeding manually.wasm-opt
fails to parse the generated Wasm. It's unclear whether it's because it doesn't support atomics, or shared memory, or something like.#![feature(stdsimd, simd_wasm64)]
needs to be added due to x86/x86_64 intrinsics seem to be marked stable, but require feature flags rust-lang/rust#98253. It's unclear whether this is a Rust bug, or if thenotify
functions aren't stable.Atomics.waitAsync
, which is unfortunately not stable yet on Firefox. Using a replacement, while technically possible, is likely extremely hard.panic=unwind
.It is however overall very encouraging.
Even if in the end the two CORS headers end up being too annoying and this feature ends up being unused, I would still be in favor of merging most of the changes in this branch, as it considerably cleans up everything.