From 94438ff771ee0a6a55d79e49a655707970acb615 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Sun, 24 Aug 2025 14:20:49 +0800 Subject: [PATCH 1/2] feat: add feature to allow spawn from worker --- Cargo.toml | 1 + rust-toolchain.toml | 2 +- src/wasm32/mod.rs | 5 ++--- src/wasm32/utils.rs | 13 ++++++------- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 743bdf0..c530dcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ readme = "README.md" [features] default = ["es_modules"] es_modules = [] +spawn_from_worker = [] [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.95" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 4887225..b9c0517 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,5 +2,5 @@ # https://rust-lang.github.io/rustup-components-history [toolchain] channel = "nightly-2024-03-16" -components = ["rust-src", "rustfmt"] +components = ["rust-src", "rustfmt", "rust-analyzer"] targets = ["wasm32-unknown-unknown"] diff --git a/src/wasm32/mod.rs b/src/wasm32/mod.rs index 8bcce7e..039f1e6 100644 --- a/src/wasm32/mod.rs +++ b/src/wasm32/mod.rs @@ -57,8 +57,7 @@ impl WorkerMessage { pub fn post(self) { let req = Box::new(self); - js_sys::eval("self") - .unwrap() + js_sys::global() .dyn_into::() .unwrap() .post_message(&JsValue::from(Box::into_raw(req) as u32)) @@ -251,7 +250,7 @@ impl Builder { func: mem::transmute::, Box>(main), }; - if is_web_worker_thread() { + if is_web_worker_thread() && !cfg!(feature = "spawn_from_worker") { WorkerMessage::SpawnThread(BuilderRequest { builder: self, context }).post(); } else { self.spawn_for_context(context); diff --git a/src/wasm32/utils.rs b/src/wasm32/utils.rs index 1791657..241ec3d 100644 --- a/src/wasm32/utils.rs +++ b/src/wasm32/utils.rs @@ -4,16 +4,15 @@ use std::{ sync::{LockResult, Mutex, MutexGuard, TryLockError}, }; +use js_sys::Reflect; use wasm_bindgen::prelude::*; use web_sys::{Blob, Url, WorkerGlobalScope}; pub fn available_parallelism() -> io::Result { - if let Some(window) = web_sys::window() { - return Ok(NonZeroUsize::new(window.navigator().hardware_concurrency() as usize).unwrap()); - } - - if let Ok(worker) = js_sys::eval("self").unwrap().dyn_into::() { - return Ok(NonZeroUsize::new(worker.navigator().hardware_concurrency() as usize).unwrap()); + if let Ok(navigator) = Reflect::get(&js_sys::global(), &"navigator".into()) { + if let Ok(hardware_concurrency) = Reflect::get(&navigator, &"hardwareConcurrency".into()) { + return Ok(NonZeroUsize::new(hardware_concurrency.as_f64().unwrap() as usize).unwrap()); + } } Err(io::Error::new( @@ -23,7 +22,7 @@ pub fn available_parallelism() -> io::Result { } pub fn is_web_worker_thread() -> bool { - js_sys::eval("self").unwrap().dyn_into::().is_ok() + js_sys::global().dyn_into::().is_ok() } /// Extracts path of the `wasm_bindgen` generated .js shim script. From 1155d645aedfdbe55f8ea336a9e8a8150239beb0 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Wed, 3 Sep 2025 01:17:47 +0800 Subject: [PATCH 2/2] feat: use std::thread::current().id() to chekck main thread --- Cargo.toml | 1 - src/lib.rs | 1 + src/wasm32/mod.rs | 4 ++-- src/wasm32/scoped.rs | 4 ++-- src/wasm32/utils.rs | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c530dcb..743bdf0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ readme = "README.md" [features] default = ["es_modules"] es_modules = [] -spawn_from_worker = [] [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.95" diff --git a/src/lib.rs b/src/lib.rs index a2685c4..7a6f222 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(thread_id_value)] #![cfg_attr(target_arch = "wasm32", feature(stdarch_wasm_atomic_wait))] // Import reusable APIs from std diff --git a/src/wasm32/mod.rs b/src/wasm32/mod.rs index 039f1e6..a186d54 100644 --- a/src/wasm32/mod.rs +++ b/src/wasm32/mod.rs @@ -13,7 +13,7 @@ use scoped::ScopeData; pub use scoped::{scope, Scope, ScopedJoinHandle}; use signal::Signal; use utils::SpinLockMutex; -pub use utils::{available_parallelism, get_wasm_bindgen_shim_script_path, get_worker_script, is_web_worker_thread}; +pub use utils::{available_parallelism, get_wasm_bindgen_shim_script_path, get_worker_script, is_main_thread}; use wasm_bindgen::prelude::*; use web_sys::{DedicatedWorkerGlobalScope, Worker, WorkerOptions, WorkerType}; @@ -250,7 +250,7 @@ impl Builder { func: mem::transmute::, Box>(main), }; - if is_web_worker_thread() && !cfg!(feature = "spawn_from_worker") { + if !is_main_thread() { WorkerMessage::SpawnThread(BuilderRequest { builder: self, context }).post(); } else { self.spawn_for_context(context); diff --git a/src/wasm32/scoped.rs b/src/wasm32/scoped.rs index cd18532..df13c18 100644 --- a/src/wasm32/scoped.rs +++ b/src/wasm32/scoped.rs @@ -7,7 +7,7 @@ use std::{ }, }; -use super::{signal::Signal, utils::is_web_worker_thread, Builder, JoinInner}; +use super::{signal::Signal, utils::is_main_thread, Builder, JoinInner}; /// A scope to spawn scoped threads in. /// @@ -89,7 +89,7 @@ where F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T, { // Fail early to avoid flaky panics that depend on execution time - if !is_web_worker_thread() { + if is_main_thread() { panic!("scope is not allowed on the main thread"); } diff --git a/src/wasm32/utils.rs b/src/wasm32/utils.rs index 241ec3d..ac94283 100644 --- a/src/wasm32/utils.rs +++ b/src/wasm32/utils.rs @@ -6,7 +6,7 @@ use std::{ use js_sys::Reflect; use wasm_bindgen::prelude::*; -use web_sys::{Blob, Url, WorkerGlobalScope}; +use web_sys::{Blob, Url}; pub fn available_parallelism() -> io::Result { if let Ok(navigator) = Reflect::get(&js_sys::global(), &"navigator".into()) { @@ -21,8 +21,8 @@ pub fn available_parallelism() -> io::Result { )) } -pub fn is_web_worker_thread() -> bool { - js_sys::global().dyn_into::().is_ok() +pub fn is_main_thread() -> bool { + std::thread::current().id().as_u64().get() == 1_u64 } /// Extracts path of the `wasm_bindgen` generated .js shim script.