diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a25c1367e..16154bc35 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -63,9 +63,29 @@ jobs: # wasm32-unknown-unknown builds, and even has the runtime fallback for # unsupported threading, but we don't have an environment to execute in. - # wasm32-wasi can test the fallback by running in wasmtime. wasm: - name: WebAssembly + name: WebAssembly (standalone) + runs-on: ubuntu-latest + strategy: + matrix: + include: + - toolchain: stable + - toolchain: nightly + cargoflags: --features web_spin_lock + rustflags: -C target-feature=+atomics,+bulk-memory,+mutable-globals + env: + RUSTFLAGS: ${{ matrix.rustflags }} + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.toolchain }} + targets: wasm32-unknown-unknown + - run: cargo build --verbose --target wasm32-unknown-unknown ${{ matrix.cargoflags }} + + # wasm32-wasi can test the fallback by running in wasmtime. + wasi: + name: WebAssembly (WASI) runs-on: ubuntu-latest env: CARGO_TARGET_WASM32_WASI_RUNNER: /home/runner/.wasmtime/bin/wasmtime @@ -73,10 +93,9 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable with: - targets: wasm32-unknown-unknown,wasm32-wasi - - run: cargo check --verbose --target wasm32-unknown-unknown - - run: cargo check --verbose --target wasm32-wasi + targets: wasm32-wasi - run: curl https://wasmtime.dev/install.sh -sSf | bash + - run: cargo build --verbose --target wasm32-wasi - run: cargo test --verbose --target wasm32-wasi --package rayon - run: cargo test --verbose --target wasm32-wasi --package rayon-core @@ -93,6 +112,6 @@ jobs: done: name: Complete runs-on: ubuntu-latest - needs: [check, test, demo, i686, wasm, fmt] + needs: [check, test, demo, i686, wasm, wasi, fmt] steps: - run: exit 0 diff --git a/Cargo.toml b/Cargo.toml index bd019dbc9..c2ee04bd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,12 +20,20 @@ exclude = ["ci"] [dependencies] rayon-core = { version = "1.12.0", path = "rayon-core" } +wasm_sync = { version = "0.1.0", optional = true } # This is a public dependency! [dependencies.either] version = "1.0" default-features = false +[features] +# This feature switches to a spin-lock implementation on the browser's +# main thread to avoid the forbidden `atomics.wait`. +# +# Only useful on the `wasm32-unknown-unknown` target. +web_spin_lock = ["dep:wasm_sync", "rayon-core/web_spin_lock"] + [dev-dependencies] rand = "0.8" rand_xorshift = "0.3" diff --git a/ci/compat-Cargo.lock b/ci/compat-Cargo.lock index ca7d0737b..371bdb4bd 100644 --- a/ci/compat-Cargo.lock +++ b/ci/compat-Cargo.lock @@ -1065,6 +1065,7 @@ dependencies = [ "rand", "rand_xorshift", "rayon-core", + "wasm_sync", ] [[package]] @@ -1077,6 +1078,7 @@ dependencies = [ "rand", "rand_xorshift", "scoped-tls", + "wasm_sync", ] [[package]] @@ -1476,6 +1478,15 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +[[package]] +name = "wasm_sync" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f22b3c2526c5834350ca8de37292cbd2cb7724e6c812930cfb8c558340cf76f" +dependencies = [ + "web-sys", +] + [[package]] name = "wayland-backend" version = "0.3.2" diff --git a/rayon-core/Cargo.toml b/rayon-core/Cargo.toml index 2cd5372bb..b3de9270f 100644 --- a/rayon-core/Cargo.toml +++ b/rayon-core/Cargo.toml @@ -19,6 +19,15 @@ categories = ["concurrency"] [dependencies] crossbeam-deque = "0.8.1" crossbeam-utils = "0.8.0" +wasm_sync = { version = "0.1.0", optional = true } + +[features] + +# This feature switches to a spin-lock implementation on the browser's +# main thread to avoid the forbidden `atomics.wait`. +# +# Only useful on the `wasm32-unknown-unknown` target. +web_spin_lock = ["dep:wasm_sync"] [dev-dependencies] rand = "0.8" diff --git a/rayon-core/src/latch.rs b/rayon-core/src/latch.rs index b0cbbd833..6c2e4fe97 100644 --- a/rayon-core/src/latch.rs +++ b/rayon-core/src/latch.rs @@ -1,10 +1,11 @@ use std::marker::PhantomData; use std::ops::Deref; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, Condvar, Mutex}; +use std::sync::Arc; use std::usize; use crate::registry::{Registry, WorkerThread}; +use crate::sync::{Condvar, Mutex}; /// We define various kinds of latches, which are all a primitive signaling /// mechanism. A latch starts as false. Eventually someone calls `set()` and diff --git a/rayon-core/src/lib.rs b/rayon-core/src/lib.rs index 7001c8c1d..39df8a2c3 100644 --- a/rayon-core/src/lib.rs +++ b/rayon-core/src/lib.rs @@ -103,6 +103,12 @@ pub use self::thread_pool::current_thread_index; pub use self::thread_pool::ThreadPool; pub use self::thread_pool::{yield_local, yield_now, Yield}; +#[cfg(not(feature = "web_spin_lock"))] +use std::sync; + +#[cfg(feature = "web_spin_lock")] +use wasm_sync as sync; + use self::registry::{CustomSpawn, DefaultSpawn, ThreadSpawn}; /// Returns the maximum number of threads that Rayon supports in a single thread-pool. diff --git a/rayon-core/src/registry.rs b/rayon-core/src/registry.rs index e4f2ac7cd..46cd22b31 100644 --- a/rayon-core/src/registry.rs +++ b/rayon-core/src/registry.rs @@ -1,6 +1,7 @@ use crate::job::{JobFifo, JobRef, StackJob}; use crate::latch::{AsCoreLatch, CoreLatch, Latch, LatchRef, LockLatch, OnceLatch, SpinLatch}; use crate::sleep::Sleep; +use crate::sync::Mutex; use crate::unwind; use crate::{ ErrorKind, ExitHandler, PanicHandler, StartHandler, ThreadPoolBuildError, ThreadPoolBuilder, @@ -15,7 +16,7 @@ use std::io; use std::mem; use std::ptr; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, Mutex, Once}; +use std::sync::{Arc, Once}; use std::thread; use std::usize; diff --git a/rayon-core/src/sleep/mod.rs b/rayon-core/src/sleep/mod.rs index 03d1077f7..fa1f7beed 100644 --- a/rayon-core/src/sleep/mod.rs +++ b/rayon-core/src/sleep/mod.rs @@ -2,9 +2,9 @@ //! for an overview. use crate::latch::CoreLatch; +use crate::sync::{Condvar, Mutex}; use crossbeam_utils::CachePadded; use std::sync::atomic::Ordering; -use std::sync::{Condvar, Mutex}; use std::thread; use std::usize; diff --git a/src/iter/par_bridge.rs b/src/iter/par_bridge.rs index eb058d3e6..17bc15bf4 100644 --- a/src/iter/par_bridge.rs +++ b/src/iter/par_bridge.rs @@ -1,6 +1,11 @@ -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +#[cfg(not(feature = "web_spin_lock"))] use std::sync::Mutex; +#[cfg(feature = "web_spin_lock")] +use wasm_sync::Mutex; + +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; + use crate::iter::plumbing::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer}; use crate::iter::ParallelIterator; use crate::{current_num_threads, current_thread_index};