From 1dedfb85001b1f300f9e0ed49c95d5f47dba7380 Mon Sep 17 00:00:00 2001 From: Sebastian Moser Date: Tue, 17 Sep 2024 19:50:24 +0200 Subject: [PATCH] threading in the browser fun --- Cargo.lock | 190 ++++++++++++++++++++++----------------- Cargo.toml | 3 +- src/core/instance/mod.rs | 47 +++++++--- src/platform/wasm/mod.rs | 71 +++++++++++---- 4 files changed, 200 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e4989d..42b0b0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,18 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -128,17 +140,6 @@ dependencies = [ "syn 2.0.66", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.3.0" @@ -586,16 +587,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] -name = "env_logger" -version = "0.8.4" +name = "env_filter" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ - "atty", - "humantime", "log", "regex", - "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", ] [[package]] @@ -763,6 +774,10 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "serde", +] [[package]] name = "headers" @@ -803,15 +818,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.9" @@ -956,6 +962,7 @@ checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", + "serde", ] [[package]] @@ -977,9 +984,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1112,6 +1119,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-cli", "wasm-bindgen-test", + "web-sys", ] [[package]] @@ -1183,7 +1191,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] @@ -1505,6 +1513,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.203" @@ -1703,15 +1717,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" version = "1.0.61" @@ -2131,9 +2136,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walrus" -version = "0.20.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c03529cd0c4400a2449f640d2f27cd1b48c3065226d15e26d98e4429ab0adb7" +checksum = "160c3708e3ad718ab4d84bec8de8c3d3450cd2902bd6c3ee3bbf50ad7529c2ad" dependencies = [ "anyhow", "gimli 0.26.2", @@ -2175,19 +2180,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -2200,9 +2206,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-cli" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f61e21873f51e3059a8c7c3eef81ede7513d161cfc60751c7b2ffa6ed28270" +checksum = "bb05f9e183365f5cf3ac04d60b54b0e33f494e93730267b5af82633443ee8035" dependencies = [ "anyhow", "docopt", @@ -2220,12 +2226,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-cli-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca821da8c1ae6c87c5e94493939a206daa8587caff227c6032e0061a3d80817f" +checksum = "1a7f49ca6e7da74d53d6d716b868828a47d1c3808a8f676e2104fadd3b9874bb" dependencies = [ "anyhow", - "base64 0.21.7", + "base64 0.22.1", "log", "rustc-demangle", "serde_json", @@ -2242,12 +2248,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-externref-xform" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "102582726b35a30d53157fbf8de3d0f0fed4c40c0c7951d69a034e9ef01da725" +checksum = "2c1f37f2705f4177cc87e5b2763115d078d39e4843e351438b34b085d53a8930" dependencies = [ "anyhow", "walrus", + "wasm-bindgen-wasm-conventions", ] [[package]] @@ -2264,9 +2271,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2274,9 +2281,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -2287,19 +2294,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-multi-value-xform" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3498e4799f43523d780ceff498f04d882a8dbc9719c28020034822e5952f32a4" +checksum = "2864e3f221fef3869992b541b238e55f53f99b43c4ce220422a6e1ec9458dc21" dependencies = [ "anyhow", "walrus", + "wasm-bindgen-wasm-conventions", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-bindgen-test" @@ -2328,9 +2336,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-threads-xform" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5add359b7f7d09a55299a9d29be54414264f2b8cf84f8c8fda5be9269b5dd9" +checksum = "7e9ca60ee029d64cf6f63a630050935360c3877844f6de38e8287afb8f1d2715" dependencies = [ "anyhow", "walrus", @@ -2339,19 +2347,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-wasm-conventions" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c04e3607b810e76768260db3a5f2e8beb477cb089ef8726da85c8eb9bd3b575" +checksum = "6e429e00149de60ffc768e6e1f0563778a237e7c11cc01801edf9734bff8161f" dependencies = [ "anyhow", + "leb128", + "log", "walrus", + "wasmparser", ] [[package]] name = "wasm-bindgen-wasm-interpreter" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea966593c8243a33eb4d643254eb97a69de04e89462f46cf6b4f506aae89b3a" +checksum = "771c49db324f195f221796bf3868247dd91cca4a85604dcb3729213e439abe59" dependencies = [ "anyhow", "log", @@ -2361,24 +2372,32 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.29.0" +version = "0.212.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881" +checksum = "501940df4418b8929eb6d52f1aade1fdd15a5b86c92453cb696e3c906bd3fc33" dependencies = [ "leb128", ] [[package]] name = "wasmparser" -version = "0.80.2" +version = "0.212.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b" +checksum = "8d28bc49ba1e5c5b61ffa7a2eace10820443c4b7d1c0b144109261d14570fdf8" +dependencies = [ + "ahash", + "bitflags 2.5.0", + "hashbrown 0.14.5", + "indexmap 2.5.0", + "semver", + "serde", +] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -2409,15 +2428,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2591,6 +2601,26 @@ dependencies = [ "memchr", ] +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "zeroize" version = "1.8.1" diff --git a/Cargo.toml b/Cargo.toml index ef0347e..4933e74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ required-features = [ "os-target" ] [features] default = [ "os-target" ] os-target = [ "clap", "home", "nix", "sysinfo", "ciborium/default", "tracing-subscriber", "async", "tracing-subscriber/env-filter", "libloading", "ciborium-io", "tracing-core" ] -wasm-target = [ "wasm-bindgen", "console_error_panic_hook", "wasm-bindgen-cli" ] +wasm-target = [ "wasm-bindgen", "console_error_panic_hook", "wasm-bindgen-cli", "web-sys", "web-sys/Worker", "web-sys/Window", "web-sys/WorkerOptions", "web-sys/WorkerType" ] async = ["tokio/net", "tokio", "tokio/rt-multi-thread", "tokio/io-util"] @@ -46,6 +46,7 @@ dyn-clone = "1.0.17" wasm-bindgen = { version = "0.2.84", optional = true } console_error_panic_hook = { version = "0.1.7", optional = true } wasm-bindgen-cli = { version = "0.2.92", optional = true } +web-sys = { version = "0.3.70", optional = true } # os dependencies clap = { version = "4.4.11", features = ["cargo"], optional = true } diff --git a/src/core/instance/mod.rs b/src/core/instance/mod.rs index 7cd637b..b804a7c 100644 --- a/src/core/instance/mod.rs +++ b/src/core/instance/mod.rs @@ -397,23 +397,27 @@ impl Instance { } pub fn spawn(&mut self, name: &str, func: impl FnOnce() -> MizeResult<()> + Send + 'static) -> MizeResult<()> { - let threads_inner = self.threads.lock()?; + let mut threads_inner = self.threads.lock()?; let mut next_thread_id = self.next_thread_id.lock()?; - threads_inner.push((next_thread_id, name.to_owned())); + threads_inner.push((*next_thread_id, name.to_owned())); - let to_spawn = move || { - debug!("spawning thread: {}", name); - let my_thread_id = next_thread_id; + let my_thread_id_no_mutex_guard = *next_thread_id; + let thread_mutex = self.threads.clone(); + let name_to_move = name.to_owned(); + let to_spawn = move || -> MizeResult<()> { + debug!("spawning thread: {}", name_to_move); + let my_thread_id = my_thread_id_no_mutex_guard; func()?; - let mut threads_inner = self.threads.lock()?; - threads_inner = threads_inner.into_iter().filter(|el| match el { + let mut threads_inner = thread_mutex.lock()?; + *threads_inner = threads_inner.clone().into_iter().filter(|el| match el { (my_thread_id, _) => false, (_, _) => true, - }); - debug!("thread '{}' stopped", name); + }).collect(); + debug!("thread '{}' stopped", name_to_move); + Ok(()) }; *next_thread_id += 1; @@ -422,7 +426,7 @@ impl Instance { thread::spawn(move || to_spawn()); #[cfg(feature = "wasm-target")] - crate::platform::wasm::wasm_spawn(move || to_spawn())?; + crate::platform::wasm::wasm_spawn(to_spawn)?; Ok(()) } @@ -452,12 +456,22 @@ impl Instance { return Ok(data); } + #[cfg(feature = "async")] - pub fn spawn_async + Send + Sync + 'static>(&mut self, name: &str, func: F) { - self.threads.push(name.to_owned()); + pub fn spawn_async + Send + Sync + 'static>(&mut self, name: &str, func: F) -> MizeResult<()> { + let mut threads_inner = self.threads.lock()?; + let mut next_thread_id = self.next_thread_id.lock()?; + + threads_inner.push((*next_thread_id, name.to_owned())); let runtime_inner = self.runtime.lock().unwrap(); runtime_inner.spawn(func); + + *next_thread_id += 1; + + Ok(()) } + + #[cfg(feature = "async")] pub fn async_get_handle(&self) -> Handle { let runtime_inner = self.runtime.lock().unwrap(); @@ -467,13 +481,18 @@ impl Instance { #[cfg(feature = "async")] pub fn spawn_async_blocking + Send + Sync + 'static>(&mut self, name: &str, func: F) -> F::Output { - use std::process::Output; - self.threads.push(name.to_owned()); + let mut threads_inner = self.threads.lock().expect("mutex lock failed in spawn_async_blocking"); + let mut next_thread_id = self.next_thread_id.lock().expect("mutex lock failed in spawn_async_blocking"); + + threads_inner.push((*next_thread_id, name.to_owned())); let runtime_inner = self.runtime.lock().unwrap(); let handle = runtime_inner.handle().to_owned(); drop(runtime_inner); let result = handle.block_on(func); + + *next_thread_id += 1; + return result; } diff --git a/src/platform/wasm/mod.rs b/src/platform/wasm/mod.rs index e7707d2..775c57b 100644 --- a/src/platform/wasm/mod.rs +++ b/src/platform/wasm/mod.rs @@ -1,10 +1,15 @@ use wasm_bindgen::prelude::*; use std::ptr::NonNull; use std::panic; +use web_sys::js_sys; +use crate::platform::wasm::js_sys::Function; +use web_sys::{WorkerOptions, WorkerType}; +use web_sys::Worker; use crate::instance::{self, Instance}; use crate::error::MizeResult; -use crate::Module; +use crate::{mize_err, Module}; +use crate::MizeError; // console_log macro @@ -30,28 +35,62 @@ static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; // A function imitating `std::thread::spawn`. // thanks to: https://www.tweag.io/blog/2022-11-24-wasm-threads-and-messages/ -pub fn wasm_spawn(f: impl FnOnce() + Send + 'static) -> MizeResult<()> { - let worker = web_sys::Worker::new("./worker.js")?; - // Double-boxing because `dyn FnOnce` is unsized and so `Box` is a fat pointer. - // But `Box>` is just a plain pointer, and since wasm has 32-bit pointers, - // we can cast it to a `u32` and back. - let ptr = Box::into_raw(Box::new(Box::new(f) as Box)); - let msg = js_sys::Array::new(); - // Send the worker a reference to our memory chunk, so it can initialize a wasm module - // using the same memory. - msg.push(&wasm_bindgen::memory()); - // Also send the worker the address of the closure we want to execute. - msg.push(&JsValue::from(ptr as u32)); - worker.post_message(&msg); +pub fn wasm_spawn(f: impl FnOnce() -> MizeResult<()> + Send + 'static) -> MizeResult<()> { + - Ok(()) + // to get window.mize_worker_url, which is set by some js code, which gets "compiled" by a + // bundler, which sets window.mize_worker_url to the url of ./npm_pkg/worker.js + // I hate the js ecosystem.... + // those urls then become base64 data urls containing the js code...... i hate my life + // import worker from './worker.js?worker' ..... does however crate a worker-hash.js file in + // the dist dir...... + // this is then however a function, that creates the worker.... so put that at + // window.mize_worker_fn and call that here + + + //let js_fn_code = r#" + //return window.mize_worker_url + //"#; + //let js_fn = Function::new_no_args(js_fn_code); + //let res = js_fn.call0(&web_sys::wasm_bindgen::JsValue::NULL).unwrap(); + + + let window_obj = JsValue::from(web_sys::window().unwrap()); + let worker_fn: Function = js_sys::Reflect::get(&window_obj, &("mize_worker_fn".into())).unwrap().into(); + let worker: Worker = worker_fn.call0(&web_sys::wasm_bindgen::JsValue::NULL).unwrap().into(); + + /* + let worker_url_href = js_sys::Reflect::get(&worker_url_obj, &("href".into())).unwrap(); + let worker_url = worker_url_href.as_string().unwrap(); + + let mut worker_options = WorkerOptions::new(); + worker_options.set_type(WorkerType::Module); + let worker = web_sys::Worker::new_with_options( + worker_url.as_str(), + &worker_options + ).map_err(|e| mize_err!("From JsValue: {:?}", e))?; + */ + + // Double-boxing because `dyn FnOnce` is unsized and so `Box` is a fat pointer. + // But `Box>` is just a plain pointer, and since wasm has 32-bit pointers, + // we can cast it to a `u32` and back. + let ptr = Box::into_raw(Box::new(Box::new(f) as Box MizeResult<()>>)); + let msg = js_sys::Array::new(); + // Send the worker a reference to our memory chunk, so it can initialize a wasm module + // using the same memory. + msg.push(&wasm_bindgen::memory()); + // Also send the worker the address of the closure we want to execute. + msg.push(&JsValue::from(ptr as u32)); + worker.post_message(&msg); + + Ok(()) } #[wasm_bindgen] // This function is here for `worker.js` to call. pub fn worker_entry_point(addr: u32) { // Interpret the address we were given as a pointer to a closure to call. - let closure = unsafe { Box::from_raw(ptr as *mut Box) }; + let closure = unsafe { Box::from_raw(addr as *mut Box) }; (*closure)(); }