Skip to content

Commit b1daf81

Browse files
committed
Modernize some documentation
Mostly around the raytrace example but also contributing new web-sys APIs.
1 parent c6db488 commit b1daf81

File tree

5 files changed

+131
-70
lines changed

5 files changed

+131
-70
lines changed

crates/futures/src/task/multithread.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ impl Task {
149149
// * `AWAKE` - the Promise will immediately be resolved and
150150
// we'll execute the work on the next microtask queue.
151151
Poll::Pending => {
152-
wait_async(&self.atomic.state, SLEEPING).then(&inner.closure);
152+
drop(wait_async(&self.atomic.state, SLEEPING).then(&inner.closure));
153153
}
154154
}
155155
}

examples/raytrace-parallel/build.sh

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,11 @@ set -ex
2020
RUSTFLAGS='-C target-feature=+atomics,+bulk-memory' \
2121
cargo build --target wasm32-unknown-unknown --release -Z build-std=std,panic_abort
2222

23-
# Note the usage of `--no-modules` here which is used to create an output which
24-
# is usable from Web Workers. We notably can't use `--target bundler` since
25-
# Webpack doesn't have support for atomics yet.
26-
cargo run --manifest-path ../../crates/cli/Cargo.toml \
27-
--bin wasm-bindgen -- \
28-
../../target/wasm32-unknown-unknown/release/raytrace_parallel.wasm --out-dir . \
29-
--no-modules
23+
# Note the usage of `--target no-modules` here which is required for passing
24+
# the memory import to each wasm module.
25+
cargo run -p wasm-bindgen-cli -- \
26+
../../target/wasm32-unknown-unknown/release/raytrace_parallel.wasm \
27+
--out-dir . \
28+
--target no-modules
3029

31-
python3 -m http.server
30+
python3 server.py

examples/raytrace-parallel/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ concurrency.disabled = true;
1212

1313
// First up, but try to do feature detection to provide better error messages
1414
function loadWasm() {
15-
let msg = 'This demo requires a current version of Firefox (e.g., 70.0) with\n'
16-
msg += 'the `javascript.options.shared_memory` option enabled in `about:config`';
15+
let msg = 'This demo requires a current version of Firefox (e.g., 79.0)';
1716
if (typeof SharedArrayBuffer !== 'function') {
1817
alert('this browser does not have SharedArrayBuffer support enabled' + '\n\n' + msg);
1918
return
Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Supporting More Web APIs in `web-sys`
22

3-
1. <input type="checkbox"/> Ensure that the `.webidl` file describing the
3+
1. Ensure that the `.webidl` file describing the
44
interface exists somewhere within the `crates/web-sys/webidls/enabled`
55
directory.
66

@@ -28,49 +28,12 @@
2828
git mv webidls/unavailable_enum_ident/MyWebApi.webidl webidls/enabled/MyWebApi.webidl
2929
```
3030

31-
2. <input type="checkbox"/> Verify that the `web-sys` crate still builds and
32-
that its tests still pass with the new `.webidl` file enabled:
31+
2. Regenerate the `web-sys` crate auto-generated bindings, which you can do with
32+
the following commands:
3333

3434
```sh
3535
cd crates/web-sys
36-
cargo build
37-
cargo test
36+
cargo run --release --package wasm-bindgen-webidl webidls src/features
3837
```
3938

40-
3. <input type="checkbox"/> Verify that bindings are being generated for your new
41-
API by generating the documentation and searching for the new API in it:
42-
43-
```sh
44-
cd crates/web-sys
45-
cargo doc --open
46-
# search for the new API in the opened docs
47-
```
48-
49-
* <input type="checkbox"/> If the new API is **not** showing up in the docs,
50-
rebuild the `web-sys` crate [with logging enabled](logging.html)
51-
and look for warning messages that mention your new API. Figure out why
52-
bindings weren't generated and then add support to `wasm_bindgen_webidl` for
53-
whatever is needed to generate your API's bindings.
54-
55-
> You might find it helpful to view the generated rust bindings, to see if
56-
> they are what you would expect. The file will be located at
57-
> `target/wasm32-unknown-unknown/debug/build/web-sys-xxx/out/bindings.rs`,
58-
> where `xxx` is a combinations of numbers and letters that represents your
59-
> build. This file is pretty unintelligable until you run `rustfmt` on it, like
60-
> `rustfmt target/wasm32-unknown-unknown/debug/build/web-sys-xxx/out/bindings.rs`.
61-
62-
> There are commented out lines in `web-sys/build.rs` that run rustfmt as part of
63-
> the build process, and this can be very helpful for debugging as any error
64-
> messages with inline code will display it in a readable format.
65-
66-
4. <input type="checkbox"/> Add tests for as many of the features in the WebIDL file
67-
as possible to `crates/web-sys/tests/all/`. See the
68-
[`web-sys` testing documentation](testing.html) for details.
69-
70-
> __Note__: Start here at __4__ if the WebIDL has already been added but doesn't have
71-
> full test coverage, then go back to __3__ if you find any problems.
72-
73-
5. <input type="checkbox"/> If all entities in the WebIDL file have full test coverage,
74-
mark the WebIDL script in the `README.md` file as complete by changing `[ ]` to `[x]`.
75-
76-
6. <input type="checkbox"/> Send a pull request! 😊
39+
You can then use `git diff` to ensure the bindings look correct.

guide/src/examples/raytrace.md

Lines changed: 117 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,120 @@
55
[online]: https://wasm-bindgen.netlify.app/exbuild/raytrace-parallel/
66
[code]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/raytrace-parallel
77

8-
**This is an unstable and experimental example** of using threads with
9-
WebAssembly and Rust, culminating in a parallel raytracer demo. The browser requirements are:
10-
11-
* Firefox Nightly
12-
- `SharedArrayBuffer` is enabled in `about:config` in Firefox
13-
* Google Chrome
14-
- No flags required on recent versions of Chrome
15-
* other browsers haven't implemented the proposed WebAssembly features yet.
16-
17-
Locally to build this demo you'll need `xargo` and the `rust-src` rustup
18-
component, and afterwards `./build.sh` like other examples should build the
19-
example.
20-
21-
Again, to reiterate, this is all experimental and we're working through various
22-
issues as we're working on this. If you're curious to see how this works it's
23-
best to explore via the source code right now! More info will be available here
24-
once WebAssembly threads are closer to stabilization.
8+
This is an of using threads with WebAssembly, Rust, and `wasm-bindgen`,
9+
culminating in a parallel raytracer demo. There's a number of moving pieces to
10+
this demo and it's unfortunately not the easiest thing to wrangle, but it's
11+
hoped that this'll give you a bit of a taste of what it's like to use threads
12+
and wasm with Rust on the web.
13+
14+
### Building the demo
15+
16+
One of the major gotchas with threaded WebAssembly is that Rust does not ship a
17+
precompiled target (e.g. standard library) which has threading support enabled.
18+
This means that you'll need to recompile the standard library with the
19+
appropriate rustc flags, namely `-C target-feature=+atomics,+bulk-memory`.
20+
21+
To do this you can use the `RUSTFLAGS` environment variable that Cargo reads:
22+
23+
```sh
24+
export RUSTFLAGS='-C target-feature=+atomics,+bulk-memory'
25+
```
26+
27+
To recompile the standard library it's recommended to use Cargo's
28+
[`-Zbuild-std`](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std)
29+
feature:
30+
31+
```sh
32+
cargo build --target wasm32-unknown-unknown -Z build-std=panic_abort,std
33+
```
34+
35+
Note that you can also configure this via `.cargo/config.toml`:
36+
37+
```toml
38+
[unstable]
39+
build-std = ['std', 'panic_abort']
40+
41+
[build]
42+
target = "wasm32-unknown-unknown"
43+
rustflags = '-Ctarget-feature=+atomics,+bulk-memory'
44+
```
45+
46+
After this `cargo build` should produce a WebAssembly file with threading
47+
enabled, and the standard library will be appropriately compiled as well.
48+
49+
The final step in this is to run `wasm-bindgen` as usual, and `wasm-bindgen`
50+
needs no extra configuration to work with threads. You can continue to run it
51+
through `wasm-pack`, for example.
52+
53+
### Running the demo
54+
55+
Currently it's required to use the `--target no-modules` flag with
56+
`wasm-bindgen` to run threaded code. This is because the WebAssembly file
57+
imports memory instead of exporting it, so we need to hook initialization of the
58+
wasm module at this time to provide the appropriate memory object.
59+
60+
With `--target no-modules` you'll be able to use `importScripts` inside of each
61+
web worker to import the shim JS generated by `wasm-bindgen` as well as calling
62+
the `wasm_bindgen` initialization function with the shared memory instance from
63+
the main thread. The expected usage is that WebAssembly on the main thread will
64+
post its memory object to all other threads to get instantiated with.
65+
66+
### Caveats
67+
68+
Unfortunately at this time running wasm on the web with threads has a number of
69+
caveats, although some are specific to just `wasm-bindgen`. These are some
70+
pieces to consider and watch out for, although we're always looking for
71+
improvements to be made so if you have an idea please file an issue!
72+
73+
* The main thread in a browser cannot block. This means that if you run
74+
WebAssembly code on the main thread you can *never* block, meaning you can't
75+
do so much as acquire a mutex. This is an extremely difficult limitation to
76+
work with on the web, although one workaround is to run wasm exclusively in
77+
web workers and run JS on the main thread. It is possible to run the same wasm
78+
across all threads, but you need to be extremely vigilant about
79+
synchronization with the main thread.
80+
81+
* Setting up a threaded environment is a bit wonky and doesn't feel smooth
82+
today. For example `--target no-modules` is required with `wasm-bindgen` and
83+
very specific shims are required on both the main thread and worker threads.
84+
These are possible to work with but are somewhat brittle since there's no
85+
standard way to spin up web workers as wasm threads.
86+
87+
* There is no standard notion of a "thread". For example the standard library
88+
has no viable route to implement the `std::thread` module. As a consequence
89+
there is no concept of thread exit and TLS destructors will never run. With no
90+
concept of a thread exit thread stacks will also never be deallocated.
91+
Currently the intention is that with threaded wasm a pool of threads will be
92+
used but that pool is initialized once and never changes over time, since
93+
resources are never reclaimed from it. Much of this has to do with the
94+
`#[wasm_bindgen]`-specific handling of threads. You can get more advanced, but
95+
at that point you may have to not use `wasm-bindgen` as well.
96+
97+
* Web Workers executing WebAssembly code cannot receive events from JS. A Web
98+
Worker has to fully return back to the browser (and ideally should do so
99+
occasionally) to receive JS messages and such. This means that common
100+
paradigms like a rayon thread pool do not apply straightforward-ly to the web.
101+
The intention of the web is that all long-term blocking happens in the browser
102+
itself, not in each thread, but many crates in the ecosystem leveraging
103+
threading are not necessarily engineered this way.
104+
105+
These caveats are all largely inherited from the web platform itself, and
106+
they're important to consider when designing an application for threading. It's
107+
highly unlikely that you can pull a crate off the shelf and "just use it" due to
108+
these limitations. You'll need to be sure to carefully plan ahead and ensure
109+
that gotchas such as these don't cause issues in the future. As mentioned before
110+
though we're always trying to actively develop this support so if folks have
111+
ideas about how to improve, or if web standards change, we'll try to update this
112+
documentation!
113+
114+
### Browser Requirements
115+
116+
This demo should work in the latest Firefox and Chrome versions at this time,
117+
and other browsers are likely to follow suit. Note that threads and
118+
`SharedArrayBuffer` require HTTP headers to be set to work correctly. For more
119+
information see the [documentation on
120+
MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer)
121+
under "Security requirements" as well as [Firefox's rollout blog
122+
post](https://hacks.mozilla.org/2020/07/safely-reviving-shared-memory/). This
123+
means that during local development you'll need to configure your web server
124+
appropriately or enable a workaround in your browser.

0 commit comments

Comments
 (0)