From 232a1c4fbc40de22f78628766500f752be87ae8a Mon Sep 17 00:00:00 2001 From: John Sharratt's Shared Account Date: Fri, 10 Jun 2022 21:45:28 +0200 Subject: [PATCH] Modified the store so that it can be Cloned Added a Reactor that drives WebAssembly react pattern Fixed multithreading Added thread local storage Implemented the remaining functionality for the bus --- Cargo.lock | 82 +- docs/migration_to_3.0.0.md | 2 +- examples/imports_function_env.rs | 4 +- lib/api/Cargo.toml | 2 + lib/api/src/common/reactors.rs | 88 ++ lib/api/src/js/function_env.rs | 4 +- lib/api/src/js/imports.rs | 40 +- lib/api/src/js/instance.rs | 37 +- lib/api/src/js/mod.rs | 5 + lib/api/src/js/module.rs | 3 + lib/api/src/js/thread.rs | 44 + lib/api/src/sys/externals/function.rs | 18 +- lib/api/src/sys/externals/memory.rs | 183 ++- lib/api/src/sys/function_env.rs | 25 +- lib/api/src/sys/imports.rs | 52 +- lib/api/src/sys/instance.rs | 7 +- lib/api/src/sys/mem_access.rs | 68 +- lib/api/src/sys/mod.rs | 5 + lib/api/src/sys/ptr.rs | 18 +- lib/api/src/sys/store.rs | 32 +- lib/api/src/sys/thread.rs | 44 + lib/api/tests/sys_reference_types.rs | 6 +- lib/c-api/src/wasm_c_api/externals/memory.rs | 3 +- lib/c-api/src/wasm_c_api/wasi/mod.rs | 4 +- lib/cli/src/commands/run/wasi.rs | 2 +- .../src/translator/code_translator.rs | 31 +- lib/compiler/src/engine/resolver.rs | 2 +- lib/compiler/src/translator/environ.rs | 9 +- lib/derive/src/value_type.rs | 14 +- lib/emscripten/src/lib.rs | 24 +- lib/emscripten/src/macros.rs | 2 +- lib/emscripten/src/memory.rs | 3 + lib/types/src/error.rs | 4 + lib/types/src/memory.rs | 5 + lib/vbus/src/lib.rs | 190 ++- lib/vm/Cargo.toml | 1 + lib/vm/src/export.rs | 9 +- lib/vm/src/extern_ref.rs | 7 +- lib/vm/src/function_env.rs | 13 +- lib/vm/src/global.rs | 12 + lib/vm/src/instance/mod.rs | 27 +- lib/vm/src/lib.rs | 2 +- lib/vm/src/memory.rs | 143 ++- lib/vm/src/store.rs | 9 +- lib/vm/src/table.rs | 229 +++- lib/vm/src/vmcontext.rs | 60 +- lib/wasi-types/src/bus.rs | 35 +- lib/wasi-types/src/file.rs | 3 + lib/wasi/Cargo.toml | 7 +- lib/wasi/src/lib.rs | 845 ++++++------ lib/wasi/src/macros.rs | 39 +- lib/wasi/src/runtime.rs | 18 +- lib/wasi/src/state/builder.rs | 2 + lib/wasi/src/state/mod.rs | 152 ++- lib/wasi/src/state/types.rs | 26 +- lib/wasi/src/syscalls/legacy/snapshot0.rs | 79 +- lib/wasi/src/syscalls/mod.rs | 1136 ++++++++++++++--- lib/wasi/src/syscalls/wasi.rs | 450 ------- lib/wasi/src/syscalls/wasix32.rs | 1060 --------------- lib/wasi/src/syscalls/wasix64.rs | 1060 --------------- lib/wasi/tests/stdio.rs | 16 +- tests/compilers/imports.rs | 10 +- tests/compilers/issues.rs | 8 +- tests/compilers/metering.rs | 5 +- tests/compilers/native_functions.rs | 18 +- tests/compilers/wast.rs | 2 +- tests/lib/wast/src/wasi_wast.rs | 10 +- 67 files changed, 2956 insertions(+), 3599 deletions(-) create mode 100644 lib/api/src/common/reactors.rs create mode 100644 lib/api/src/js/thread.rs create mode 100644 lib/api/src/sys/thread.rs delete mode 100644 lib/wasi/src/syscalls/wasi.rs delete mode 100644 lib/wasi/src/syscalls/wasix32.rs delete mode 100644 lib/wasi/src/syscalls/wasix64.rs diff --git a/Cargo.lock b/Cargo.lock index 26b7f0fb2b8..048a1b62b51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,15 +54,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" [[package]] name = "arbitrary" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e0a02cf12f1b1f48b14cb7f8217b876d09992b39c816ffb3b1ba64dd979a87" +checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60" dependencies = [ "derive_arbitrary", ] @@ -476,6 +476,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + [[package]] name = "cranelift-bforest" version = "0.82.3" @@ -619,9 +628,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff1f980957787286a554052d03c7aee98d99cc32e09f6d45f0a814133c87978" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -722,9 +731,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8728db27dd9033a7456655aaeb35fde74425d0f130b4cb18a19171ef38a1b454" +checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d" dependencies = [ "proc-macro2", "quote", @@ -893,9 +902,9 @@ dependencies = [ [[package]] name = "erased-serde" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad132dd8d0d0b546348d7d86cb3191aad14b34e5f979781fc005c80d4ac67ffd" +checksum = "81d013529d5574a60caeda29e179e695125448e5de52e3874f7b4c1d7360e18e" dependencies = [ "serde", ] @@ -1129,9 +1138,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6392766afd7964e2531940894cffe4bd8d7d17dbc3c1c4857040fd4b33bdb3" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown 0.12.1", @@ -1707,9 +1716,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -1736,9 +1745,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] @@ -1988,9 +1997,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" [[package]] name = "ryu" @@ -2176,6 +2185,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -2311,9 +2331,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.96" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -2439,6 +2459,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thread-id" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" +dependencies = [ + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -2673,6 +2704,12 @@ dependencies = [ "libc", ] +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "walkdir" version = "2.3.2" @@ -2835,6 +2872,8 @@ dependencies = [ "target-lexicon 0.12.4", "tempfile", "thiserror", + "tracing", + "waker-fn", "wasm-bindgen", "wasm-bindgen-test", "wasmer-compiler", @@ -3146,6 +3185,7 @@ dependencies = [ "cc", "cfg-if 1.0.0", "corosensei", + "derivative", "enum-iterator", "indexmap", "lazy_static", @@ -3189,7 +3229,9 @@ dependencies = [ "getrandom", "libc", "serde", + "sha2", "thiserror", + "thread-id", "tracing", "tracing-wasm", "typetag", diff --git a/docs/migration_to_3.0.0.md b/docs/migration_to_3.0.0.md index fc4f2511530..28faeb778da 100644 --- a/docs/migration_to_3.0.0.md +++ b/docs/migration_to_3.0.0.md @@ -20,7 +20,7 @@ This version introduces the following changes to make the Wasmer API more ergono 1. `ImportsObject` and the traits `Resolver`, `NamedResolver`, etc have been removed and replaced with a single simple type `Imports`. This reduces the complexity of setting up an `Instance`. The helper macro `imports!` can still be used. 2. There is a new `Context` that goes along the `Store`. The `Context` will keep track of all memory and functions used, removing old tracking and Weak/Strong pointer difference. Every function and memory that is retreive is linked to a specific `Context`, and cannot be mixed with another `Context` -3. `WasmerEnv` and associated traits and macro have been removed. To use Environenment, a simple structure now need to be attached to the `Context`, and can be retreive from current `Context`. All functions now takes a mendatory first argument that is of type `ContextMut<_>`, with `_` being either nothing `()` or the Environement type needed. the function creation `XXX_with_env(...)` don't exist anymore, simply use `Function::new(...)` or `Function::native_new(...)` with the correct `ContextMut<_>` type. Because the `WasmerEnv` and all helpers don't exists anymore, you have to import memory yourself, there isn't any per instance initialisation automatically done anymore. It's especialy important for WasiEnv context. `Env` can be accessed from a `Context` using `Context::data()` or `Context::data_mut()`. +3. `WasmerEnv` and associated traits and macro have been removed. To use Environenment, a simple structure now need to be attached to the `Context`, and can be retreive from current `Context`. All functions now takes a mendatory first argument that is of type `ContextMut<_>`, with `_` being either nothing `()` or the Environement type needed. the function creation `XXX_with_env(...)` don't exist anymore, simply use `Function::new(...)` or `Function::native_new(...)` with the correct `ContextMut<_>` type. Because the `WasmerEnv` and all helpers don't exists anymore, you have to import memory yourself, there isn't any per instance initialisation automatically done anymore. It's especialy important for WasiEnv context. `Env` can be accessed from a `Context` using `Context::data()`. 4. The `Engine`s API has been simplified, Instead of the `wasmer` user choosing and setting up an engine explicitly, everything now uses the universal engine. All functionalites of the `staticlib`,`dylib` Engines should be available unless explicitly stated as unsupported. ## How to use Wasmer 3.0.0 diff --git a/examples/imports_function_env.rs b/examples/imports_function_env.rs index b28719fefc4..6cf68842690 100644 --- a/examples/imports_function_env.rs +++ b/examples/imports_function_env.rs @@ -71,7 +71,7 @@ fn main() -> Result<(), Box> { // This struct may have been anything. The only constraint is it must be // possible to know the size of the `Env` at compile time (i.e it has to // implement the `Sized` trait). - // The Env is then accessed using `data()` or `data_mut()` method. + // The Env is then accessed using `data()` method. #[derive(Clone)] struct Env { counter: Arc>, @@ -82,7 +82,7 @@ fn main() -> Result<(), Box> { *env.data().counter.lock().unwrap() } fn add_to_counter(mut env: FunctionEnvMut, add: i32) -> i32 { - let mut counter_ref = env.data_mut().counter.lock().unwrap(); + let mut counter_ref = env.data().counter.lock().unwrap(); *counter_ref += add; *counter_ref diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index db2916ebe03..adf6137e85d 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -26,6 +26,8 @@ indexmap = { version = "1.6", features = ["serde-1"] } cfg-if = "1.0" thiserror = "1.0" more-asserts = "0.2" +tracing = "0.1" +waker-fn = { version = "1.1" } # - Optional shared dependencies. wat = { version = "1.0", optional = true } diff --git a/lib/api/src/common/reactors.rs b/lib/api/src/common/reactors.rs new file mode 100644 index 00000000000..3143e31d80c --- /dev/null +++ b/lib/api/src/common/reactors.rs @@ -0,0 +1,88 @@ +use std::collections::VecDeque; +use std::sync::Mutex; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering; +use std::sync::mpsc; +use std::sync::Arc; +use std::task::Waker; +use std::time::Duration; + +/// Reactor pattern implementation that allows for web assembly +/// processes to easily implement asynchronous IO +#[derive(Debug, Clone)] +pub struct Reactors +{ + waker: Waker, + woken: Arc, + waiting: Arc>>>, +} + +impl Default +for Reactors { + fn default() -> Self { + let woken = Arc::new(AtomicBool::new(false)); + let waiting: Arc>>> = Default::default(); + + let waker = { + let woken = woken.clone(); + let waiting = Arc::downgrade(&waiting); + waker_fn::waker_fn(move || { + if let Some(waiting) = waiting.upgrade() { + let mut guard = waiting.lock().unwrap(); + woken.store(true, Ordering::Release); + if let Some(reactor) = guard.pop_front() { + let _ = reactor.send(()); + } + } + }) + }; + + Self { + waker, + woken, + waiting, + } + } +} + +impl Reactors +{ + /// Gets a reference to the waker that can be used for + /// asynchronous calls + pub fn get_waker(&self) -> Waker { + self.waker.clone() + } + + /// Wakes one of the reactors thats currently waiting + pub fn wake(&self) { + self.waker.wake_by_ref(); + } + + /// Wakes all of the reactors thats currently waiting + pub fn wake_all(&self) { + let mut guard = self.waiting.lock().unwrap(); + self.woken.store(true, Ordering::Release); + guard.clear(); + } + + /// Returns true if woken, otherwise false for timeout + pub fn wait(&self, timeout: Duration) -> bool { + let rx = { + let mut guard = self.waiting.lock().unwrap(); + if self.woken.compare_exchange(true, false, Ordering::AcqRel, Ordering::Acquire).is_ok() { + return true; + } + if timeout.is_zero() { + return false; + } + + let (tx, rx) = mpsc::channel(); + guard.push_back(tx); + rx + }; + match rx.recv_timeout(timeout) { + Ok(_) => true, + Err(_) => false, + } + } +} diff --git a/lib/api/src/js/function_env.rs b/lib/api/src/js/function_env.rs index 81ef590a7c2..0715737c8d9 100644 --- a/lib/api/src/js/function_env.rs +++ b/lib/api/src/js/function_env.rs @@ -93,7 +93,9 @@ impl FunctionEnvMut<'_, T> { } /// Returns a mutable- reference to the host state in this context. - pub fn data_mut<'a>(&'a mut self) -> &'a mut T { + /// (this will only return a mutable reference as long as the environment + /// has not been cloned - environments are cloned during multithreading) + pub fn data_mut<'a>(&'a mut self) -> Option<&'a mut T> { self.func_env.as_mut(&mut self.store_mut) } diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs index 94866e66842..b5f425efdbb 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -9,6 +9,7 @@ use crate::js::types::AsJs; use crate::Extern; use std::collections::HashMap; use std::fmt; +use tracing::trace; /// All of the import data used when instantiating. /// @@ -130,7 +131,11 @@ impl Imports { /// Resolve and return a vector of imports in the order they are defined in the `module`'s source code. /// /// This means the returned `Vec` might be a subset of the imports contained in `self`. - pub fn imports_for_module(&self, module: &Module) -> Result, InstantiationError> { + pub fn imports_for_module( + &self, + _store: &mut impl AsStoreMut, + module: &Module + ) -> Result, InstantiationError> { let mut ret = vec![]; for import in module.imports() { if let Some(imp) = self @@ -139,6 +144,9 @@ impl Imports { { ret.push(imp.clone()); } else { + for (k1, k2) in self.map.keys() { + trace!("import extern ({}, {})", k1, k2); + } return Err(InstantiationError::Link(format!( "Error while importing {0:?}.{1:?}: unknown import. Expected {2:?}", import.module(), @@ -174,6 +182,36 @@ impl Imports { } imports } + + /// Iterates through all the imports in this structure + pub fn iter<'a>(&'a self) -> ImportsIterator<'a> { + ImportsIterator::new(self) + } +} + +pub struct ImportsIterator<'a> { + iter: std::collections::hash_map::Iter<'a, (String, String), Extern> +} + +impl<'a> ImportsIterator<'a> +{ + fn new(imports: &'a Imports) -> Self { + let iter = imports.map.iter(); + Self { iter } + } +} + +impl<'a> Iterator +for ImportsIterator<'a> { + type Item = (&'a str, &'a str, &'a Extern); + + fn next(&mut self) -> Option { + self.iter + .next() + .map(|(k, v)| { + (k.0.as_str(), k.1.as_str(), v) + }) + } } impl IntoIterator for &Imports { diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 6d2762adf66..e7675985dec 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -5,8 +5,12 @@ use crate::js::externals::Extern; use crate::js::imports::Imports; use crate::js::module::Module; use crate::js::store::{AsStoreMut, AsStoreRef, StoreHandle}; +use crate::js::thread::ThreadControl; +use crate::js::Reactors; use js_sys::WebAssembly; use std::fmt; +use std::sync::Arc; +use std::atomic::{AtomicU32, Ordering}; /// A WebAssembly Instance is a stateful, executable /// instance of a WebAssembly [`Module`]. @@ -19,8 +23,10 @@ use std::fmt; #[derive(Clone)] pub struct Instance { _handle: StoreHandle, + thread_seed: Arc, module: Module, - #[allow(dead_code)] + /// Reactors are used to wake up the program + pub reactors: Reactors, imports: Imports, /// The exports for an instance. pub exports: Exports, @@ -112,6 +118,8 @@ impl Instance { Ok(Self { _handle: instance, + thread_seed: Arc::new(AtomicU32::new(0)), + reactors: Default::default(), module: module.clone(), imports, exports, @@ -131,6 +139,33 @@ impl Instance { ) -> &'context WebAssembly::Instance { &self._handle.get(store.as_store_ref().objects()) } + + #[doc(hidden)] + pub fn resolve<'a, T, Args, Rets>(&'a self, name: &str) -> Result + where + Args: crate::WasmTypeList, + Rets: crate::WasmTypeList, + T: super::exports::ExportableWithGenerics<'a, Args, Rets>, + { + match self.exports.get_with_generics_weak(name) { + Ok(a) => Ok(a), + Err(crate::ExportError::Missing(a)) if a == "memory" => { + for (_, _, import) in self.imports.iter() { + if let Extern::Memory(_) = import { + return T::get_self_from_extern_with_generics(import); + } + } + Err(crate::ExportError::Missing("memory".to_string())) + } + Err(err) => Err(err) + } + } + + /// Creates a a thread and returns it + pub fn new_thread(&self) -> ThreadControl { + let id = self.thread_seed.fetch_add(1, Ordering::AcqRel) + 1; + ThreadControl::new(id) + } } impl fmt::Debug for Instance { diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 9863123c55b..966226adb3b 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -43,6 +43,9 @@ mod trap; mod types; mod value; mod wasm_bindgen_polyfill; +mod thread; +#[path = "../common/reactors.rs"] +mod reactors; pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError}; pub use crate::js::export::Export; @@ -61,6 +64,8 @@ pub use crate::js::native::TypedFunction; pub use crate::js::native_type::NativeWasmTypeInto; pub use crate::js::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use crate::js::trap::RuntimeError; +pub use crate::js::thread::ThreadControl; +pub use crate::js::reactors::Reactors; pub use crate::js::store::{ AsStoreMut, AsStoreRef, Store, StoreHandle, StoreMut, StoreObject, StoreObjects, StoreRef, diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 209f46dfd46..9b1833d93fc 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -21,6 +21,7 @@ use wasmer_types::{ ExportsIterator, ExternType, FunctionType, GlobalType, ImportsIterator, MemoryType, Mutability, Pages, TableType, Type, }; +use tracing::{warn}; #[derive(Debug)] #[cfg_attr(feature = "std", derive(Error))] @@ -261,6 +262,8 @@ impl Module { )?; } import_externs.push(import); + } else { + warn!("import not found {}:{}", import_type.module(), import_type.name()); } // in case the import is not found, the JS Wasm VM will handle // the error for us, so we don't need to handle it diff --git a/lib/api/src/js/thread.rs b/lib/api/src/js/thread.rs new file mode 100644 index 00000000000..8e74badc5ab --- /dev/null +++ b/lib/api/src/js/thread.rs @@ -0,0 +1,44 @@ +use std::{sync::{Arc, mpsc, Mutex}, time::Duration}; + +/// Contains controls for the instance +#[derive(Debug, Clone)] +pub struct ThreadControl { + id: u32, + /// Signalers used to tell joiners that the thread has exited + exit: Arc>>>, + /// Event to wait on for the thread to join + join: Arc>>, +} + +impl ThreadControl { + /// Creates a thread control object the a specific unique identifier + pub fn new(id: u32) -> ThreadControl { + let (tx, rx) = mpsc::channel(); + ThreadControl { + id, + exit: Arc::new(Mutex::new(Some(tx))), + join: Arc::new(Mutex::new(rx)), + } + } + + /// Returns the unique ID of this thread + pub fn id(&self) -> u32 { + self.id + } + + /// Makes the instance thread that its exited + pub fn mark_exited(&self) { + let mut guard = self.exit.lock().unwrap(); + guard.take(); + } + + /// Waits for the thread to exit (false = timeout) + pub fn join(&self, timeout: Duration) -> bool { + let guard = self.join.lock().unwrap(); + match guard.recv_timeout(timeout) { + Ok(_) => true, + Err(mpsc::RecvTimeoutError::Disconnected) => true, + Err(mpsc::RecvTimeoutError::Timeout) => false, + } + } +} \ No newline at end of file diff --git a/lib/api/src/sys/externals/function.rs b/lib/api/src/sys/externals/function.rs index c317b9648ca..56f30b288e8 100644 --- a/lib/api/src/sys/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -11,6 +11,7 @@ pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList}; use std::cell::UnsafeCell; use std::cmp::max; use std::ffi::c_void; +use std::sync::Arc; use wasmer_types::RawValue; use wasmer_vm::{ on_host_stack, raise_user_trap, resume_panic, wasmer_call_trampoline, InternalStoreHandle, @@ -123,11 +124,12 @@ impl Function { } Ok(()) }; - let mut host_data = Box::new(VMDynamicFunctionContext { + let mut host_data = VMDynamicFunctionContext { address: std::ptr::null(), ctx: DynamicFunction { func: wrapper }, - }); + }; host_data.address = host_data.ctx.func_body_ptr(); + let host_data = Arc::new(host_data); // We don't yet have the address with the Wasm ABI signature. // The engine linker will replace the address with one pointing to a @@ -149,10 +151,10 @@ impl Function { }; let vm_function = VMFunction { - anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))), + anyfunc: Arc::new(MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc)))), kind: VMFunctionKind::Dynamic, signature: function_type, - host_data, + host_data: Arc::new(host_data), }; Self { handle: StoreHandle::new(store.as_store_mut().objects_mut(), vm_function), @@ -189,7 +191,7 @@ impl Function { { // println!("new native {:p}", &new_env); - let host_data = Box::new(StaticFunction { + let host_data = Arc::new(StaticFunction { raw_store: store.as_store_mut().as_raw() as *mut u8, env: env.clone(), func, @@ -213,7 +215,7 @@ impl Function { }; let vm_function = VMFunction { - anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))), + anyfunc: Arc::new(MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc)))), kind: VMFunctionKind::Static, signature: function_type, host_data, @@ -429,12 +431,12 @@ impl Function { .lookup_signature(funcref.0.as_ref().type_index) .expect("Signature not found in store"); let vm_function = VMFunction { - anyfunc: MaybeInstanceOwned::Instance(funcref.0), + anyfunc: Arc::new(MaybeInstanceOwned::Instance(funcref.0)), signature, // All functions in tables are already Static (as dynamic functions // are converted to use the trampolines with static signatures). kind: wasmer_vm::VMFunctionKind::Static, - host_data: Box::new(()), + host_data: Arc::new(()), }; Self { handle: StoreHandle::new(store.as_store_mut().objects_mut(), vm_function), diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index 93ae55f1769..5a9c07abb85 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -9,7 +9,7 @@ use std::mem; use std::mem::MaybeUninit; use std::slice; use wasmer_types::Pages; -use wasmer_vm::{InternalStoreHandle, MemoryError, StoreHandle, StoreObjects, VMExtern, VMMemory}; +use wasmer_vm::{InternalStoreHandle, MemoryError, StoreHandle, StoreObjects, VMExtern, VMMemory, VMMemoryView}; /// A WebAssembly `memory` instance. /// @@ -72,47 +72,6 @@ impl Memory { self.handle.get(store.as_store_ref().objects()).ty() } - /// Returns the pointer to the raw bytes of the `Memory`. - // - // This used by wasmer-emscripten and wasmer-c-api, but should be treated - // as deprecated and not used in future code. - #[doc(hidden)] - pub fn data_ptr(&self, store: &impl AsStoreRef) -> *mut u8 { - self.buffer(store).base - } - - /// Returns the size (in bytes) of the `Memory`. - pub fn data_size(&self, store: &impl AsStoreRef) -> u64 { - self.buffer(store).len.try_into().unwrap() - } - - /// Retrieve a slice of the memory contents. - /// - /// # Safety - /// - /// Until the returned slice is dropped, it is undefined behaviour to - /// modify the memory contents in any way including by calling a wasm - /// function that writes to the memory or by resizing the memory. - #[doc(hidden)] - pub unsafe fn data_unchecked(&self, store: &impl AsStoreRef) -> &[u8] { - self.data_unchecked_mut(store) - } - - /// Retrieve a mutable slice of the memory contents. - /// - /// # Safety - /// - /// This method provides interior mutability without an UnsafeCell. Until - /// the returned value is dropped, it is undefined behaviour to read or - /// write to the pointed-to memory in any way except through this slice, - /// including by calling a wasm function that reads the memory contents or - /// by resizing this Memory. - #[allow(clippy::mut_from_ref)] - #[doc(hidden)] - pub unsafe fn data_unchecked_mut(&self, store: &impl AsStoreRef) -> &mut [u8] { - slice::from_raw_parts_mut(self.buffer(store).base, self.buffer(store).len) - } - /// Returns the size (in [`Pages`]) of the `Memory`. /// /// # Example @@ -172,61 +131,13 @@ impl Memory { self.handle.get_mut(store.objects_mut()).grow(delta.into()) } - /// Safely reads bytes from the memory at the given offset. - /// - /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned - /// to indicate an out-of-bounds access. - /// - /// This method is guaranteed to be safe (from the host side) in the face of - /// concurrent writes. - pub fn read( - &self, - store: &impl AsStoreRef, - offset: u64, - buf: &mut [u8], - ) -> Result<(), MemoryAccessError> { - self.buffer(store).read(offset, buf) - } - - /// Safely reads bytes from the memory at the given offset. - /// - /// This method is similar to `read` but allows reading into an - /// uninitialized buffer. An initialized view of the buffer is returned. - /// - /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned - /// to indicate an out-of-bounds access. - /// - /// This method is guaranteed to be safe (from the host side) in the face of - /// concurrent writes. - pub fn read_uninit<'a>( - &self, - store: &impl AsStoreRef, - offset: u64, - buf: &'a mut [MaybeUninit], - ) -> Result<&'a mut [u8], MemoryAccessError> { - self.buffer(store).read_uninit(offset, buf) - } - - /// Safely writes bytes to the memory at the given offset. - /// - /// If the write exceeds the bounds of the memory then a `MemoryAccessError` is - /// returned. - /// - /// This method is guaranteed to be safe (from the host side) in the face of - /// concurrent reads/writes. - pub fn write( - &self, - store: &impl AsStoreRef, - offset: u64, - data: &[u8], - ) -> Result<(), MemoryAccessError> { - self.buffer(store).write(offset, data) - } - - pub(crate) fn buffer<'a>(&'a self, store: &'a impl AsStoreRef) -> MemoryBuffer<'a> { - let definition = self.handle.get(store.as_store_ref().objects()).vmmemory(); - let def = unsafe { definition.as_ref() }; - MemoryBuffer { + /// In order to access the memory you must first lock it + /// (this will prevent it from growing) + pub fn lock<'a>(&'a self, store: &'a impl AsStoreRef) -> MemoryGuard<'a> { + let view = self.handle.get(store.as_store_ref().objects()).vmmemory(); + let def = unsafe { view.as_ref() }; + MemoryGuard { + _view: view, base: def.base, len: def.current_length, marker: PhantomData, @@ -272,15 +183,23 @@ impl<'a> Exportable<'a> for Memory { } /// Underlying buffer for a memory. -#[derive(Copy, Clone)] -pub(crate) struct MemoryBuffer<'a> { +#[derive(Clone)] +pub struct MemoryGuard<'a> { + _view: VMMemoryView<'a>, base: *mut u8, len: usize, marker: PhantomData<(&'a Memory, &'a StoreObjects)>, } -impl<'a> MemoryBuffer<'a> { - pub(crate) fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> { +impl<'a> MemoryGuard<'a> { + /// Safely reads bytes from the memory at the given offset. + /// + /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned + /// to indicate an out-of-bounds access. + /// + /// This method is guaranteed to be safe (from the host side) in the face of + /// concurrent writes. + pub fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> { let end = offset .checked_add(buf.len() as u64) .ok_or(MemoryAccessError::Overflow)?; @@ -293,7 +212,17 @@ impl<'a> MemoryBuffer<'a> { Ok(()) } - pub(crate) fn read_uninit<'b>( + /// Safely reads bytes from the memory at the given offset. + /// + /// This method is similar to `read` but allows reading into an + /// uninitialized buffer. An initialized view of the buffer is returned. + /// + /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned + /// to indicate an out-of-bounds access. + /// + /// This method is guaranteed to be safe (from the host side) in the face of + /// concurrent writes. + pub fn read_uninit<'b>( &self, offset: u64, buf: &'b mut [MaybeUninit], @@ -312,7 +241,14 @@ impl<'a> MemoryBuffer<'a> { Ok(unsafe { slice::from_raw_parts_mut(buf_ptr, buf.len()) }) } - pub(crate) fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> { + /// Safely writes bytes to the memory at the given offset. + /// + /// If the write exceeds the bounds of the memory then a `MemoryAccessError` is + /// returned. + /// + /// This method is guaranteed to be safe (from the host side) in the face of + /// concurrent reads/writes. + pub fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> { let end = offset .checked_add(data.len() as u64) .ok_or(MemoryAccessError::Overflow)?; @@ -324,6 +260,47 @@ impl<'a> MemoryBuffer<'a> { } Ok(()) } + + /// Retrieve a mutable slice of the memory contents. + /// + /// # Safety + /// + /// This method provides interior mutability without an UnsafeCell. Until + /// the returned value is dropped, it is undefined behaviour to read or + /// write to the pointed-to memory in any way except through this slice, + /// including by calling a wasm function that reads the memory contents or + /// by resizing this Memory. + #[allow(clippy::mut_from_ref)] + #[doc(hidden)] + pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] { + slice::from_raw_parts_mut(self.base, self.len) + } + + /// Returns the pointer to the raw bytes of the `Memory`. + // + // This used by wasmer-emscripten and wasmer-c-api, but should be treated + // as deprecated and not used in future code. + #[doc(hidden)] + pub fn data_ptr(&self) -> *mut u8 { + self.base + } + + /// Returns the size (in bytes) of the `Memory`. + pub fn data_size(&self) -> u64 { + self.len.try_into().unwrap() + } + + /// Retrieve a slice of the memory contents. + /// + /// # Safety + /// + /// Until the returned slice is dropped, it is undefined behaviour to + /// modify the memory contents in any way including by calling a wasm + /// function that writes to the memory or by resizing the memory. + #[doc(hidden)] + pub unsafe fn data_unchecked(&self) -> &[u8] { + self.data_unchecked_mut() + } } // We can't use a normal memcpy here because it has undefined behavior if the diff --git a/lib/api/src/sys/function_env.rs b/lib/api/src/sys/function_env.rs index 0dde57ea78c..d0f9214b47a 100644 --- a/lib/api/src/sys/function_env.rs +++ b/lib/api/src/sys/function_env.rs @@ -2,7 +2,7 @@ use std::{any::Any, marker::PhantomData}; use wasmer_vm::{StoreHandle, StoreObjects, VMFunctionEnvironment}; -use crate::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; +use crate::{AsStoreMut, AsStoreRef, StoreMut, StoreRef, Store}; #[derive(Debug)] #[repr(transparent)] @@ -29,7 +29,7 @@ impl FunctionEnv { } /// Get the data as reference - pub fn as_ref<'a>(&self, store: &'a impl AsStoreMut) -> &'a T + pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T where T: Any + Send + 'static + Sized, { @@ -40,16 +40,18 @@ impl FunctionEnv { .unwrap() } - /// Get the data as mutable - pub fn as_mut<'a>(&self, store: &'a mut impl AsStoreMut) -> &'a mut T + /// Get the data as mutable reference + /// (this will only return a mutable reference as long as the environment + /// has not been cloned - environments are cloned during multithreading) + pub fn as_mut<'a>(&mut self, store: &'a mut impl AsStoreMut) -> Option<&'a mut T> where T: Any + Send + 'static + Sized, { self.handle .get_mut(store.objects_mut()) .as_mut() - .downcast_mut::() - .unwrap() + .map(|a| a.downcast_mut::()) + .flatten() } /// Convert it into a `FunctionEnvMut` @@ -85,8 +87,10 @@ impl FunctionEnvMut<'_, T> { self.func_env.as_ref(&self.store_mut) } - /// Returns a mutable- reference to the host state in this function environement. - pub fn data_mut(&mut self) -> &mut T { + /// Returns a mutable- reference to the host state in this context. + /// (this will only return a mutable reference as long as the environment + /// has not been cloned - environments are cloned during multithreading) + pub fn data_mut<'a>(&'a mut self) -> Option<&'a mut T> { self.func_env.as_mut(&mut self.store_mut) } @@ -97,6 +101,11 @@ impl FunctionEnvMut<'_, T> { func_env: self.func_env.clone(), } } + + /// Clones the store thats within this environment and returns it + pub fn clone_store(&mut self) -> Store { + self.store_mut.clone_store() + } } impl AsStoreRef for FunctionEnvMut<'_, T> { diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index 98fdc848c5b..3484555214c 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -1,11 +1,12 @@ //! The import module contains the implementation data structures and helper functions used to //! manipulate and access a wasm module's imports including memories, tables, globals, and //! functions. -use crate::{Exports, Extern, Module}; +use crate::{Exports, Extern, Module, Memory, AsStoreMut}; use std::collections::HashMap; use std::fmt; use wasmer_compiler::LinkError; use wasmer_types::ImportError; +use tracing::trace; /// All of the import data used when instantiating. /// @@ -132,7 +133,11 @@ impl Imports { /// Resolve and return a vector of imports in the order they are defined in the `module`'s source code. /// /// This means the returned `Vec` might be a subset of the imports contained in `self`. - pub fn imports_for_module(&self, module: &Module) -> Result, LinkError> { + pub fn imports_for_module( + &self, + store: &mut impl AsStoreMut, + module: &Module + ) -> Result, LinkError> { let mut ret = vec![]; for import in module.imports() { if let Some(imp) = self @@ -140,7 +145,20 @@ impl Imports { .get(&(import.module().to_string(), import.name().to_string())) { ret.push(imp.clone()); + } else if let wasmer_types::ExternType::Memory(mem_ty) = import.ty() { + ret.push(Extern::Memory(Memory::new(store, mem_ty.clone()) + .map_err(|err| { + LinkError::Import( + import.module().to_string(), + import.name().to_string(), + ImportError::MemoryError(err.to_string()), + ) + })? + )); } else { + for (k1, k2) in self.map.keys() { + trace!("import extern ({}, {})", k1, k2); + } return Err(LinkError::Import( import.module().to_string(), import.name().to_string(), @@ -150,6 +168,36 @@ impl Imports { } Ok(ret) } + + /// Iterates through all the imports in this structure + pub fn iter<'a>(&'a self) -> ImportsIterator<'a> { + ImportsIterator::new(self) + } +} + +pub struct ImportsIterator<'a> { + iter: std::collections::hash_map::Iter<'a, (String, String), Extern> +} + +impl<'a> ImportsIterator<'a> +{ + fn new(imports: &'a Imports) -> Self { + let iter = imports.map.iter(); + Self { iter } + } +} + +impl<'a> Iterator +for ImportsIterator<'a> { + type Item = (&'a str, &'a str, &'a Extern); + + fn next(&mut self) -> Option { + self.iter + .next() + .map(|(k, v)| { + (k.0.as_str(), k.1.as_str(), v) + }) + } } impl IntoIterator for &Imports { diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index ae1b1118f0f..e620881ee83 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -1,3 +1,4 @@ +use crate::Reactors; use crate::sys::exports::Exports; use crate::sys::externals::Extern; use crate::sys::imports::Imports; @@ -21,6 +22,8 @@ use super::store::AsStoreMut; pub struct Instance { _handle: StoreHandle, module: Module, + /// Reactors are used to wake up the program + pub reactors: Reactors, /// The exports for an instance. pub exports: Exports, } @@ -115,7 +118,7 @@ impl Instance { imports: &Imports, ) -> Result { let imports = imports - .imports_for_module(module) + .imports_for_module(store, module) .map_err(InstantiationError::Link)?; let mut handle = module.instantiate(store, &imports)?; let exports = module @@ -130,6 +133,7 @@ impl Instance { let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), + reactors: Default::default(), module: module.clone(), exports, }; @@ -166,6 +170,7 @@ impl Instance { let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), + reactors: Default::default(), module: module.clone(), exports, }; diff --git a/lib/api/src/sys/mem_access.rs b/lib/api/src/sys/mem_access.rs index 270e1728c9a..6575226d510 100644 --- a/lib/api/src/sys/mem_access.rs +++ b/lib/api/src/sys/mem_access.rs @@ -12,7 +12,7 @@ use std::{ use thiserror::Error; use wasmer_types::ValueType; -use super::externals::memory::MemoryBuffer; +use super::externals::memory::MemoryGuard; use super::store::AsStoreRef; /// Error for invalid [`Memory`] access. @@ -52,9 +52,9 @@ impl From for MemoryAccessError { /// /// This wrapper safely handles concurrent modifications of the data by another /// thread. -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct WasmRef<'a, T: ValueType> { - buffer: MemoryBuffer<'a>, + buffer: MemoryGuard<'a>, offset: u64, marker: PhantomData<*mut T>, } @@ -64,7 +64,7 @@ impl<'a, T: ValueType> WasmRef<'a, T> { #[inline] pub fn new(store: &'a impl AsStoreRef, memory: &'a Memory, offset: u64) -> Self { Self { - buffer: memory.buffer(store), + buffer: memory.lock(store), offset, marker: PhantomData, } @@ -72,25 +72,25 @@ impl<'a, T: ValueType> WasmRef<'a, T> { /// Get the offset into Wasm linear memory for this `WasmRef`. #[inline] - pub fn offset(self) -> u64 { + pub fn offset(&self) -> u64 { self.offset } /// Get a `WasmPtr` for this `WasmRef`. #[inline] - pub fn as_ptr32(self) -> WasmPtr { + pub fn as_ptr32(&self) -> WasmPtr { WasmPtr::new(self.offset as u32) } /// Get a 64-bit `WasmPtr` for this `WasmRef`. #[inline] - pub fn as_ptr64(self) -> WasmPtr { + pub fn as_ptr64(&self) -> WasmPtr { WasmPtr::new(self.offset) } /// Get a `WasmPtr` fror this `WasmRef`. #[inline] - pub fn as_ptr(self) -> WasmPtr { + pub fn as_ptr(&self) -> WasmPtr { let offset: M::Offset = self .offset .try_into() @@ -101,7 +101,7 @@ impl<'a, T: ValueType> WasmRef<'a, T> { /// Reads the location pointed to by this `WasmRef`. #[inline] - pub fn read(self) -> Result { + pub fn read(&self) -> Result { let mut out = MaybeUninit::uninit(); let buf = unsafe { slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::()) }; @@ -111,7 +111,7 @@ impl<'a, T: ValueType> WasmRef<'a, T> { /// Writes to the location pointed to by this `WasmRef`. #[inline] - pub fn write(self, val: T) -> Result<(), MemoryAccessError> { + pub fn write(&self, val: T) -> Result<(), MemoryAccessError> { let mut data = MaybeUninit::new(val); let data = unsafe { slice::from_raw_parts_mut( @@ -146,9 +146,9 @@ impl<'a, T: ValueType> fmt::Debug for WasmRef<'a, T> { /// /// This wrapper safely handles concurrent modifications of the data by another /// thread. -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct WasmSlice<'a, T: ValueType> { - buffer: MemoryBuffer<'a>, + view: MemoryGuard<'a>, offset: u64, len: u64, marker: PhantomData<*mut T>, @@ -173,7 +173,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { .checked_add(total_len) .ok_or(MemoryAccessError::Overflow)?; Ok(Self { - buffer: memory.buffer(store), + view: memory.lock(store), offset, len, marker: PhantomData, @@ -182,43 +182,43 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { /// Get the offset into Wasm linear memory for this `WasmSlice`. #[inline] - pub fn offset(self) -> u64 { + pub fn offset(&self) -> u64 { self.offset } /// Get a 32-bit `WasmPtr` for this `WasmRef`. #[inline] - pub fn as_ptr32(self) -> WasmPtr { + pub fn as_ptr32(&self) -> WasmPtr { WasmPtr::new(self.offset as u32) } /// Get a 64-bit `WasmPtr` for this `WasmRef`. #[inline] - pub fn as_ptr64(self) -> WasmPtr { + pub fn as_ptr64(&self) -> WasmPtr { WasmPtr::new(self.offset) } /// Get the number of elements in this slice. #[inline] - pub fn len(self) -> u64 { + pub fn len(&self) -> u64 { self.len } /// Returns `true` if the number of elements is 0. #[inline] - pub fn is_empty(self) -> bool { + pub fn is_empty(&self) -> bool { self.len == 0 } /// Get a `WasmRef` to an element in the slice. #[inline] - pub fn index(self, idx: u64) -> WasmRef<'a, T> { + pub fn index(&self, idx: u64) -> WasmRef<'a, T> { if idx >= self.len { panic!("WasmSlice out of bounds"); } let offset = self.offset + idx * mem::size_of::() as u64; WasmRef { - buffer: self.buffer, + buffer: self.view.clone(), offset, marker: PhantomData, } @@ -226,13 +226,13 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { /// Get a `WasmSlice` for a subslice of this slice. #[inline] - pub fn subslice(self, range: Range) -> WasmSlice<'a, T> { + pub fn subslice(&self, range: Range) -> WasmSlice<'a, T> { if range.start > range.end || range.end > self.len { panic!("WasmSlice out of bounds"); } let offset = self.offset + range.start * mem::size_of::() as u64; Self { - buffer: self.buffer, + view: self.view.clone(), offset, len: range.end - range.start, marker: PhantomData, @@ -241,19 +241,19 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { /// Get an iterator over the elements in this slice. #[inline] - pub fn iter(self) -> WasmSliceIter<'a, T> { - WasmSliceIter { slice: self } + pub fn iter(&self) -> WasmSliceIter<'a, T> { + WasmSliceIter { slice: self.clone() } } /// Reads an element of this slice. #[inline] - pub fn read(self, idx: u64) -> Result { + pub fn read(&self, idx: u64) -> Result { self.index(idx).read() } /// Writes to an element of this slice. #[inline] - pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> { + pub fn write(&self, idx: u64, val: T) -> Result<(), MemoryAccessError> { self.index(idx).write(val) } @@ -261,7 +261,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { /// /// The length of the buffer must match the length of the slice. #[inline] - pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> { + pub fn read_slice(&self, buf: &mut [T]) -> Result<(), MemoryAccessError> { assert_eq!( buf.len() as u64, self.len, @@ -273,7 +273,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { buf.len() * mem::size_of::(), ) }; - self.buffer.read_uninit(self.offset, bytes)?; + self.view.read_uninit(self.offset, bytes)?; Ok(()) } @@ -284,7 +284,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { /// This method returns an initialized view of the buffer. #[inline] pub fn read_slice_uninit( - self, + &self, buf: &mut [MaybeUninit], ) -> Result<&mut [T], MemoryAccessError> { assert_eq!( @@ -298,7 +298,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { buf.len() * mem::size_of::(), ) }; - self.buffer.read_uninit(self.offset, bytes)?; + self.view.read_uninit(self.offset, bytes)?; Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) }) } @@ -306,7 +306,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { /// /// The length of the slice must match the length of the `WasmSlice`. #[inline] - pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> { + pub fn write_slice(&self, data: &[T]) -> Result<(), MemoryAccessError> { assert_eq!( data.len() as u64, self.len, @@ -315,12 +315,12 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { let bytes = unsafe { slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) }; - self.buffer.write(self.offset, bytes) + self.view.write(self.offset, bytes) } /// Reads this `WasmSlice` into a `Vec`. #[inline] - pub fn read_to_vec(self) -> Result, MemoryAccessError> { + pub fn read_to_vec(&self) -> Result, MemoryAccessError> { let len = self.len.try_into().expect("WasmSlice length overflow"); let mut vec = Vec::with_capacity(len); let bytes = unsafe { @@ -329,7 +329,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> { len * mem::size_of::(), ) }; - self.buffer.read_uninit(self.offset, bytes)?; + self.view.read_uninit(self.offset, bytes)?; unsafe { vec.set_len(len); } diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 9eca8454d15..4326b780b70 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -12,6 +12,9 @@ mod ptr; mod store; mod tunables; mod value; +mod thread; +#[path = "../common/reactors.rs"] +mod reactors; pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use crate::sys::extern_ref::ExternRef; @@ -26,6 +29,8 @@ pub use crate::sys::module::Module; pub use crate::sys::native::TypedFunction; pub use crate::sys::native_type::NativeWasmTypeInto; pub use crate::sys::store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; +pub use crate::sys::thread::ThreadControl; +pub use crate::sys::reactors::Reactors; pub use crate::sys::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use crate::sys::store::Store; diff --git a/lib/api/src/sys/ptr.rs b/lib/api/src/sys/ptr.rs index d0ebdade26a..4141552338d 100644 --- a/lib/api/src/sys/ptr.rs +++ b/lib/api/src/sys/ptr.rs @@ -76,7 +76,7 @@ impl WasmPtr { /// Get the offset into Wasm linear memory for this `WasmPtr`. #[inline] - pub fn offset(self) -> M::Offset { + pub fn offset(&self) -> M::Offset { self.offset } @@ -97,7 +97,7 @@ impl WasmPtr { /// Checks whether the `WasmPtr` is null. #[inline] - pub fn is_null(self) -> bool { + pub fn is_null(&self) -> bool { self.offset.into() == 0 } @@ -142,20 +142,20 @@ impl WasmPtr { /// Creates a `WasmRef` from this `WasmPtr` which allows reading and /// mutating of the value being pointed to. #[inline] - pub fn deref<'a>(self, store: &'a impl AsStoreRef, memory: &'a Memory) -> WasmRef<'a, T> { + pub fn deref<'a>(&self, store: &'a impl AsStoreRef, memory: &'a Memory) -> WasmRef<'a, T> { WasmRef::new(store, memory, self.offset.into()) } /// Reads the address pointed to by this `WasmPtr` in a memory. #[inline] - pub fn read(self, store: &impl AsStoreRef, memory: &Memory) -> Result { + pub fn read(&self, store: &impl AsStoreRef, memory: &Memory) -> Result { self.deref(&store, memory).read() } /// Writes to the address pointed to by this `WasmPtr` in a memory. #[inline] pub fn write( - self, + &self, store: &impl AsStoreRef, memory: &Memory, val: T, @@ -170,7 +170,7 @@ impl WasmPtr { /// address. #[inline] pub fn slice<'a>( - self, + &self, store: &'a impl AsStoreRef, memory: &'a Memory, len: M::Offset, @@ -184,7 +184,7 @@ impl WasmPtr { /// This last value is not included in the returned vector. #[inline] pub fn read_until( - self, + &self, store: &impl AsStoreRef, memory: &Memory, mut end: impl FnMut(&T) -> bool, @@ -209,7 +209,7 @@ impl WasmPtr { /// modified. #[inline] pub fn read_utf8_string( - self, + &self, store: &impl AsStoreRef, memory: &Memory, len: M::Offset, @@ -224,7 +224,7 @@ impl WasmPtr { /// modified. #[inline] pub fn read_utf8_string_with_nul( - self, + &self, store: &impl AsStoreRef, memory: &Memory, ) -> Result { diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index bf0fce4b5d6..6ab8e25180e 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -1,5 +1,6 @@ use crate::sys::tunables::BaseTunables; use std::fmt; +use std::ops::Deref; use std::sync::Arc; use wasmer_compiler::CompilerConfig; use wasmer_compiler::{Engine, Tunables, Universal}; @@ -10,11 +11,20 @@ use wasmer_vm::StoreObjects; /// We require the context to have a fixed memory address for its lifetime since /// various bits of the VM have raw pointers that point back to it. Hence we /// wrap the actual context in a box. +#[derive(Clone)] pub(crate) struct StoreInner { pub(crate) objects: StoreObjects, pub(crate) engine: Arc, - pub(crate) tunables: Box, - pub(crate) trap_handler: Option>>, + pub(crate) tunables: Arc, + pub(crate) trap_handler: Option>>, +} + +impl StoreInner +{ + /// Freezes the tables so that copying is a shallow copy rather than full copy + pub(crate) fn freeze(&mut self) { + self.objects.freeze(); + } } /// The store represents all global state that can be manipulated by @@ -43,11 +53,12 @@ impl Store { where E: Engine + ?Sized, { - Self::new_with_tunables(engine, BaseTunables::for_target(engine.target())) + let ret = Self::new_with_tunables(engine, BaseTunables::for_target(engine.target())); + ret } /// Set the trap handler in this store. - pub fn set_trap_handler(&mut self, handler: Option>>) { + pub fn set_trap_handler(&mut self, handler: Option>>) { self.inner.trap_handler = handler; } @@ -64,7 +75,7 @@ impl Store { inner: Box::new(StoreInner { objects: Default::default(), engine: engine.cloned(), - tunables: Box::new(tunables), + tunables: Arc::new(tunables), trap_handler: None, }), } @@ -178,7 +189,7 @@ impl<'a> StoreRef<'a> { self.inner .trap_handler .as_ref() - .map(|handler| &*handler as *const _) + .map(|handler| handler.deref() as *const _) } } @@ -198,6 +209,15 @@ impl<'a> StoreMut<'a> { &self.inner.engine } + /// Clones the store, before its cloned COW operations (freeze) are performed + /// so that its a shallow copy + pub fn clone_store(&mut self) -> Store { + self.inner.freeze(); + Store { + inner: Box::new(self.inner.clone()) + } + } + /// Checks whether two stores are identical. A store is considered /// equal to another store if both have the same engine. The /// tunables are excluded from the logic. diff --git a/lib/api/src/sys/thread.rs b/lib/api/src/sys/thread.rs new file mode 100644 index 00000000000..8e74badc5ab --- /dev/null +++ b/lib/api/src/sys/thread.rs @@ -0,0 +1,44 @@ +use std::{sync::{Arc, mpsc, Mutex}, time::Duration}; + +/// Contains controls for the instance +#[derive(Debug, Clone)] +pub struct ThreadControl { + id: u32, + /// Signalers used to tell joiners that the thread has exited + exit: Arc>>>, + /// Event to wait on for the thread to join + join: Arc>>, +} + +impl ThreadControl { + /// Creates a thread control object the a specific unique identifier + pub fn new(id: u32) -> ThreadControl { + let (tx, rx) = mpsc::channel(); + ThreadControl { + id, + exit: Arc::new(Mutex::new(Some(tx))), + join: Arc::new(Mutex::new(rx)), + } + } + + /// Returns the unique ID of this thread + pub fn id(&self) -> u32 { + self.id + } + + /// Makes the instance thread that its exited + pub fn mark_exited(&self) { + let mut guard = self.exit.lock().unwrap(); + guard.take(); + } + + /// Waits for the thread to exit (false = timeout) + pub fn join(&self, timeout: Duration) -> bool { + let guard = self.join.lock().unwrap(); + match guard.recv_timeout(timeout) { + Ok(_) => true, + Err(mpsc::RecvTimeoutError::Disconnected) => true, + Err(mpsc::RecvTimeoutError::Timeout) => false, + } + } +} \ No newline at end of file diff --git a/lib/api/tests/sys_reference_types.rs b/lib/api/tests/sys_reference_types.rs index 24eb03f1137..2f8f4582d47 100644 --- a/lib/api/tests/sys_reference_types.rs +++ b/lib/api/tests/sys_reference_types.rs @@ -44,15 +44,15 @@ mod sys { } let func_to_call = - Function::new_native(&mut store, &env, |mut env: FunctionEnvMut| -> i32 { - env.data_mut().0.store(true, Ordering::SeqCst); + Function::new_native(&mut store, &env, |env: FunctionEnvMut| -> i32 { + env.data().0.store(true, Ordering::SeqCst); 343 }); let call_set_value: &Function = instance.exports.get_function("call_set_value")?; let results: Box<[Value]> = call_set_value.call(&mut store, &[Value::FuncRef(Some(func_to_call))])?; assert!(env - .as_mut(&mut store.as_store_mut()) + .as_ref(&store.as_store_ref()) .0 .load(Ordering::SeqCst)); assert_eq!(&*results, &[Value::I32(343)]); diff --git a/lib/c-api/src/wasm_c_api/externals/memory.rs b/lib/c-api/src/wasm_c_api/externals/memory.rs index 1b1bee25529..faa10fe4cac 100644 --- a/lib/c-api/src/wasm_c_api/externals/memory.rs +++ b/lib/c-api/src/wasm_c_api/externals/memory.rs @@ -66,7 +66,8 @@ pub unsafe extern "C" fn wasm_memory_data(memory: &mut wasm_memory_t) -> *mut u8 memory .extern_ .memory() - .data_ptr(&memory.extern_.store.store()) + .lock(&memory.extern_.store.store()) + .data_ptr() } // size in bytes diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 54ed50ed46b..e80b8408095 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -204,8 +204,8 @@ pub unsafe extern "C" fn wasi_env_read_stdout( buffer_len: usize, ) -> isize { let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len as usize); - let mut store_mut = env.store.store_mut(); - let state = env.inner.data_mut(&mut store_mut).state(); + let store = env.store.store(); + let state = env.inner.data(&store).state(); if let Ok(mut stdout) = state.stdout() { if let Some(stdout) = stdout.as_mut() { diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 3a0121a2069..6f5243ad2e8 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -101,7 +101,7 @@ impl Wasi { } let wasi_env = wasi_state_builder.finalize(store)?; - wasi_env.env.as_mut(store).state.fs.is_wasix.store( + wasi_env.env.as_ref(store).state.fs.is_wasix.store( is_wasix_module(module), std::sync::atomic::Ordering::Release, ); diff --git a/lib/compiler-cranelift/src/translator/code_translator.rs b/lib/compiler-cranelift/src/translator/code_translator.rs index c750d6c3231..d432f074361 100644 --- a/lib/compiler-cranelift/src/translator/code_translator.rs +++ b/lib/compiler-cranelift/src/translator/code_translator.rs @@ -1063,15 +1063,24 @@ pub fn translate_operator( assert!(builder.func.dfg.value_type(expected) == implied_ty); // `fn translate_atomic_wait` can inspect the type of `expected` to figure out what // code it needs to generate, if it wants. - let res = environ.translate_atomic_wait( + match environ.translate_atomic_wait( builder.cursor(), heap_index, heap, addr, expected, timeout, - )?; - state.push1(res); + ) { + Ok(res) => { + state.push1(res); + }, + Err(wasmer_types::WasmError::Unsupported(_err)) => { + // If multiple threads hit a mutex then the function will fail + builder.ins().trap(ir::TrapCode::UnreachableCodeReached); + state.reachable = false; + }, + Err(err) => { return Err(err); } + }; } Operator::MemoryAtomicNotify { memarg } => { let heap_index = MemoryIndex::from_u32(memarg.memory); @@ -1079,9 +1088,19 @@ pub fn translate_operator( let count = state.pop1(); // 32 (fixed) let addr = state.pop1(); // 32 (fixed) let addr = fold_atomic_mem_addr(addr, memarg, I32, builder); - let res = - environ.translate_atomic_notify(builder.cursor(), heap_index, heap, addr, count)?; - state.push1(res); + match environ.translate_atomic_notify(builder.cursor(), heap_index, heap, addr, count) + { + Ok(res) => { + state.push1(res); + }, + Err(wasmer_types::WasmError::Unsupported(_err)) => { + // Simple return a zero as this function is needed for the __wasi_init_memory function + // but the equivalent notify.wait will not be called (as only one thread calls __start) + // hence these atomic operations are not needed + state.push1(builder.ins().iconst(I32, i64::from(0))); + }, + Err(err) => { return Err(err); } + }; } Operator::I32AtomicLoad { memarg } => { translate_atomic_load(I32, I32, memarg, builder, state, environ)? diff --git a/lib/compiler/src/engine/resolver.rs b/lib/compiler/src/engine/resolver.rs index a97044adb8b..eb363ba0520 100644 --- a/lib/compiler/src/engine/resolver.rs +++ b/lib/compiler/src/engine/resolver.rs @@ -158,7 +158,7 @@ pub fn resolve_imports( } memory_imports.push(VMMemoryImport { - definition: m.vmmemory(), + definition: m.vmmemory_owned(), handle, }); } diff --git a/lib/compiler/src/translator/environ.rs b/lib/compiler/src/translator/environ.rs index cc42e5f3f58..674b07cfd6e 100644 --- a/lib/compiler/src/translator/environ.rs +++ b/lib/compiler/src/translator/environ.rs @@ -1,7 +1,6 @@ // This file contains code from external sources. // Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md use super::state::ModuleTranslationState; -use crate::lib::std::borrow::ToOwned; use crate::lib::std::string::ToString; use crate::lib::std::{boxed::Box, string::String, vec::Vec}; use crate::translate_module; @@ -16,7 +15,7 @@ use wasmer_types::{ LocalFunctionIndex, MemoryIndex, MemoryType, ModuleInfo, SignatureIndex, TableIndex, TableInitializer, TableType, }; -use wasmer_types::{WasmError, WasmResult}; +use wasmer_types::WasmResult; /// Contains function data: bytecode and its offset in the module. #[derive(Hash)] @@ -254,11 +253,15 @@ impl<'data> ModuleEnvironment<'data> { } pub(crate) fn declare_memory(&mut self, memory: MemoryType) -> WasmResult<()> { + /* + * Shared memories are now supported by WASIX but they are not imported (still exported) + if memory.shared { - return Err(WasmError::Unsupported( + return Err(wasmer_types::WasmError::Unsupported( "shared memories are not supported yet".to_owned(), )); } + */ self.module.memories.push(memory); Ok(()) } diff --git a/lib/derive/src/value_type.rs b/lib/derive/src/value_type.rs index 5e9fe23c826..0280f5ead13 100644 --- a/lib/derive/src/value_type.rs +++ b/lib/derive/src/value_type.rs @@ -1,7 +1,7 @@ use proc_macro2::TokenStream; use proc_macro_error::abort; use quote::quote; -use syn::{Data, DeriveInput, Fields, Member, Meta, MetaList, NestedMeta}; +use syn::{Data, DeriveInput, Member, Meta, MetaList, NestedMeta, Field}; /// We can only validate types that have a well defined layout. fn check_repr(input: &DeriveInput) { @@ -35,7 +35,7 @@ fn check_repr(input: &DeriveInput) { } /// Zero out any padding bytes between fields. -fn zero_padding(fields: &Fields) -> TokenStream { +fn zero_padding(fields: Vec<&Field>) -> TokenStream { let names: Vec<_> = fields .iter() .enumerate() @@ -93,18 +93,18 @@ pub fn impl_value_type(input: &DeriveInput) -> TokenStream { let struct_name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let fields = match &input.data { - Data::Struct(ds) => &ds.fields, + let zero_padding = match &input.data { + Data::Struct(ds) => zero_padding(ds.fields.iter().collect()), _ => abort!(input, "ValueType can only be derived for structs"), }; - let zero_padding = zero_padding(fields); - quote! { unsafe impl #impl_generics ::wasmer::ValueType for #struct_name #ty_generics #where_clause { #[inline] fn zero_padding_bytes(&self, _bytes: &mut [::core::mem::MaybeUninit]) { - #zero_padding + unsafe { + #zero_padding + } } } } diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 0ca0884414d..9ce0b5d5ec3 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -25,7 +25,7 @@ use std::sync::{Arc, Mutex, RwLock}; use wasmer::{ imports, namespace, AsStoreMut, ExportError, Exports, Function, FunctionEnv, FunctionEnvMut, FunctionType, Global, Imports, Instance, Memory, MemoryType, Module, Pages, RuntimeError, - Table, TableType, TypedFunction, Value, WasmPtr, + Table, TableType, TypedFunction, Value, WasmPtr, AsStoreRef, }; use wasmer_types::Type as ValType; @@ -98,7 +98,7 @@ impl EmEnv { } } - pub fn set_memory(&mut self, memory: Memory) { + pub fn set_memory(&self, memory: Memory) { let mut w = self.memory.write().unwrap(); *w = Some(memory); } @@ -108,12 +108,13 @@ impl EmEnv { (&*self.memory.read().unwrap()).as_ref().cloned().unwrap() } - pub fn set_functions(&mut self, funcs: EmscriptenFunctions) { - self.funcs = Arc::new(Mutex::new(funcs)); + pub fn set_functions(&self, funcs: EmscriptenFunctions) { + let mut w = self.funcs.lock().unwrap(); + *w = funcs; } pub fn set_data( - &mut self, + &self, data: &EmscriptenGlobalsData, mapped_dirs: HashMap, ) { @@ -598,7 +599,7 @@ pub fn run_emscripten_instance( args: Vec<&str>, entrypoint: Option, ) -> Result<(), RuntimeError> { - let env = &mut ctx.data_mut(); + let env = &mut ctx.data(); env.set_memory(globals.memory.clone()); // get emscripten export let mut emfuncs = EmscriptenFunctions::new(); @@ -823,7 +824,7 @@ pub fn run_emscripten_instance( if let Ok(func) = instance.exports.get_typed_function(&ctx, "setThrew") { emfuncs.set_threw = Some(func); } - ctx.data_mut().set_functions(emfuncs); + ctx.data().set_functions(emfuncs); set_up_emscripten(&mut ctx, instance)?; @@ -864,16 +865,19 @@ fn store_module_arguments(ctx: &mut FunctionEnvMut, args: Vec<&str>) -> ( } pub fn emscripten_set_up_memory( - store: &mut impl AsStoreMut, + store: &impl AsStoreRef, ctx: &FunctionEnv, memory: &Memory, globals: &EmscriptenGlobalsData, ) -> Result<(), String> { - ctx.as_mut(store).set_memory(memory.clone()); + ctx.as_ref(store).set_memory(memory.clone()); + + let data_size = memory.lock(store).data_size(); + let dynamictop_ptr = WasmPtr::::new(globals.dynamictop_ptr).deref(store, memory); let dynamic_base = globals.dynamic_base; - if dynamictop_ptr.offset() >= memory.data_size(store) { + if dynamictop_ptr.offset() >= data_size { return Err("dynamictop_ptr beyond memory len".to_string()); } dynamictop_ptr.write(dynamic_base as i32).unwrap(); diff --git a/lib/emscripten/src/macros.rs b/lib/emscripten/src/macros.rs index 904721fbb19..e90ad81225c 100644 --- a/lib/emscripten/src/macros.rs +++ b/lib/emscripten/src/macros.rs @@ -1,5 +1,5 @@ macro_rules! emscripten_memory_pointer { ($ctx:expr, $memory:expr, $pointer:expr) => { - $memory.data_ptr(&$ctx).wrapping_add($pointer as usize) + $memory.lock(&$ctx).data_ptr().wrapping_add($pointer as usize) }; } diff --git a/lib/emscripten/src/memory.rs b/lib/emscripten/src/memory.rs index e3fe43a2db8..4e0acdcbe1e 100644 --- a/lib/emscripten/src/memory.rs +++ b/lib/emscripten/src/memory.rs @@ -91,6 +91,7 @@ pub fn sbrk(mut ctx: FunctionEnvMut, increment: i32) -> i32 { .unwrap() .globals .dynamictop_ptr; + let dynamictop_ptr = WasmPtr::::new(top_ptr).deref(&ctx, &memory); let old_dynamic_top = dynamictop_ptr.read().unwrap(); let new_dynamic_top: i32 = old_dynamic_top + increment; @@ -103,6 +104,8 @@ pub fn sbrk(mut ctx: FunctionEnvMut, increment: i32) -> i32 { increment, total_memory ); + drop(dynamictop_ptr); + if increment > 0 && new_dynamic_top < old_dynamic_top || new_dynamic_top < 0 { abort_on_cannot_grow_memory_old(ctx); return -1; diff --git a/lib/types/src/error.rs b/lib/types/src/error.rs index 115cb1ae6c1..61911dca0e3 100644 --- a/lib/types/src/error.rs +++ b/lib/types/src/error.rs @@ -52,6 +52,10 @@ pub enum ImportError { /// This error occurs when an import was expected but not provided. #[error("unknown import. Expected {0:?}")] UnknownImport(ExternType), + + /// Memory Error + #[error("memory error. {0}")] + MemoryError(String), } /// An error while preinstantiating a module. diff --git a/lib/types/src/memory.rs b/lib/types/src/memory.rs index a842abda4e9..55106306ab3 100644 --- a/lib/types/src/memory.rs +++ b/lib/types/src/memory.rs @@ -83,6 +83,9 @@ pub unsafe trait MemorySize: Copy { /// Zero value used for `WasmPtr::is_null`. const ZERO: Self::Offset; + /// One value used for counting. + const ONE: Self::Offset; + /// Convert an `Offset` to a `Native`. fn offset_to_native(offset: Self::Offset) -> Self::Native; @@ -97,6 +100,7 @@ unsafe impl MemorySize for Memory32 { type Offset = u32; type Native = i32; const ZERO: Self::Offset = 0; + const ONE: Self::Offset = 1; fn offset_to_native(offset: Self::Offset) -> Self::Native { offset as Self::Native } @@ -112,6 +116,7 @@ unsafe impl MemorySize for Memory64 { type Offset = u64; type Native = i64; const ZERO: Self::Offset = 0; + const ONE: Self::Offset = 1; fn offset_to_native(offset: Self::Offset) -> Self::Native { offset as Self::Native } diff --git a/lib/vbus/src/lib.rs b/lib/vbus/src/lib.rs index e51ec11ffac..0cda403e17b 100644 --- a/lib/vbus/src/lib.rs +++ b/lib/vbus/src/lib.rs @@ -5,8 +5,9 @@ use thiserror::Error; pub use wasmer_vfs::FileDescriptor; pub use wasmer_vfs::StdioMode; +use wasmer_vfs::VirtualFile; -pub type Result = std::result::Result; +pub type Result = std::result::Result; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] @@ -26,10 +27,14 @@ impl From for CallDescriptor { pub trait VirtualBus: fmt::Debug + Send + Sync + 'static { /// Starts a new WAPM sub process - fn new_spawn(&self) -> SpawnOptions; + fn new_spawn(&self) -> SpawnOptions { + SpawnOptions::new(Box::new(UnsupportedVirtualBusSpawner::default())) + } /// Creates a listener thats used to receive BUS commands - fn listen(&self) -> Result>; + fn listen<'a>(&'a self) -> Result<&'a dyn VirtualBusListener> { + Err(VirtualBusError::Unsupported) + } } pub trait VirtualBusSpawner { @@ -46,7 +51,7 @@ pub struct SpawnOptionsConfig { stdin_mode: StdioMode, stdout_mode: StdioMode, stderr_mode: StdioMode, - working_dir: String, + working_dir: Option, remote_instance: Option, access_token: Option, } @@ -80,8 +85,8 @@ impl SpawnOptionsConfig { self.stderr_mode } - pub fn working_dir(&self) -> &str { - self.working_dir.as_str() + pub fn working_dir(&self) -> Option<&str> { + self.working_dir.as_ref().map(|a| a.as_str()) } pub fn remote_instance(&self) -> Option<&str> { @@ -110,7 +115,7 @@ impl SpawnOptions { stdin_mode: StdioMode::Null, stdout_mode: StdioMode::Null, stderr_mode: StdioMode::Null, - working_dir: "/".to_string(), + working_dir: None, remote_instance: None, access_token: None, }, @@ -157,7 +162,7 @@ impl SpawnOptions { } pub fn working_dir(&mut self, working_dir: String) -> &mut Self { - self.conf.working_dir = working_dir; + self.conf.working_dir = Some(working_dir); self } @@ -179,8 +184,18 @@ impl SpawnOptions { #[derive(Debug)] pub struct BusSpawnedProcess { + /// Name of the spawned process + pub name: String, + /// Configuration applied to this spawned thread + pub config: SpawnOptionsConfig, /// Reference to the spawned instance - pub inst: Box, + pub inst: Box, + /// Virtual file used for stdin + pub stdin: Option>, + /// Virtual file used for stdout + pub stdout: Option>, + /// Virtual file used for stderr + pub stderr: Option>, } pub trait VirtualBusScope: fmt::Debug + Send + Sync + 'static { @@ -192,10 +207,15 @@ pub trait VirtualBusInvokable: fmt::Debug + Send + Sync + 'static { /// Invokes a service within this instance fn invoke( &self, - topic: String, + topic_hash: u128, format: BusDataFormat, - buf: &[u8], - ) -> Result>; + buf: Vec, + ) -> Box; +} + +pub trait VirtualBusInvoked: fmt::Debug + Unpin + 'static { + //// Returns once the bus has been invoked (or failed) + fn poll_invoked(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>>; } pub trait VirtualBusProcess: @@ -204,29 +224,117 @@ pub trait VirtualBusProcess: /// Returns the exit code if the instance has finished fn exit_code(&self) -> Option; - /// Returns a file descriptor used to read the STDIN - fn stdin_fd(&self) -> Option; - - /// Returns a file descriptor used to write to STDOUT - fn stdout_fd(&self) -> Option; - - /// Returns a file descriptor used to write to STDERR - fn stderr_fd(&self) -> Option; + /// Polls to check if the process is ready yet to receive commands + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()>; } pub trait VirtualBusInvocation: - VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static + VirtualBusInvokable + fmt::Debug + Send + Sync + Unpin + 'static { /// Polls for new listen events related to this context fn poll_event(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } +#[derive(Debug)] +pub struct InstantInvocation +{ + val: Option, + err: Option, + call: Option>, +} + +impl InstantInvocation +{ + pub fn response(format: BusDataFormat, data: Vec) -> Self { + Self { + val: Some(BusInvocationEvent::Response { format, data }), + err: None, + call: None + } + } + + pub fn fault(err: VirtualBusError) -> Self { + Self { + val: None, + err: Some(err), + call: None + } + } + + pub fn call(val: Box) -> Self { + Self { + val: None, + err: None, + call: Some(val) + } + } +} + +impl VirtualBusInvoked +for InstantInvocation +{ + fn poll_invoked(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll>> { + if let Some(err) = self.err.take() { + return Poll::Ready(Err(err)); + } + if let Some(val) = self.val.take() { + return Poll::Ready(Ok(Box::new(InstantInvocation { + val: Some(val), + err: None, + call: None, + }))); + } + match self.call.take() { + Some(val) => { + Poll::Ready(Ok(val)) + }, + None => { + Poll::Ready(Err(VirtualBusError::AlreadyConsumed)) + } + } + } +} + +impl VirtualBusInvocation +for InstantInvocation +{ + fn poll_event(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + match self.val.take() { + Some(val) => { + Poll::Ready(val) + }, + None => { + Poll::Ready(BusInvocationEvent::Fault { fault: VirtualBusError::AlreadyConsumed }) + } + } + } +} + +impl VirtualBusInvokable +for InstantInvocation +{ + fn invoke( + &self, + _topic_hash: u128, + _format: BusDataFormat, + _buf: Vec, + ) -> Box { + Box::new( + InstantInvocation { + val: None, + err: Some(VirtualBusError::InvalidTopic), + call: None + } + ) + } +} + #[derive(Debug)] pub enum BusInvocationEvent { /// The server has sent some out-of-band data to you Callback { /// Topic that this call relates to - topic: String, + topic_hash: u128, /// Format of the data we received format: BusDataFormat, /// Data passed in the call @@ -239,34 +347,43 @@ pub enum BusInvocationEvent { /// Data returned by the call data: Vec, }, + /// The service has responded with a fault + Fault { + /// Fault code that was raised + fault: VirtualBusError + } } -pub trait VirtualBusListener: fmt::Debug + Send + Sync + 'static { +pub trait VirtualBusListener: fmt::Debug + Send + Sync + Unpin + 'static { /// Polls for new calls to this service - fn poll_call(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; + fn poll(self: Pin<&Self>, cx: &mut Context<'_>) -> Poll; } #[derive(Debug)] pub struct BusCallEvent { - /// Topic that this call relates to - pub topic: String, + /// Topic hash that this call relates to + pub topic_hash: u128, /// Reference to the call itself - pub called: Box, + pub called: Box, /// Format of the data we received pub format: BusDataFormat, /// Data passed in the call pub data: Vec, } -pub trait VirtualBusCalled: VirtualBusListener + fmt::Debug + Send + Sync + 'static { +pub trait VirtualBusCalled: fmt::Debug + Send + Sync + 'static +{ + /// Polls for new calls to this service + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; + /// Sends an out-of-band message back to the caller - fn callback(&self, topic: String, format: BusDataFormat, buf: &[u8]) -> Result<()>; + fn callback(&self, topic_hash: u128, format: BusDataFormat, buf: Vec); /// Informs the caller that their call has failed - fn fault(self, fault: BusError) -> Result<()>; + fn fault(self: Box, fault: VirtualBusError); /// Finishes the call and returns a particular response - fn reply(self, format: BusDataFormat, buf: &[u8]) -> Result<()>; + fn reply(&self, format: BusDataFormat, buf: Vec); } /// Format that the supplied data is in @@ -284,13 +401,6 @@ pub enum BusDataFormat { pub struct UnsupportedVirtualBus {} impl VirtualBus for UnsupportedVirtualBus { - fn new_spawn(&self) -> SpawnOptions { - SpawnOptions::new(Box::new(UnsupportedVirtualBusSpawner::default())) - } - - fn listen(&self) -> Result> { - Err(BusError::Unsupported) - } } #[derive(Debug, Default)] @@ -298,12 +408,12 @@ pub struct UnsupportedVirtualBusSpawner {} impl VirtualBusSpawner for UnsupportedVirtualBusSpawner { fn spawn(&mut self, _name: &str, _config: &SpawnOptionsConfig) -> Result { - Err(BusError::Unsupported) + Err(VirtualBusError::Unsupported) } } #[derive(Error, Copy, Clone, Debug, PartialEq, Eq)] -pub enum BusError { +pub enum VirtualBusError { /// Failed during serialization #[error("serialization failed")] Serialization, diff --git a/lib/vm/Cargo.toml b/lib/vm/Cargo.toml index 907a6602c64..530f404c319 100644 --- a/lib/vm/Cargo.toml +++ b/lib/vm/Cargo.toml @@ -26,6 +26,7 @@ scopeguard = "1.1.0" lazy_static = "1.4.0" region = { version = "3.0" } corosensei = { version = "0.1.2" } +derivative = { version = "^2" } [target.'cfg(target_vendor = "apple")'.dependencies] mach = "0.3.2" diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index 68427062f7c..fd398b6932c 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -1,13 +1,15 @@ // This file contains code from external sources. // Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md +use std::any::Any; +use std::sync::Arc; + use crate::global::VMGlobal; use crate::memory::VMMemory; use crate::store::InternalStoreHandle; use crate::table::VMTable; use crate::vmcontext::VMFunctionKind; use crate::{MaybeInstanceOwned, VMCallerCheckedAnyfunc}; -use std::any::Any; use wasmer_types::FunctionType; /// The value of an export passed from one instance to another. @@ -26,10 +28,11 @@ pub enum VMExtern { } /// A function export value. +#[derive(Clone)] pub struct VMFunction { /// Pointer to the `VMCallerCheckedAnyfunc` which contains data needed to /// call the function and check its signature. - pub anyfunc: MaybeInstanceOwned, + pub anyfunc: Arc>, /// The function type, used for compatibility checking. pub signature: FunctionType, @@ -39,5 +42,5 @@ pub struct VMFunction { pub kind: VMFunctionKind, /// Associated data owned by a host function. - pub host_data: Box, + pub host_data: Arc, } diff --git a/lib/vm/src/extern_ref.rs b/lib/vm/src/extern_ref.rs index f99a7e93f51..f29c526c302 100644 --- a/lib/vm/src/extern_ref.rs +++ b/lib/vm/src/extern_ref.rs @@ -1,19 +1,20 @@ -use std::any::Any; +use std::{any::Any, sync::Arc}; use wasmer_types::RawValue; use crate::store::InternalStoreHandle; /// Underlying object referenced by a `VMExternRef`. +#[derive(Clone)] pub struct VMExternObj { - contents: Box, + contents: Arc, } impl VMExternObj { /// Wraps the given value to expose it to Wasm code as an externref. pub fn new(val: impl Any + Send + Sync + 'static) -> Self { Self { - contents: Box::new(val), + contents: Arc::new(val), } } diff --git a/lib/vm/src/function_env.rs b/lib/vm/src/function_env.rs index ccedf04385e..27981b9b3de 100644 --- a/lib/vm/src/function_env.rs +++ b/lib/vm/src/function_env.rs @@ -1,15 +1,16 @@ -use std::any::Any; +use std::{any::Any, sync::Arc}; /// Underlying FunctionEnvironment used by a `VMFunction`. +#[derive(Clone)] pub struct VMFunctionEnvironment { - contents: Box, + contents: Arc, } impl VMFunctionEnvironment { /// Wraps the given value to expose it to Wasm code as a function context. pub fn new(val: impl Any + Send + 'static) -> Self { Self { - contents: Box::new(val), + contents: Arc::new(val), } } @@ -20,8 +21,8 @@ impl VMFunctionEnvironment { } #[allow(clippy::should_implement_trait)] - /// Returns a mutable reference to the underlying value. - pub fn as_mut(&mut self) -> &mut (dyn Any + Send + 'static) { - &mut *self.contents + /// Returns a reference to the underlying value. + pub fn as_mut(&mut self) -> Option<&mut (dyn Any + Send + 'static)> { + Arc::get_mut(&mut self.contents) } } diff --git a/lib/vm/src/global.rs b/lib/vm/src/global.rs index 682a66fb294..d965dfd173c 100644 --- a/lib/vm/src/global.rs +++ b/lib/vm/src/global.rs @@ -8,6 +8,18 @@ pub struct VMGlobal { vm_global_definition: MaybeInstanceOwned, } +impl Clone +for VMGlobal +{ + fn clone(&self) -> Self { + let val = self.vm_global_definition.as_ptr().clone(); + Self { + ty: self.ty.clone(), + vm_global_definition: MaybeInstanceOwned::Instance(val), + } + } +} + impl VMGlobal { /// Create a new, zero bit-pattern initialized global from a [`GlobalType`]. pub fn new(global_type: GlobalType) -> Self { diff --git a/lib/vm/src/instance/mod.rs b/lib/vm/src/instance/mod.rs index 0fefd60a651..f7d87f908ac 100644 --- a/lib/vm/src/instance/mod.rs +++ b/lib/vm/src/instance/mod.rs @@ -17,7 +17,7 @@ use crate::trap::{catch_traps, Trap, TrapCode}; use crate::vmcontext::{ VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionContext, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition, - VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, + VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, VMMemoryDefinitionGuard, }; use crate::{FunctionBodyPtr, MaybeInstanceOwned, TrapHandlerFn, VMFunctionBody}; use crate::{VMFuncRef, VMFunction, VMGlobal, VMMemory, VMTable}; @@ -32,7 +32,7 @@ use std::fmt; use std::mem; use std::ptr::{self, NonNull}; use std::slice; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use wasmer_types::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, PrimaryMap}; use wasmer_types::{ DataIndex, DataInitializer, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, GlobalInit, @@ -207,18 +207,21 @@ impl Instance { } /// Get a locally defined or imported memory. - fn get_memory(&self, index: MemoryIndex) -> VMMemoryDefinition { + fn get_memory(&self, index: MemoryIndex) -> VMMemoryDefinitionGuard<'_> { if let Some(local_index) = self.module.local_memory_index(index) { self.memory(local_index) } else { let import = self.imported_memory(index); - unsafe { *import.definition.as_ref() } + let view = import.definition.view(); + VMMemoryDefinitionGuard::View(view) } } /// Return the indexed `VMMemoryDefinition`. - fn memory(&self, index: LocalMemoryIndex) -> VMMemoryDefinition { - unsafe { *self.memory_ptr(index).as_ref() } + fn memory(&self, index: LocalMemoryIndex) -> VMMemoryDefinitionGuard<'_> { + VMMemoryDefinitionGuard::Owned( + unsafe { *self.memory_ptr(index).as_ref() } + ) } #[allow(dead_code)] @@ -644,7 +647,7 @@ impl Instance { len: u32, ) -> Result<(), Trap> { let import = self.imported_memory(memory_index); - let memory = unsafe { import.definition.as_ref() }; + let memory = VMMemoryDefinitionGuard::View(import.definition.view()); // The following memory copy is not synchronized and is not atomic: unsafe { memory.memory_copy(dst, src, len) } } @@ -679,7 +682,7 @@ impl Instance { len: u32, ) -> Result<(), Trap> { let import = self.imported_memory(memory_index); - let memory = unsafe { import.definition.as_ref() }; + let memory = VMMemoryDefinitionGuard::View(import.definition.view()); // The following memory fill is not synchronized and is not atomic: unsafe { memory.memory_fill(dst, val, len) } } @@ -999,16 +1002,16 @@ impl InstanceHandle { // exported. let signature = instance.module.signatures[*sig_index].clone(); let vm_function = VMFunction { - anyfunc: MaybeInstanceOwned::Instance(NonNull::from( + anyfunc: Arc::new(MaybeInstanceOwned::Instance(NonNull::from( &instance.funcrefs[def_index], - )), + ))), signature, // Any function received is already static at this point as: // 1. All locally defined functions in the Wasm have a static signature. // 2. All the imported functions are already static (because // they point to the trampolines rather than the dynamic addresses). kind: VMFunctionKind::Static, - host_data: Box::new(()), + host_data: Arc::new(RwLock::new(Box::new(()))), }; InternalStoreHandle::new(self.instance_mut().context_mut(), vm_function) } else { @@ -1152,7 +1155,7 @@ unsafe fn get_memory_slice<'instance>( instance.memory(local_memory_index) } else { let import = instance.imported_memory(init.location.memory_index); - *import.definition.as_ref() + VMMemoryDefinitionGuard::View(import.definition.view()) }; slice::from_raw_parts_mut(memory.base, memory.current_length) } diff --git a/lib/vm/src/lib.rs b/lib/vm/src/lib.rs index 1b30f1e61e4..c9f63bb365a 100644 --- a/lib/vm/src/lib.rs +++ b/lib/vm/src/lib.rs @@ -45,7 +45,7 @@ pub use crate::function_env::VMFunctionEnvironment; pub use crate::global::*; pub use crate::imports::Imports; pub use crate::instance::{InstanceAllocator, InstanceHandle}; -pub use crate::memory::{MemoryError, VMMemory}; +pub use crate::memory::{MemoryError, VMMemory, VMMemoryView, VMMemoryViewOwned}; pub use crate::mmap::Mmap; pub use crate::probestack::PROBESTACK; pub use crate::sig_registry::SignatureRegistry; diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index 098dd8501b6..40123123bfb 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -7,10 +7,12 @@ use crate::vmcontext::VMMemoryDefinition; use crate::{mmap::Mmap, store::MaybeInstanceOwned}; +use derivative::Derivative; use more_asserts::assert_ge; use std::cell::UnsafeCell; use std::convert::TryInto; use std::ptr::NonNull; +use std::sync::{Arc, RwLock, RwLockReadGuard}; use thiserror::Error; use wasmer_types::{Bytes, MemoryStyle, MemoryType, Pages}; @@ -57,6 +59,7 @@ pub enum MemoryError { } /// A linear memory instance. +#[derive(Clone)] pub struct VMMemory { // The underlying allocation. mmap: WasmMmap, @@ -73,17 +76,63 @@ pub struct VMMemory { // Size in bytes of extra guard pages after the end to optimize loads and stores with // constant offsets. offset_guard_size: usize, - - /// The owned memory definition used by the generated code - vm_memory_definition: MaybeInstanceOwned, } -#[derive(Debug)] -struct WasmMmap { +#[derive(Derivative)] +#[derivative(Debug)] +struct WasmMmapInner { // Our OS allocation of mmap'd memory. alloc: Mmap, // The current logical size in wasm pages of this linear memory. size: Pages, + /// The owned memory definition used by the generated code + #[derivative(Debug = "ignore")] + vm_memory_definition: MaybeInstanceOwned, +} + +#[derive(Debug, Clone)] +struct WasmMmap { + // The inner part of the memory is protected from concurrent grows + inner: Arc>, +} + +/// View into the virtual machine memory +#[derive(Debug, Clone)] +pub struct VMMemoryView<'a> +{ + _inner: Arc>, + frozen: NonNull +} + +impl<'a> std::ops::Deref +for VMMemoryView<'a> +{ + type Target = NonNull; + + fn deref(&self) -> &Self::Target { + &self.frozen + } +} + +/// View into the virtual machine memory (owned) +#[derive(Clone)] +pub struct VMMemoryViewOwned +{ + inner: Arc>, +} + +impl VMMemoryViewOwned +{ + /// Provides a static view into the memory that is multithread safe + /// (this will lock the memory and prevent it from growing) + pub fn view(&self) -> VMMemoryView<'_> { + let inner = self.inner.read().unwrap(); + let frozen = inner.vm_memory_definition.as_ptr(); + VMMemoryView { + _inner: Arc::new(inner), + frozen + } + } } impl VMMemory { @@ -154,18 +203,15 @@ impl VMMemory { let mapped_pages = memory.minimum; let mapped_bytes = mapped_pages.bytes(); - let mut mmap = WasmMmap { - alloc: Mmap::accessible_reserved(mapped_bytes.0, request_bytes) - .map_err(MemoryError::Region)?, - size: memory.minimum, - }; + let mut alloc = Mmap::accessible_reserved(mapped_bytes.0, request_bytes) + .map_err(MemoryError::Region)?; - let base_ptr = mmap.alloc.as_mut_ptr(); + let base_ptr = alloc.as_mut_ptr(); let mem_length = memory.minimum.bytes().0; - Ok(Self { - mmap, - maximum: memory.maximum, - offset_guard_size: offset_guard_bytes, + + let mmap = WasmMmapInner { + alloc, + size: memory.minimum, vm_memory_definition: if let Some(mem_loc) = vm_memory_location { { let mut ptr = mem_loc; @@ -180,16 +226,19 @@ impl VMMemory { current_length: mem_length, }))) }, + }; + + Ok(Self { + mmap: WasmMmap { + inner: Arc::new(RwLock::new(mmap)) + }, + maximum: memory.maximum, + offset_guard_size: offset_guard_bytes, memory: *memory, style: style.clone(), }) } - /// Get the `VMMemoryDefinition`. - fn get_vm_memory_definition(&self) -> NonNull { - self.vm_memory_definition.as_ptr() - } - /// Returns the type for this memory. pub fn ty(&self) -> MemoryType { let minimum = self.size(); @@ -206,9 +255,9 @@ impl VMMemory { /// Returns the number of allocated wasm pages. pub fn size(&self) -> Pages { - // TODO: investigate this function for race conditions + let inner = self.mmap.inner.read().unwrap(); unsafe { - let md_ptr = self.get_vm_memory_definition(); + let md_ptr = inner.vm_memory_definition.as_ptr(); let md = md_ptr.as_ref(); Bytes::from(md.current_length).try_into().unwrap() } @@ -218,26 +267,26 @@ impl VMMemory { /// /// Returns `None` if memory can't be grown by the specified amount /// of wasm pages. - pub fn grow(&mut self, delta: Pages) -> Result { + pub fn grow(&self, delta: Pages) -> Result { // Optimization of memory.grow 0 calls. + let mut inner = self.mmap.inner.write().unwrap(); if delta.0 == 0 { - return Ok(self.mmap.size); + return Ok(inner.size.clone()); } - let new_pages = self - .mmap + let new_pages = inner .size .checked_add(delta) .ok_or(MemoryError::CouldNotGrow { - current: self.mmap.size, + current: inner.size, attempted_delta: delta, })?; - let prev_pages = self.mmap.size; + let prev_pages = inner.size; if let Some(maximum) = self.maximum { if new_pages > maximum { return Err(MemoryError::CouldNotGrow { - current: self.mmap.size, + current: inner.size, attempted_delta: delta, }); } @@ -249,7 +298,7 @@ impl VMMemory { if new_pages >= Pages::max_value() { // Linear memory size would exceed the index range. return Err(MemoryError::CouldNotGrow { - current: self.mmap.size, + current: inner.size, attempted_delta: delta, }); } @@ -258,7 +307,7 @@ impl VMMemory { let prev_bytes = prev_pages.bytes().0; let new_bytes = new_pages.bytes().0; - if new_bytes > self.mmap.alloc.len() - self.offset_guard_size { + if new_bytes > inner.alloc.len() - self.offset_guard_size { // If the new size is within the declared maximum, but needs more memory than we // have on hand, it's a dynamic heap and it can move. let guard_bytes = self.offset_guard_size; @@ -273,34 +322,48 @@ impl VMMemory { let mut new_mmap = Mmap::accessible_reserved(new_bytes, request_bytes).map_err(MemoryError::Region)?; - let copy_len = self.mmap.alloc.len() - self.offset_guard_size; + let copy_len = inner.alloc.len() - self.offset_guard_size; new_mmap.as_mut_slice()[..copy_len] - .copy_from_slice(&self.mmap.alloc.as_slice()[..copy_len]); + .copy_from_slice(&inner.alloc.as_slice()[..copy_len]); - self.mmap.alloc = new_mmap; + inner.alloc = new_mmap; } else if delta_bytes > 0 { // Make the newly allocated pages accessible. - self.mmap + inner .alloc .make_accessible(prev_bytes, delta_bytes) .map_err(MemoryError::Region)?; } - self.mmap.size = new_pages; + inner.size = new_pages; // update memory definition unsafe { - let mut md_ptr = self.get_vm_memory_definition(); + let mut md_ptr = inner.vm_memory_definition.as_ptr(); let md = md_ptr.as_mut(); md.current_length = new_pages.bytes().0; - md.base = self.mmap.alloc.as_mut_ptr() as _; + md.base = inner.alloc.as_mut_ptr() as _; } Ok(prev_pages) } /// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code. - pub fn vmmemory(&self) -> NonNull { - self.get_vm_memory_definition() + /// that blocks memory grow while its being accessed + pub fn vmmemory(&self) -> VMMemoryView<'_> { + let inner = self.mmap.inner.read().unwrap(); + let frozen = inner.vm_memory_definition.as_ptr(); + VMMemoryView { + _inner: Arc::new(inner), + frozen + } + } + + /// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code + /// that is thread safe + pub fn vmmemory_owned(&self) -> VMMemoryViewOwned { + VMMemoryViewOwned { + inner: self.mmap.inner.clone() + } } } diff --git a/lib/vm/src/store.rs b/lib/vm/src/store.rs index 747154f9d50..d3c6c6ed01e 100644 --- a/lib/vm/src/store.rs +++ b/lib/vm/src/store.rs @@ -60,7 +60,7 @@ impl_context_object! { } /// Set of objects managed by a context. -#[derive(Default)] +#[derive(Default, Clone)] pub struct StoreObjects { id: StoreId, memories: Vec, @@ -96,6 +96,13 @@ impl StoreObjects { (&mut high[0], &mut low[a.index()]) } } + + /// Freezes the tables so that copying is a shallow copy rather than full copy + pub fn freeze(&mut self) { + for table in self.tables.iter_mut() { + table.freeze(); + } + } } /// Handle to an object managed by a context. diff --git a/lib/vm/src/table.rs b/lib/vm/src/table.rs index bdc5e5fdbaa..63b07da114d 100644 --- a/lib/vm/src/table.rs +++ b/lib/vm/src/table.rs @@ -14,6 +14,7 @@ use std::cell::UnsafeCell; use std::convert::TryFrom; use std::fmt; use std::ptr::NonNull; +use std::sync::Arc; use wasmer_types::TableStyle; use wasmer_types::{TableType, TrapCode, Type as ValType}; @@ -68,8 +69,8 @@ impl Default for TableElement { } } -/// A table instance. -pub struct VMTable { +pub struct VMTableOwned +{ vec: Vec, maximum: Option, /// The WebAssembly table description. @@ -79,15 +80,57 @@ pub struct VMTable { vm_table_definition: MaybeInstanceOwned, } -impl VMTable { +impl Clone +for VMTableOwned +{ + fn clone(&self) -> Self { + let mut vec = self.vec.clone(); + let base = vec.as_mut_ptr(); + Self { + vec: self.vec.clone(), + maximum: self.maximum.clone(), + table: self.table.clone(), + style: self.style.clone(), + vm_table_definition: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMTableDefinition { + base: base as _, + current_elements: unsafe { + self.get_vm_table_definition().as_ref().current_elements + }, + }))) + } + } +} + +impl VMTableOwned { /// Create a new linear table instance with specified minimum and maximum number of elements. /// /// This creates a `Table` with metadata owned by a VM, pointed to by /// `vm_table_location`: this can be used to create a local table. - pub fn new(table: &TableType, style: &TableStyle) -> Result { + fn new(table: &TableType, style: &TableStyle) -> Result { unsafe { Self::new_inner(table, style, None) } } + /// Takes the table and replaces it with an empty table + fn take(&mut self) -> VMTableOwned + { + let mut vec = Vec::new(); + let mut vm_table_definition = MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMTableDefinition { + base: vec.as_mut_ptr() as _, + current_elements: 0, + }))); + + std::mem::swap(&mut vec, &mut self.vec); + std::mem::swap(&mut vm_table_definition, &mut self.vm_table_definition); + + Self { + vec, + maximum: self.maximum.clone(), + table: self.table.clone(), + style: self.style.clone(), + vm_table_definition, + } + } + /// Create a new linear table instance with specified minimum and maximum number of elements. /// /// This creates a `Table` with metadata owned by a VM, pointed to by @@ -95,7 +138,7 @@ impl VMTable { /// /// # Safety /// - `vm_table_location` must point to a valid location in VM memory. - pub unsafe fn from_definition( + unsafe fn from_definition( table: &TableType, style: &TableStyle, vm_table_location: NonNull, @@ -160,17 +203,17 @@ impl VMTable { } /// Returns the type for this Table. - pub fn ty(&self) -> &TableType { + fn ty(&self) -> &TableType { &self.table } /// Returns the style for this Table. - pub fn style(&self) -> &TableStyle { + fn style(&self) -> &TableStyle { &self.style } /// Returns the number of allocated elements. - pub fn size(&self) -> u32 { + fn size(&self) -> u32 { // TODO: investigate this function for race conditions unsafe { let td_ptr = self.get_vm_table_definition(); @@ -183,7 +226,7 @@ impl VMTable { /// /// Returns `None` if table can't be grown by the specified amount /// of elements, otherwise returns the previous size of the table. - pub fn grow(&mut self, delta: u32, init_value: TableElement) -> Option { + fn grow(&mut self, delta: u32, init_value: TableElement) -> Option { let size = self.size(); let new_len = size.checked_add(delta)?; if self.maximum.map_or(false, |max| new_len > max) { @@ -210,7 +253,7 @@ impl VMTable { /// Get reference to the specified element. /// /// Returns `None` if the index is out of bounds. - pub fn get(&self, index: u32) -> Option { + fn get(&self, index: u32) -> Option { let raw_data = self.vec.get(index as usize).cloned()?; Some(match self.table.ty { ValType::ExternRef => TableElement::ExternRef(unsafe { raw_data.extern_ref }), @@ -224,7 +267,7 @@ impl VMTable { /// # Errors /// /// Returns an error if the index is out of bounds. - pub fn set(&mut self, index: u32, reference: TableElement) -> Result<(), Trap> { + fn set(&mut self, index: u32, reference: TableElement) -> Result<(), Trap> { match self.vec.get_mut(index as usize) { Some(slot) => { match (self.table.ty, reference) { @@ -251,7 +294,7 @@ impl VMTable { } /// Return a `VMTableDefinition` for exposing the table to compiled wasm code. - pub fn vmtable(&self) -> NonNull { + fn vmtable(&self) -> NonNull { self.get_vm_table_definition() } @@ -261,9 +304,9 @@ impl VMTable { /// /// Returns an error if the range is out of bounds of either the source or /// destination tables. - pub fn copy( + fn copy( &mut self, - src_table: &Self, + src_table: &VMTable, dst_index: u32, src_index: u32, len: u32, @@ -307,7 +350,7 @@ impl VMTable { /// /// Returns an error if the range is out of bounds of either the source or /// destination tables. - pub fn copy_within(&mut self, dst_index: u32, src_index: u32, len: u32) -> Result<(), Trap> { + fn copy_within(&mut self, dst_index: u32, src_index: u32, len: u32) -> Result<(), Trap> { // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-copy if src_index.checked_add(len).map_or(true, |n| n > self.size()) { @@ -338,3 +381,159 @@ impl VMTable { Ok(()) } } + +/// A table instance. +pub enum VMTable { + /// The table data is directly owned (and hence is writable) + Owned(VMTableOwned), + /// The table data is shared with multiple owners (and hence is readonly) + Shared(Arc), +} + +impl Clone +for VMTable +{ + fn clone(&self) -> Self { + Self::Shared( + match self { + Self::Owned(a) => Arc::new(a.clone()), + Self::Shared(a) => a.clone(), + } + ) + } +} + +impl VMTable { + /// Create a new linear table instance with specified minimum and maximum number of elements. + /// + /// This creates a `Table` with metadata owned by a VM, pointed to by + /// `vm_table_location`: this can be used to create a local table. + pub fn new(table: &TableType, style: &TableStyle) -> Result { + Ok(Self::Shared(Arc::new(VMTableOwned::new(table, style)?))) + } + + /// Create a new linear table instance with specified minimum and maximum number of elements. + /// + /// This creates a `Table` with metadata owned by a VM, pointed to by + /// `vm_table_location`: this can be used to create a local table. + /// + /// # Safety + /// - `vm_table_location` must point to a valid location in VM memory. + pub unsafe fn from_definition( + table: &TableType, + style: &TableStyle, + vm_table_location: NonNull, + ) -> Result { + Ok(Self::Shared(Arc::new(VMTableOwned::from_definition(table, style, vm_table_location)?))) + } + + /// Copies the data in this table and allows it to be mutated again + fn copy_on_write(&mut self) -> &mut VMTableOwned + { + match self { + Self::Owned(a) => a, + Self::Shared(a) => { + let a = (**a).clone(); + *self = Self::Owned(a); + match self { + Self::Owned(a) => a, + _ => { unreachable!("the shared instance was just overridden") } + } + } + } + } + + /// Makes this object sharable so that clones are shallow + pub(crate) fn freeze(&mut self) { + if let Self::Owned(a) = self { + let b = a.take(); + drop(a); + *self = Self::Shared(Arc::new(b)); + } + } + + /// Returns the type for this Table. + pub fn ty(&self) -> &TableType { + match self { + Self::Owned(a) => a.ty(), + Self::Shared(a) => a.ty() + } + } + + /// Returns the style for this Table. + pub fn style(&self) -> &TableStyle { + match self { + Self::Owned(a) => a.style(), + Self::Shared(a) => a.style() + } + } + + /// Returns the number of allocated elements. + pub fn size(&self) -> u32 { + match self { + Self::Owned(a) => a.size(), + Self::Shared(a) => a.size() + } + } + + /// Grow table by the specified amount of elements. + /// + /// Returns `None` if table can't be grown by the specified amount + /// of elements, otherwise returns the previous size of the table. + pub fn grow(&mut self, delta: u32, init_value: TableElement) -> Option { + self.copy_on_write().grow(delta, init_value) + } + + /// Get reference to the specified element. + /// + /// Returns `None` if the index is out of bounds. + pub fn get(&self, index: u32) -> Option { + match self { + Self::Owned(a) => a.get(index), + Self::Shared(a) => a.get(index) + } + } + + /// Set reference to the specified element. + /// + /// # Errors + /// + /// Returns an error if the index is out of bounds. + pub fn set(&mut self, index: u32, reference: TableElement) -> Result<(), Trap> { + self.copy_on_write().set(index, reference) + } + + /// Return a `VMTableDefinition` for exposing the table to compiled wasm code. + pub fn vmtable(&self) -> NonNull { + match self { + Self::Owned(a) => a.vmtable(), + Self::Shared(a) => a.vmtable() + } + } + + /// Copy `len` elements from `src_table[src_index..]` into `dst_table[dst_index..]`. + /// + /// # Errors + /// + /// Returns an error if the range is out of bounds of either the source or + /// destination tables. + pub fn copy( + &mut self, + src_table: &Self, + dst_index: u32, + src_index: u32, + len: u32, + ) -> Result<(), Trap> { + self.copy_on_write().copy(src_table, dst_index, src_index, len) + } + + /// Copy `len` elements from `table[src_index..]` to `table[dst_index..]`. + /// + /// # Errors + /// + /// Returns an error if the range is out of bounds of either the source or + /// destination tables. + pub fn copy_within(&mut self, dst_index: u32, src_index: u32, len: u32) -> Result<(), Trap> { + self.copy_on_write().copy_within(dst_index, src_index, len) + } +} \ No newline at end of file diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index edc3bf4d40e..9520c10ebde 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -6,10 +6,10 @@ use crate::global::VMGlobal; use crate::instance::Instance; -use crate::memory::VMMemory; +use crate::memory::{VMMemory, VMMemoryViewOwned}; use crate::store::InternalStoreHandle; use crate::trap::{Trap, TrapCode}; -use crate::VMFunctionBody; +use crate::{VMFunctionBody, VMMemoryView}; use crate::VMTable; use crate::{VMBuiltinFunctionIndex, VMFunction}; use std::convert::TryFrom; @@ -108,7 +108,8 @@ mod test_vmfunction_import { /// containing the relevant context for running the function indicated /// in `address`. #[repr(C)] -pub struct VMDynamicFunctionContext { +pub struct VMDynamicFunctionContext +{ /// The address of the inner dynamic function. /// /// Note: The function must be on the form of @@ -223,7 +224,7 @@ mod test_vmtable_import { #[repr(C)] pub struct VMMemoryImport { /// A pointer to the imported memory description. - pub definition: NonNull, + pub definition: VMMemoryViewOwned, /// A handle to the `Memory` that owns the memory description. pub handle: InternalStoreHandle, @@ -316,18 +317,49 @@ pub struct VMMemoryDefinition { pub current_length: usize, } +/// Represents a VMMemoryDefinition that is multithread safe +pub enum VMMemoryDefinitionGuard<'a> +{ + Owned(VMMemoryDefinition), + View(VMMemoryView<'a>), +} + +impl<'a> std::ops::Deref +for VMMemoryDefinitionGuard<'a> +{ + type Target = VMMemoryDefinition; + + fn deref(&self) -> &Self::Target { + match self { + Self::Owned(a) => a, + Self::View(a) => { + unsafe { a.as_ref() } + } + } + } +} + /// # Safety /// This data is safe to share between threads because it's plain data that /// is the user's responsibility to synchronize. -unsafe impl Send for VMMemoryDefinition {} +unsafe impl<'a> Send for VMMemoryDefinitionGuard<'a> {} /// # Safety /// This data is safe to share between threads because it's plain data that /// is the user's responsibility to synchronize. And it's `Copy` so there's /// really no difference between passing it by reference or by value as far as /// correctness in a multi-threaded context is concerned. -unsafe impl Sync for VMMemoryDefinition {} +unsafe impl<'a> Sync for VMMemoryDefinitionGuard<'a> {} + +impl<'a> VMMemoryDefinitionGuard<'a> { + /// This must only be used while the scope self remains + /// as it has a read lock on the memory + unsafe fn get_definition(&self) -> VMMemoryDefinition { + match self { + Self::Owned(a) => a.clone(), + Self::View(a) => *a.as_ptr() + } + } -impl VMMemoryDefinition { /// Do an unsynchronized, non-atomic `memory.copy` for the memory. /// /// # Errors @@ -339,13 +371,14 @@ impl VMMemoryDefinition { /// The memory is not copied atomically and is not synchronized: it's the /// caller's responsibility to synchronize. pub(crate) unsafe fn memory_copy(&self, dst: u32, src: u32, len: u32) -> Result<(), Trap> { + let definition = self.get_definition(); // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy if src .checked_add(len) - .map_or(true, |n| usize::try_from(n).unwrap() > self.current_length) + .map_or(true, |n| usize::try_from(n).unwrap() > definition.current_length) || dst .checked_add(len) - .map_or(true, |m| usize::try_from(m).unwrap() > self.current_length) + .map_or(true, |m| usize::try_from(m).unwrap() > definition.current_length) { return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); } @@ -355,8 +388,8 @@ impl VMMemoryDefinition { // Bounds and casts are checked above, by this point we know that // everything is safe. - let dst = self.base.add(dst); - let src = self.base.add(src); + let dst = definition.base.add(dst); + let src = definition.base.add(src); ptr::copy(src, dst, len as usize); Ok(()) @@ -373,9 +406,10 @@ impl VMMemoryDefinition { /// The memory is not filled atomically and is not synchronized: it's the /// caller's responsibility to synchronize. pub(crate) unsafe fn memory_fill(&self, dst: u32, val: u32, len: u32) -> Result<(), Trap> { + let definition = self.get_definition(); if dst .checked_add(len) - .map_or(true, |m| usize::try_from(m).unwrap() > self.current_length) + .map_or(true, |m| usize::try_from(m).unwrap() > definition.current_length) { return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); } @@ -385,7 +419,7 @@ impl VMMemoryDefinition { // Bounds and casts are checked above, by this point we know that // everything is safe. - let dst = self.base.offset(dst); + let dst = definition.base.offset(dst); ptr::write_bytes(dst, val, len as usize); Ok(()) diff --git a/lib/wasi-types/src/bus.rs b/lib/wasi-types/src/bus.rs index ff8bea2ecb3..33ff6e77ec4 100644 --- a/lib/wasi-types/src/bus.rs +++ b/lib/wasi-types/src/bus.rs @@ -1,6 +1,7 @@ use super::*; use wasmer_derive::ValueType; -use wasmer_types::MemorySize; + +pub type __wasi_hash_t = u128; pub type __wasi_busdataformat_t = u8; pub const __WASI_BUS_DATA_FORMAT_RAW: __wasi_busdataformat_t = 0; @@ -28,7 +29,7 @@ pub struct __wasi_option_bid_t { pub bid: __wasi_bid_t, } -pub type __wasi_cid_t = u8; +pub type __wasi_cid_t = u64; #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] @@ -62,23 +63,20 @@ pub struct __wasi_busevent_exit_t { #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] -pub struct __wasi_busevent_call_t { +pub struct __wasi_busevent_call_t { pub parent: __wasi_option_cid_t, pub cid: __wasi_cid_t, pub format: __wasi_busdataformat_t, - pub topic_ptr: M::Offset, - pub topic_len: M::Offset, - pub buf_ptr: M::Offset, - pub buf_len: M::Offset, + pub topic_hash: __wasi_hash_t, + pub fd: __wasi_fd_t, } #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] -pub struct __wasi_busevent_result_t { +pub struct __wasi_busevent_result_t { pub format: __wasi_busdataformat_t, pub cid: __wasi_cid_t, - pub buf_ptr: M::Offset, - pub buf_len: M::Offset, + pub fd: __wasi_fd_t, } #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] @@ -96,18 +94,25 @@ pub struct __wasi_busevent_close_t { #[derive(Copy, Clone)] #[repr(C)] -pub union __wasi_busevent_u { +pub union __wasi_busevent_u { pub noop: u8, pub exit: __wasi_busevent_exit_t, - pub call: __wasi_busevent_call_t, - pub result: __wasi_busevent_result_t, + pub call: __wasi_busevent_call_t, + pub result: __wasi_busevent_result_t, pub fault: __wasi_busevent_fault_t, pub close: __wasi_busevent_close_t, } +#[derive(Copy, Clone, ValueType)] +#[repr(C)] +pub struct __wasi_busevent_t { + pub tag: __wasi_buseventtype_t, + pub padding: [u8; 63], +} + #[derive(Copy, Clone)] #[repr(C)] -pub struct __wasi_busevent_t { +pub struct __wasi_busevent_t2 { pub tag: __wasi_buseventtype_t, - pub u: __wasi_busevent_u, + pub u: __wasi_busevent_u, } diff --git a/lib/wasi-types/src/file.rs b/lib/wasi-types/src/file.rs index 0d58ba9bbe4..92f0e74a6be 100644 --- a/lib/wasi-types/src/file.rs +++ b/lib/wasi-types/src/file.rs @@ -18,6 +18,9 @@ pub const __WASI_STDERR_FILENO: __wasi_fd_t = 2; pub type __wasi_pid_t = u32; pub type __wasi_tid_t = u32; +pub type __wasi_tl_key_t = u32; +pub type __wasi_tl_val_t = u64; + pub type __wasi_fdflags_t = u16; pub const __WASI_FDFLAG_APPEND: __wasi_fdflags_t = 1 << 0; pub const __WASI_FDFLAG_DSYNC: __wasi_fdflags_t = 1 << 1; diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 2f0d97193fa..a6f97c8c071 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -31,6 +31,8 @@ bincode = { version = "1.3", optional = true } chrono = { version = "^0.4", default-features = false, features = [ "wasmbind", "std", "clock" ], optional = true } derivative = { version = "^2" } bytes = "1" +thread-id = { version = "4", optional = true } +sha2 = { version = "0.10" } [target.'cfg(unix)'.dependencies] libc = { version = "^0.2", default-features = false } @@ -48,8 +50,8 @@ tracing-wasm = "0.2" [features] default = ["sys-default"] -sys = ["wasmer/sys"] -sys-default = ["wasmer/sys-default", "sys", "logging", "host-fs", "sys-poll", "host-vnet" ] +sys = ["wasmer/sys", "thread-id"] +sys-default = ["wasmer/sys-default", "sys", "logging", "host-fs", "sys-poll", "host-vnet", "host-threads" ] sys-poll = [] js = ["wasmer/js", "mem-fs", "wasmer-vfs/no-time", "getrandom/js", "chrono"] @@ -57,6 +59,7 @@ js-default = ["js", "wasmer/js-default"] test-js = ["js", "wasmer/js-default", "wasmer/wat"] host-vnet = [ "wasmer-wasi-local-networking" ] +host-threads = [] host-fs = ["wasmer-vfs/host-fs"] mem-fs = ["wasmer-vfs/mem-fs"] diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index abc96368fc2..e84984cda96 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -40,8 +40,6 @@ mod state; mod syscalls; mod utils; -use crate::syscalls::*; - pub use crate::state::{ Fd, Pipe, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiState, WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, @@ -50,6 +48,7 @@ pub use crate::syscalls::types; pub use crate::utils::{ get_wasi_version, get_wasi_versions, is_wasi_module, is_wasix_module, WasiVersion, }; +use derivative::Derivative; pub use wasmer_vbus::{UnsupportedVirtualBus, VirtualBus}; #[deprecated(since = "2.1.0", note = "Please use `wasmer_vfs::FsError`")] pub use wasmer_vfs::FsError as WasiFsError; @@ -59,18 +58,18 @@ pub use wasmer_vfs::{FsError, VirtualFile}; pub use wasmer_vnet::{UnsupportedVirtualNetworking, VirtualNetworking}; use wasmer_wasi_types::__WASI_CLOCK_MONOTONIC; -use derivative::*; +use std::cell::RefCell; use std::ops::Deref; use thiserror::Error; use wasmer::{ imports, namespace, AsStoreMut, Exports, Function, FunctionEnv, Imports, Memory, Memory32, - MemoryAccessError, MemorySize, Module, TypedFunction, + MemoryAccessError, MemorySize, Module, TypedFunction, Reactors, Memory64, AsStoreRef, Instance, ExportError }; pub use runtime::{ PluggableRuntimeImplementation, WasiRuntimeImplementation, WasiThreadError, WasiTtyState, }; -use std::sync::{mpsc, Arc, Mutex, RwLockReadGuard, RwLockWriteGuard}; +use std::sync::{Arc, RwLockReadGuard, RwLockWriteGuard}; use std::time::Duration; /// This is returned in `RuntimeError`. @@ -84,9 +83,20 @@ pub enum WasiError { } /// Represents the ID of a WASI thread -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WasiThreadId(u32); +impl WasiThreadId { + pub fn raw(&self) -> u32 { + self.0 + } + + pub fn inc(&mut self) -> WasiThreadId { + self.0 += 1; + self.clone() + } +} + impl From for WasiThreadId { fn from(id: u32) -> Self { Self(id) @@ -107,145 +117,69 @@ impl From for WasiBusProcessId { Self(id) } } -impl From for u32 { - fn from(id: WasiBusProcessId) -> u32 { - id.0 as u32 - } -} - -#[cfg(target_family = "wasm")] -#[link(wasm_import_module = "__wbindgen_thread_xform__")] -extern "C" { - fn __wbindgen_thread_id() -> u32; -} - -#[derive(Debug, Clone)] -pub struct WasiThread { - /// ID of this thread - #[allow(dead_code)] - id: WasiThreadId, - /// Signalers used to tell joiners that the thread has exited - exit: Arc>>>, - /// Event to wait on for the thread to join - join: Arc>>, -} - -impl WasiThread { - /// Waits for the thread to exit (false = timeout) - pub fn join(&self, timeout: Duration) -> bool { - let guard = self.join.lock().unwrap(); - match guard.recv_timeout(timeout) { - Ok(_) => true, - Err(mpsc::RecvTimeoutError::Disconnected) => true, - Err(mpsc::RecvTimeoutError::Timeout) => false, - } +impl Into for WasiBusProcessId { + fn into(self) -> u32 { + self.0 as u32 } } -pub struct WasiFunctionEnv { - pub env: FunctionEnv, -} - -impl WasiFunctionEnv { - pub fn new(store: &mut impl AsStoreMut, env: WasiEnv) -> Self { - Self { - env: FunctionEnv::new(store, env), - } - } - - /// Get an `Imports` for a specific version of WASI detected in the module. - pub fn import_object( - &self, - store: &mut impl AsStoreMut, - module: &Module, - ) -> Result { - let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?; - Ok(generate_import_object_from_env( - store, - &self.env, - wasi_version, - )) - } - - pub fn data_mut<'a>(&'a self, store: &'a mut impl AsStoreMut) -> &'a mut WasiEnv { - self.env.as_mut(store) - } - - /// Like `import_object` but containing all the WASI versions detected in - /// the module. - pub fn import_object_for_all_wasi_versions( - &self, - store: &mut impl AsStoreMut, - module: &Module, - ) -> Result { - let wasi_versions = - get_wasi_versions(module, false).ok_or(WasiError::UnknownWasiVersion)?; - - let mut resolver = Imports::new(); - for version in wasi_versions.iter() { - let new_import_object = generate_import_object_from_env(store, &self.env, *version); - for ((n, m), e) in new_import_object.into_iter() { - resolver.define(&n, &m, e); - } - } - - if is_wasix_module(module) { - self.data_mut(store) - .state - .fs - .is_wasix - .store(true, std::sync::atomic::Ordering::Release); - } - - Ok(resolver) - } +/// The protected environment attributes that are set after the WasiEnv is initialized +#[derive(Clone)] +pub struct WasiEnvInner +{ + /// Represents a reference to the memory + memory: Memory, + /// Represents the reactors used to sleep and wake + reactors: Reactors, + /// Represents the callback for spawning a thread (name = "_start_thread") + thread_spawn: Option>, + /// Represents the callback for spawning a reactor (name = "_react") + react: Option>, + /// Represents the callback for destroying a local thread variable (name = "_thread_local_destroy") + thread_local_destroy: Option>, + /// Represents the callback for allocating memory (name = "_malloc") + _malloc: Option>, + /// Represents the callback for deallocating memory (name = "_free") + _free: Option>, } /// The environment provided to the WASI imports. #[derive(Derivative, Clone)] #[derivative(Debug)] -#[allow(dead_code)] pub struct WasiEnv { /// ID of this thread (zero is the main thread) id: WasiThreadId, - /// Represents a reference to the memory - memory: Option, - /// If the module has it then map the thread start - #[derivative(Debug = "ignore")] - thread_start: Option>, - #[derivative(Debug = "ignore")] - reactor_work: Option>, - #[derivative(Debug = "ignore")] - reactor_finish: Option>, - #[derivative(Debug = "ignore")] - malloc: Option>, - #[derivative(Debug = "ignore")] - free: Option>, /// Shared state of the WASI system. Manages all the data that the /// executing WASI program can see. pub state: Arc, + /// Inner functions and references that are loaded before the environment starts + #[derivative(Debug = "ignore")] + pub inner: Option, /// Implementation of the WASI runtime. pub(crate) runtime: Arc, } +// Represents the current thread ID for the executing method +thread_local!(pub(crate) static THREAD_ID: RefCell = RefCell::new(0)); + impl WasiEnv { - /// Create a new WasiEnv from a WasiState (memory will be set to None) pub fn new(state: WasiState) -> Self { - Self { + let state = Arc::new(state); + Self::new_ext(state) + } + + fn new_ext(state: Arc) -> Self { + let ret = Self { id: 0u32.into(), - state: Arc::new(state), - memory: None, - thread_start: None, - reactor_work: None, - reactor_finish: None, - malloc: None, - free: None, + state, + inner: None, runtime: Arc::new(PluggableRuntimeImplementation::default()), - } + }; + ret } - + /// Returns a copy of the current runtime implementation for this environment - pub fn runtime(&self) -> &(dyn WasiRuntimeImplementation) { + pub fn runtime<'a>(&'a self) -> &'a (dyn WasiRuntimeImplementation) { self.runtime.deref() } @@ -259,47 +193,31 @@ impl WasiEnv { /// Returns the current thread ID pub fn current_thread_id(&self) -> WasiThreadId { - self.id - } - - /// Creates a new thread only this wasi environment - pub fn new_thread(&self) -> WasiThread { - let (tx, rx) = mpsc::channel(); - - let mut guard = self.state.threading.lock().unwrap(); - - guard.thread_seed += 1; - let next_id: WasiThreadId = guard.thread_seed.into(); - - let thread = WasiThread { - id: next_id, - exit: Arc::new(Mutex::new(Some(tx))), - join: Arc::new(Mutex::new(rx)), - }; - - guard.threads.insert(thread.id, thread.clone()); - thread + THREAD_ID.with(|f| { + let thread_id = f.borrow(); + *thread_id + }).into() } - /// Copy the lazy reference so that when it's initialized during the - /// export phase, all the other references get a copy of it - pub fn memory_clone(&self) -> Option { - self.memory.clone() + /// Returns the number of active threads + pub fn active_threads(&self) -> u32 { + let guard = self.state.threading.read().unwrap(); + guard.active_threads() } // Yields execution pub fn yield_now(&self) -> Result<(), WasiError> { - self.runtime.yield_now(self.id)?; + self.runtime.yield_now(self.current_thread_id())?; Ok(()) } // Sleeps for a period of time pub fn sleep(&self, duration: Duration) -> Result<(), WasiError> { let duration = duration.as_nanos(); - let start = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + let start = syscalls::platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; self.yield_now()?; loop { - let now = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + let now = syscalls::platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; let delta = match now.checked_sub(start) { Some(a) => a, None => { @@ -322,39 +240,46 @@ impl WasiEnv { } /// Accesses the virtual networking implementation - pub fn net(&self) -> &(dyn VirtualNetworking) { + pub fn net<'a>(&'a self) -> &'a (dyn VirtualNetworking) { self.runtime.networking() } /// Accesses the virtual bus implementation - pub fn bus(&self) -> &(dyn VirtualBus) { + pub fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { self.runtime.bus() } - pub(crate) fn get_memory_and_wasi_state(&self, _mem_index: u32) -> (&Memory, &WasiState) { - let memory = self.memory(); - let state = self.state.deref(); - (memory, state) - } - /// Set the memory of the WasiEnv (can only be done once) - pub fn set_memory(&mut self, memory: Memory) { - if self.memory.is_some() { - panic!("Memory of a WasiEnv can only be set once!"); - } - self.memory = Some(memory); + /// Providers safe access to the initialized part of WasiEnv + /// (it must be initialized before it can be used) + pub fn inner(&self) -> &WasiEnvInner { + self.inner.as_ref() + .expect("You must initialize the WasiEnv before using it") } - /// Get memory, that needs to have been set fist + /// Providers safe access to the memory + /// (it must be initialized before it can be used) pub fn memory(&self) -> &Memory { - self.memory.as_ref().unwrap() + &self.inner().memory + } + + /// Copy the lazy reference so that when it's initialized during the + /// export phase, all the other references get a copy of it + pub fn memory_clone(&self) -> Memory { + self.memory().clone() } /// Get the WASI state pub fn state(&self) -> &WasiState { &self.state } + + pub(crate) fn get_memory_and_wasi_state(&self, _mem_index: u32) -> (&Memory, &WasiState) { + let memory = self.memory(); + let state = self.state.deref(); + (memory, state) + } - pub fn get_memory_and_wasi_state_and_inodes( + pub(crate) fn get_memory_and_wasi_state_and_inodes( &self, _mem_index: u32, ) -> (&Memory, &WasiState, RwLockReadGuard) { @@ -375,7 +300,96 @@ impl WasiEnv { } } -/// Create an [`Imports`] from a [`Context`] +pub struct WasiFunctionEnv { + pub env: FunctionEnv, +} + +impl WasiFunctionEnv { + pub fn new(store: &mut impl AsStoreMut, env: WasiEnv) -> Self { + Self { + env: FunctionEnv::new(store, env), + } + } + + /// Get an `Imports` for a specific version of WASI detected in the module. + pub fn import_object( + &self, + store: &mut impl AsStoreMut, + module: &Module, + ) -> Result { + let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?; + Ok(generate_import_object_from_env( + store, + &self.env, + wasi_version, + )) + } + + /// Gets a reference to the WasiEnvironment + pub fn data<'a>(&'a self, store: &'a impl AsStoreRef) -> &'a WasiEnv { + self.env.as_ref(store) + } + + /// Gets a mutable- reference to the host state in this context. + /// (this will only return a mutable reference as long as the environment + /// has not been cloned - environments are cloned during multithreading) + pub fn data_mut<'a>(&'a mut self, store: &'a mut impl AsStoreMut) -> &'a mut WasiEnv { + self.env + .as_mut(store) + .expect("The WasiEnv can not be mutated after its been cloned") + } + + /// Initializes the WasiEnv using the instance exports + /// (this must be executed before attempting to use it) + pub fn initialize(&mut self, store: &mut impl AsStoreMut, instance: &Instance) -> Result<(), ExportError> { + let new_inner = WasiEnvInner { + memory: instance.exports.get_memory("memory")?.clone(), + reactors: instance.reactors.clone(), + thread_spawn: instance.exports.get_typed_function(store, "_start_thread").ok(), + react: instance.exports.get_typed_function(store, "_react").ok(), + thread_local_destroy: instance.exports.get_typed_function(store, "_thread_local_destroy").ok(), + _malloc: instance.exports.get_typed_function(store, "_malloc").ok(), + _free: instance.exports.get_typed_function(store, "_free").ok() + }; + + let env = self.data_mut(store); + env.inner.replace(new_inner); + Ok(()) + } + + /// Like `import_object` but containing all the WASI versions detected in + /// the module. + pub fn import_object_for_all_wasi_versions( + &self, + store: &mut impl AsStoreMut, + module: &Module, + ) -> Result { + let wasi_versions = + get_wasi_versions(module, false).ok_or(WasiError::UnknownWasiVersion)?; + + let mut resolver = Imports::new(); + for version in wasi_versions.iter() { + let new_import_object = generate_import_object_from_env(store, &self.env, *version); + for ((n, m), e) in new_import_object.into_iter() { + resolver.define(&n, &m, e); + } + } + + if is_wasix_module(module) { + self.data(store) + .state + .fs + .is_wasix + .store(true, std::sync::atomic::Ordering::Release); + } + + Ok(resolver) + } +} + +/// Create an [`Imports`] with an existing [`WasiEnv`]. `WasiEnv` +/// needs a [`WasiState`], that can be constructed from a +/// [`WasiStateBuilder`](state::WasiStateBuilder). pub fn generate_import_object_from_env( store: &mut impl AsStoreMut, ctx: &FunctionEnv, @@ -392,6 +406,7 @@ pub fn generate_import_object_from_env( } fn wasi_unstable_exports(mut store: &mut impl AsStoreMut, ctx: &FunctionEnv) -> Exports { + use syscalls::*; let namespace = namespace! { "args_get" => Function::new_native(&mut store, ctx, args_get::), "args_sizes_get" => Function::new_native(&mut store, ctx, args_sizes_get::), @@ -446,6 +461,63 @@ fn wasi_snapshot_preview1_exports( mut store: &mut impl AsStoreMut, ctx: &FunctionEnv, ) -> Exports { + use syscalls::*; + let namespace = namespace! { + "args_get" => Function::new_native(&mut store, ctx, args_get::), + "args_sizes_get" => Function::new_native(&mut store, ctx, args_sizes_get::), + "clock_res_get" => Function::new_native(&mut store, ctx, clock_res_get::), + "clock_time_get" => Function::new_native(&mut store, ctx, clock_time_get::), + "environ_get" => Function::new_native(&mut store, ctx, environ_get::), + "environ_sizes_get" => Function::new_native(&mut store, ctx, environ_sizes_get::), + "fd_advise" => Function::new_native(&mut store, ctx, fd_advise), + "fd_allocate" => Function::new_native(&mut store, ctx, fd_allocate), + "fd_close" => Function::new_native(&mut store, ctx, fd_close), + "fd_datasync" => Function::new_native(&mut store, ctx, fd_datasync), + "fd_fdstat_get" => Function::new_native(&mut store, ctx, fd_fdstat_get::), + "fd_fdstat_set_flags" => Function::new_native(&mut store, ctx, fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native(&mut store, ctx, fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native(&mut store, ctx, fd_filestat_get::), + "fd_filestat_set_size" => Function::new_native(&mut store, ctx, fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native(&mut store, ctx, fd_filestat_set_times), + "fd_pread" => Function::new_native(&mut store, ctx, fd_pread::), + "fd_prestat_get" => Function::new_native(&mut store, ctx, fd_prestat_get::), + "fd_prestat_dir_name" => Function::new_native(&mut store, ctx, fd_prestat_dir_name::), + "fd_pwrite" => Function::new_native(&mut store, ctx, fd_pwrite::), + "fd_read" => Function::new_native(&mut store, ctx, fd_read::), + "fd_readdir" => Function::new_native(&mut store, ctx, fd_readdir::), + "fd_renumber" => Function::new_native(&mut store, ctx, fd_renumber), + "fd_seek" => Function::new_native(&mut store, ctx, fd_seek::), + "fd_sync" => Function::new_native(&mut store, ctx, fd_sync), + "fd_tell" => Function::new_native(&mut store, ctx, fd_tell::), + "fd_write" => Function::new_native(&mut store, ctx, fd_write::), + "path_create_directory" => Function::new_native(&mut store, ctx, path_create_directory::), + "path_filestat_get" => Function::new_native(&mut store, ctx, path_filestat_get::), + "path_filestat_set_times" => Function::new_native(&mut store, ctx, path_filestat_set_times::), + "path_link" => Function::new_native(&mut store, ctx, path_link::), + "path_open" => Function::new_native(&mut store, ctx, path_open::), + "path_readlink" => Function::new_native(&mut store, ctx, path_readlink::), + "path_remove_directory" => Function::new_native(&mut store, ctx, path_remove_directory::), + "path_rename" => Function::new_native(&mut store, ctx, path_rename::), + "path_symlink" => Function::new_native(&mut store, ctx, path_symlink::), + "path_unlink_file" => Function::new_native(&mut store, ctx, path_unlink_file::), + "poll_oneoff" => Function::new_native(&mut store, ctx, poll_oneoff::), + "proc_exit" => Function::new_native(&mut store, ctx, proc_exit), + "proc_raise" => Function::new_native(&mut store, ctx, proc_raise), + "random_get" => Function::new_native(&mut store, ctx, random_get::), + "sched_yield" => Function::new_native(&mut store, ctx, sched_yield), + "sock_recv" => Function::new_native(&mut store, ctx, sock_recv::), + "sock_send" => Function::new_native(&mut store, ctx, sock_send::), + "sock_shutdown" => Function::new_native(&mut store, ctx, sock_shutdown), + }; + namespace +} + +fn wasix_exports_32( + mut store: &mut impl AsStoreMut, + ctx: &FunctionEnv, +) -> Exports +{ + use syscalls::*; let namespace = namespace! { "args_get" => Function::new_native(&mut store, ctx, args_get::), "args_sizes_get" => Function::new_native(&mut store, ctx, args_sizes_get::), @@ -470,10 +542,13 @@ fn wasi_snapshot_preview1_exports( "fd_read" => Function::new_native(&mut store, ctx, fd_read::), "fd_readdir" => Function::new_native(&mut store, ctx, fd_readdir::), "fd_renumber" => Function::new_native(&mut store, ctx, fd_renumber), + "fd_dup" => Function::new_native(&mut store, ctx, fd_dup::), + "fd_event" => Function::new_native(&mut store, ctx, fd_event::), "fd_seek" => Function::new_native(&mut store, ctx, fd_seek::), "fd_sync" => Function::new_native(&mut store, ctx, fd_sync), "fd_tell" => Function::new_native(&mut store, ctx, fd_tell::), "fd_write" => Function::new_native(&mut store, ctx, fd_write::), + "fd_pipe" => Function::new_native(&mut store, ctx, fd_pipe::), "path_create_directory" => Function::new_native(&mut store, ctx, path_create_directory::), "path_filestat_get" => Function::new_native(&mut store, ctx, path_filestat_get::), "path_filestat_set_times" => Function::new_native(&mut store, ctx, path_filestat_set_times::), @@ -488,22 +563,218 @@ fn wasi_snapshot_preview1_exports( "proc_exit" => Function::new_native(&mut store, ctx, proc_exit), "proc_raise" => Function::new_native(&mut store, ctx, proc_raise), "random_get" => Function::new_native(&mut store, ctx, random_get::), + "tty_get" => Function::new_native(&mut store, ctx, tty_get::), + "tty_set" => Function::new_native(&mut store, ctx, tty_set::), + "getcwd" => Function::new_native(&mut store, ctx, getcwd::), + "chdir" => Function::new_native(&mut store, ctx, chdir::), + "thread_spawn" => Function::new_native(&mut store, ctx, thread_spawn::), + "thread_local_create" => Function::new_native(&mut store, ctx, thread_local_create::), + "thread_local_destroy" => Function::new_native(&mut store, ctx, thread_local_destroy), + "thread_local_set" => Function::new_native(&mut store, ctx, thread_local_set), + "thread_local_get" => Function::new_native(&mut store, ctx, thread_local_get::), + "thread_sleep" => Function::new_native(&mut store, ctx, thread_sleep), + "thread_id" => Function::new_native(&mut store, ctx, thread_id::), + "thread_join" => Function::new_native(&mut store, ctx, thread_join), + "thread_parallelism" => Function::new_native(&mut store, ctx, thread_parallelism::), + "thread_exit" => Function::new_native(&mut store, ctx, thread_exit), "sched_yield" => Function::new_native(&mut store, ctx, sched_yield), + "futex_wait" => Function::new_native(&mut store, ctx, futex_wait::), + "futex_wake" => Function::new_native(&mut store, ctx, futex_wake::), + "futex_wake_all" => Function::new_native(&mut store, ctx, futex_wake_all::), + "getpid" => Function::new_native(&mut store, ctx, getpid::), + "process_spawn" => Function::new_native(&mut store, ctx, process_spawn::), + "bus_open_local" => Function::new_native(&mut store, ctx, bus_open_local::), + "bus_open_remote" => Function::new_native(&mut store, ctx, bus_open_remote::), + "bus_close" => Function::new_native(&mut store, ctx, bus_close), + "bus_call" => Function::new_native(&mut store, ctx, bus_call::), + "bus_subcall" => Function::new_native(&mut store, ctx, bus_subcall::), + "bus_poll" => Function::new_native(&mut store, ctx, bus_poll::), + "call_reply" => Function::new_native(&mut store, ctx, call_reply::), + "call_fault" => Function::new_native(&mut store, ctx, call_fault), + "call_close" => Function::new_native(&mut store, ctx, call_close), + "ws_connect" => Function::new_native(&mut store, ctx, ws_connect::), + "http_request" => Function::new_native(&mut store, ctx, http_request::), + "http_status" => Function::new_native(&mut store, ctx, http_status::), + "port_bridge" => Function::new_native(&mut store, ctx, port_bridge::), + "port_unbridge" => Function::new_native(&mut store, ctx, port_unbridge), + "port_dhcp_acquire" => Function::new_native(&mut store, ctx, port_dhcp_acquire), + "port_addr_add" => Function::new_native(&mut store, ctx, port_addr_add::), + "port_addr_remove" => Function::new_native(&mut store, ctx, port_addr_remove::), + "port_addr_clear" => Function::new_native(&mut store, ctx, port_addr_clear), + "port_addr_list" => Function::new_native(&mut store, ctx, port_addr_list::), + "port_mac" => Function::new_native(&mut store, ctx, port_mac::), + "port_gateway_set" => Function::new_native(&mut store, ctx, port_gateway_set::), + "port_route_add" => Function::new_native(&mut store, ctx, port_route_add::), + "port_route_remove" => Function::new_native(&mut store, ctx, port_route_remove::), + "port_route_clear" => Function::new_native(&mut store, ctx, port_route_clear), + "port_route_list" => Function::new_native(&mut store, ctx, port_route_list::), + "sock_status" => Function::new_native(&mut store, ctx, sock_status::), + "sock_addr_local" => Function::new_native(&mut store, ctx, sock_addr_local::), + "sock_addr_peer" => Function::new_native(&mut store, ctx, sock_addr_peer::), + "sock_open" => Function::new_native(&mut store, ctx, sock_open::), + "sock_set_opt_flag" => Function::new_native(&mut store, ctx, sock_set_opt_flag), + "sock_get_opt_flag" => Function::new_native(&mut store, ctx, sock_get_opt_flag::), + "sock_set_opt_time" => Function::new_native(&mut store, ctx, sock_set_opt_time::), + "sock_get_opt_time" => Function::new_native(&mut store, ctx, sock_get_opt_time::), + "sock_set_opt_size" => Function::new_native(&mut store, ctx, sock_set_opt_size), + "sock_get_opt_size" => Function::new_native(&mut store, ctx, sock_get_opt_size::), + "sock_join_multicast_v4" => Function::new_native(&mut store, ctx, sock_join_multicast_v4::), + "sock_leave_multicast_v4" => Function::new_native(&mut store, ctx, sock_leave_multicast_v4::), + "sock_join_multicast_v6" => Function::new_native(&mut store, ctx, sock_join_multicast_v6::), + "sock_leave_multicast_v6" => Function::new_native(&mut store, ctx, sock_leave_multicast_v6::), + "sock_bind" => Function::new_native(&mut store, ctx, sock_bind::), + "sock_listen" => Function::new_native(&mut store, ctx, sock_listen::), + "sock_accept" => Function::new_native(&mut store, ctx, sock_accept::), + "sock_connect" => Function::new_native(&mut store, ctx, sock_connect::), "sock_recv" => Function::new_native(&mut store, ctx, sock_recv::), + "sock_recv_from" => Function::new_native(&mut store, ctx, sock_recv_from::), "sock_send" => Function::new_native(&mut store, ctx, sock_send::), + "sock_send_to" => Function::new_native(&mut store, ctx, sock_send_to::), + "sock_send_file" => Function::new_native(&mut store, ctx, sock_send_file::), "sock_shutdown" => Function::new_native(&mut store, ctx, sock_shutdown), + "resolve" => Function::new_native(&mut store, ctx, resolve::), }; namespace } + +fn wasix_exports_64( + mut store: &mut impl AsStoreMut, + ctx: &FunctionEnv, +) -> Exports +{ + use syscalls::*; + let namespace = namespace! { + "args_get" => Function::new_native(&mut store, ctx, args_get::), + "args_sizes_get" => Function::new_native(&mut store, ctx, args_sizes_get::), + "clock_res_get" => Function::new_native(&mut store, ctx, clock_res_get::), + "clock_time_get" => Function::new_native(&mut store, ctx, clock_time_get::), + "environ_get" => Function::new_native(&mut store, ctx, environ_get::), + "environ_sizes_get" => Function::new_native(&mut store, ctx, environ_sizes_get::), + "fd_advise" => Function::new_native(&mut store, ctx, fd_advise), + "fd_allocate" => Function::new_native(&mut store, ctx, fd_allocate), + "fd_close" => Function::new_native(&mut store, ctx, fd_close), + "fd_datasync" => Function::new_native(&mut store, ctx, fd_datasync), + "fd_fdstat_get" => Function::new_native(&mut store, ctx, fd_fdstat_get::), + "fd_fdstat_set_flags" => Function::new_native(&mut store, ctx, fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native(&mut store, ctx, fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native(&mut store, ctx, fd_filestat_get::), + "fd_filestat_set_size" => Function::new_native(&mut store, ctx, fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native(&mut store, ctx, fd_filestat_set_times), + "fd_pread" => Function::new_native(&mut store, ctx, fd_pread::), + "fd_prestat_get" => Function::new_native(&mut store, ctx, fd_prestat_get::), + "fd_prestat_dir_name" => Function::new_native(&mut store, ctx, fd_prestat_dir_name::), + "fd_pwrite" => Function::new_native(&mut store, ctx, fd_pwrite::), + "fd_read" => Function::new_native(&mut store, ctx, fd_read::), + "fd_readdir" => Function::new_native(&mut store, ctx, fd_readdir::), + "fd_renumber" => Function::new_native(&mut store, ctx, fd_renumber), + "fd_dup" => Function::new_native(&mut store, ctx, fd_dup::), + "fd_event" => Function::new_native(&mut store, ctx, fd_event::), + "fd_seek" => Function::new_native(&mut store, ctx, fd_seek::), + "fd_sync" => Function::new_native(&mut store, ctx, fd_sync), + "fd_tell" => Function::new_native(&mut store, ctx, fd_tell::), + "fd_write" => Function::new_native(&mut store, ctx, fd_write::), + "fd_pipe" => Function::new_native(&mut store, ctx, fd_pipe::), + "path_create_directory" => Function::new_native(&mut store, ctx, path_create_directory::), + "path_filestat_get" => Function::new_native(&mut store, ctx, path_filestat_get::), + "path_filestat_set_times" => Function::new_native(&mut store, ctx, path_filestat_set_times::), + "path_link" => Function::new_native(&mut store, ctx, path_link::), + "path_open" => Function::new_native(&mut store, ctx, path_open::), + "path_readlink" => Function::new_native(&mut store, ctx, path_readlink::), + "path_remove_directory" => Function::new_native(&mut store, ctx, path_remove_directory::), + "path_rename" => Function::new_native(&mut store, ctx, path_rename::), + "path_symlink" => Function::new_native(&mut store, ctx, path_symlink::), + "path_unlink_file" => Function::new_native(&mut store, ctx, path_unlink_file::), + "poll_oneoff" => Function::new_native(&mut store, ctx, poll_oneoff::), + "proc_exit" => Function::new_native(&mut store, ctx, proc_exit), + "proc_raise" => Function::new_native(&mut store, ctx, proc_raise), + "random_get" => Function::new_native(&mut store, ctx, random_get::), + "tty_get" => Function::new_native(&mut store, ctx, tty_get::), + "tty_set" => Function::new_native(&mut store, ctx, tty_set::), + "getcwd" => Function::new_native(&mut store, ctx, getcwd::), + "chdir" => Function::new_native(&mut store, ctx, chdir::), + "thread_spawn" => Function::new_native(&mut store, ctx, thread_spawn::), + "thread_local_create" => Function::new_native(&mut store, ctx, thread_local_create::), + "thread_local_destroy" => Function::new_native(&mut store, ctx, thread_local_destroy), + "thread_local_set" => Function::new_native(&mut store, ctx, thread_local_set), + "thread_local_get" => Function::new_native(&mut store, ctx, thread_local_get::), + "thread_sleep" => Function::new_native(&mut store, ctx, thread_sleep), + "thread_id" => Function::new_native(&mut store, ctx, thread_id::), + "thread_join" => Function::new_native(&mut store, ctx, thread_join), + "thread_parallelism" => Function::new_native(&mut store, ctx, thread_parallelism::), + "thread_exit" => Function::new_native(&mut store, ctx, thread_exit), + "sched_yield" => Function::new_native(&mut store, ctx, sched_yield), + "futex_wait" => Function::new_native(&mut store, ctx, futex_wait::), + "futex_wake" => Function::new_native(&mut store, ctx, futex_wake::), + "futex_wake_all" => Function::new_native(&mut store, ctx, futex_wake_all::), + "getpid" => Function::new_native(&mut store, ctx, getpid::), + "process_spawn" => Function::new_native(&mut store, ctx, process_spawn::), + "bus_open_local" => Function::new_native(&mut store, ctx, bus_open_local::), + "bus_open_remote" => Function::new_native(&mut store, ctx, bus_open_remote::), + "bus_close" => Function::new_native(&mut store, ctx, bus_close), + "bus_call" => Function::new_native(&mut store, ctx, bus_call::), + "bus_subcall" => Function::new_native(&mut store, ctx, bus_subcall::), + "bus_poll" => Function::new_native(&mut store, ctx, bus_poll::), + "call_reply" => Function::new_native(&mut store, ctx, call_reply::), + "call_fault" => Function::new_native(&mut store, ctx, call_fault), + "call_close" => Function::new_native(&mut store, ctx, call_close), + "ws_connect" => Function::new_native(&mut store, ctx, ws_connect::), + "http_request" => Function::new_native(&mut store, ctx, http_request::), + "http_status" => Function::new_native(&mut store, ctx, http_status::), + "port_bridge" => Function::new_native(&mut store, ctx, port_bridge::), + "port_unbridge" => Function::new_native(&mut store, ctx, port_unbridge), + "port_dhcp_acquire" => Function::new_native(&mut store, ctx, port_dhcp_acquire), + "port_addr_add" => Function::new_native(&mut store, ctx, port_addr_add::), + "port_addr_remove" => Function::new_native(&mut store, ctx, port_addr_remove::), + "port_addr_clear" => Function::new_native(&mut store, ctx, port_addr_clear), + "port_addr_list" => Function::new_native(&mut store, ctx, port_addr_list::), + "port_mac" => Function::new_native(&mut store, ctx, port_mac::), + "port_gateway_set" => Function::new_native(&mut store, ctx, port_gateway_set::), + "port_route_add" => Function::new_native(&mut store, ctx, port_route_add::), + "port_route_remove" => Function::new_native(&mut store, ctx, port_route_remove::), + "port_route_clear" => Function::new_native(&mut store, ctx, port_route_clear), + "port_route_list" => Function::new_native(&mut store, ctx, port_route_list::), + "sock_status" => Function::new_native(&mut store, ctx, sock_status::), + "sock_addr_local" => Function::new_native(&mut store, ctx, sock_addr_local::), + "sock_addr_peer" => Function::new_native(&mut store, ctx, sock_addr_peer::), + "sock_open" => Function::new_native(&mut store, ctx, sock_open::), + "sock_set_opt_flag" => Function::new_native(&mut store, ctx, sock_set_opt_flag), + "sock_get_opt_flag" => Function::new_native(&mut store, ctx, sock_get_opt_flag::), + "sock_set_opt_time" => Function::new_native(&mut store, ctx, sock_set_opt_time::), + "sock_get_opt_time" => Function::new_native(&mut store, ctx, sock_get_opt_time::), + "sock_set_opt_size" => Function::new_native(&mut store, ctx, sock_set_opt_size), + "sock_get_opt_size" => Function::new_native(&mut store, ctx, sock_get_opt_size::), + "sock_join_multicast_v4" => Function::new_native(&mut store, ctx, sock_join_multicast_v4::), + "sock_leave_multicast_v4" => Function::new_native(&mut store, ctx, sock_leave_multicast_v4::), + "sock_join_multicast_v6" => Function::new_native(&mut store, ctx, sock_join_multicast_v6::), + "sock_leave_multicast_v6" => Function::new_native(&mut store, ctx, sock_leave_multicast_v6::), + "sock_bind" => Function::new_native(&mut store, ctx, sock_bind::), + "sock_listen" => Function::new_native(&mut store, ctx, sock_listen::), + "sock_accept" => Function::new_native(&mut store, ctx, sock_accept::), + "sock_connect" => Function::new_native(&mut store, ctx, sock_connect::), + "sock_recv" => Function::new_native(&mut store, ctx, sock_recv::), + "sock_recv_from" => Function::new_native(&mut store, ctx, sock_recv_from::), + "sock_send" => Function::new_native(&mut store, ctx, sock_send::), + "sock_send_to" => Function::new_native(&mut store, ctx, sock_send_to::), + "sock_send_file" => Function::new_native(&mut store, ctx, sock_send_file::), + "sock_shutdown" => Function::new_native(&mut store, ctx, sock_shutdown), + "resolve" => Function::new_native(&mut store, ctx, resolve::), + }; + namespace +} + pub fn import_object_for_all_wasi_versions( store: &mut impl AsStoreMut, ctx: &FunctionEnv, ) -> Imports { - let wasi_unstable_exports = wasi_unstable_exports(store, ctx); - let wasi_snapshot_preview1_exports = wasi_snapshot_preview1_exports(store, ctx); + let exports_wasi_unstable = wasi_unstable_exports(store, ctx); + let exports_wasi_snapshot_preview1 = wasi_snapshot_preview1_exports(store, ctx); + let exports_wasix_32v1 = wasix_exports_32(store, ctx); + let exports_wasix_64v1 = wasix_exports_64(store, ctx); imports! { - "wasi_unstable" => wasi_unstable_exports, - "wasi_snapshot_preview1" => wasi_snapshot_preview1_exports, + "wasi_unstable" => exports_wasi_unstable, + "wasi_snapshot_preview1" => exports_wasi_snapshot_preview1, + "wasix_32v1" => exports_wasix_32v1, + "wasix_64v1" => exports_wasix_64v1, } } @@ -512,9 +783,9 @@ fn generate_import_object_snapshot0( store: &mut impl AsStoreMut, ctx: &FunctionEnv, ) -> Imports { - let wasi_unstable_exports = wasi_unstable_exports(store, ctx); + let exports_unstable = wasi_unstable_exports(store, ctx); imports! { - "wasi_unstable" => wasi_unstable_exports + "wasi_unstable" => exports_unstable } } @@ -522,246 +793,30 @@ fn generate_import_object_snapshot1( store: &mut impl AsStoreMut, ctx: &FunctionEnv, ) -> Imports { - let wasi_snapshot_preview1_exports = wasi_snapshot_preview1_exports(store, ctx); + let exports_wasi_snapshot_preview1 = wasi_snapshot_preview1_exports(store, ctx); imports! { - "wasi_snapshot_preview1" => wasi_snapshot_preview1_exports + "wasi_snapshot_preview1" => exports_wasi_snapshot_preview1 } } /// Combines a state generating function with the import list for snapshot 1 fn generate_import_object_wasix32_v1( - mut store: &mut impl AsStoreMut, + store: &mut impl AsStoreMut, ctx: &FunctionEnv, ) -> Imports { - use self::wasix32::*; + let exports_wasix_32v1 = wasix_exports_32(store, ctx); imports! { - "wasix_32v1" => { - "args_get" => Function::new_native(&mut store, ctx, args_get), - "args_sizes_get" => Function::new_native(&mut store, ctx, args_sizes_get), - "clock_res_get" => Function::new_native(&mut store, ctx, clock_res_get), - "clock_time_get" => Function::new_native(&mut store, ctx, clock_time_get), - "environ_get" => Function::new_native(&mut store, ctx, environ_get), - "environ_sizes_get" => Function::new_native(&mut store, ctx, environ_sizes_get), - "fd_advise" => Function::new_native(&mut store, ctx, fd_advise), - "fd_allocate" => Function::new_native(&mut store, ctx, fd_allocate), - "fd_close" => Function::new_native(&mut store, ctx, fd_close), - "fd_datasync" => Function::new_native(&mut store, ctx, fd_datasync), - "fd_fdstat_get" => Function::new_native(&mut store, ctx, fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_native(&mut store, ctx, fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_native(&mut store, ctx, fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_native(&mut store, ctx, fd_filestat_get), - "fd_filestat_set_size" => Function::new_native(&mut store, ctx, fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_native(&mut store, ctx, fd_filestat_set_times), - "fd_pread" => Function::new_native(&mut store, ctx, fd_pread), - "fd_prestat_get" => Function::new_native(&mut store, ctx, fd_prestat_get), - "fd_prestat_dir_name" => Function::new_native(&mut store, ctx, fd_prestat_dir_name), - "fd_pwrite" => Function::new_native(&mut store, ctx, fd_pwrite), - "fd_read" => Function::new_native(&mut store, ctx, fd_read), - "fd_readdir" => Function::new_native(&mut store, ctx, fd_readdir), - "fd_renumber" => Function::new_native(&mut store, ctx, fd_renumber), - "fd_dup" => Function::new_native(&mut store, ctx, fd_dup), - "fd_event" => Function::new_native(&mut store, ctx, fd_event), - "fd_seek" => Function::new_native(&mut store, ctx, fd_seek), - "fd_sync" => Function::new_native(&mut store, ctx, fd_sync), - "fd_tell" => Function::new_native(&mut store, ctx, fd_tell), - "fd_write" => Function::new_native(&mut store, ctx, fd_write), - "fd_pipe" => Function::new_native(&mut store, ctx, fd_pipe), - "path_create_directory" => Function::new_native(&mut store, ctx, path_create_directory), - "path_filestat_get" => Function::new_native(&mut store, ctx, path_filestat_get), - "path_filestat_set_times" => Function::new_native(&mut store, ctx, path_filestat_set_times), - "path_link" => Function::new_native(&mut store, ctx, path_link), - "path_open" => Function::new_native(&mut store, ctx, path_open), - "path_readlink" => Function::new_native(&mut store, ctx, path_readlink), - "path_remove_directory" => Function::new_native(&mut store, ctx, path_remove_directory), - "path_rename" => Function::new_native(&mut store, ctx, path_rename), - "path_symlink" => Function::new_native(&mut store, ctx, path_symlink), - "path_unlink_file" => Function::new_native(&mut store, ctx, path_unlink_file), - "poll_oneoff" => Function::new_native(&mut store, ctx, poll_oneoff), - "proc_exit" => Function::new_native(&mut store, ctx, proc_exit), - "proc_raise" => Function::new_native(&mut store, ctx, proc_raise), - "random_get" => Function::new_native(&mut store, ctx, random_get), - "tty_get" => Function::new_native(&mut store, ctx, tty_get), - "tty_set" => Function::new_native(&mut store, ctx, tty_set), - "getcwd" => Function::new_native(&mut store, ctx, getcwd), - "chdir" => Function::new_native(&mut store, ctx, chdir), - "thread_spawn" => Function::new_native(&mut store, ctx, thread_spawn), - "thread_sleep" => Function::new_native(&mut store, ctx, thread_sleep), - "thread_id" => Function::new_native(&mut store, ctx, thread_id), - "thread_join" => Function::new_native(&mut store, ctx, thread_join), - "thread_parallelism" => Function::new_native(&mut store, ctx, thread_parallelism), - "thread_exit" => Function::new_native(&mut store, ctx, thread_exit), - "sched_yield" => Function::new_native(&mut store, ctx, sched_yield), - "getpid" => Function::new_native(&mut store, ctx, getpid), - "process_spawn" => Function::new_native(&mut store, ctx, process_spawn), - "bus_open_local" => Function::new_native(&mut store, ctx, bus_open_local), - "bus_open_remote" => Function::new_native(&mut store, ctx, bus_open_remote), - "bus_close" => Function::new_native(&mut store, ctx, bus_close), - "bus_call" => Function::new_native(&mut store, ctx, bus_call), - "bus_subcall" => Function::new_native(&mut store, ctx, bus_subcall), - "bus_poll" => Function::new_native(&mut store, ctx, bus_poll), - "call_reply" => Function::new_native(&mut store, ctx, call_reply), - "call_fault" => Function::new_native(&mut store, ctx, call_fault), - "call_close" => Function::new_native(&mut store, ctx, call_close), - "ws_connect" => Function::new_native(&mut store, ctx, ws_connect), - "http_request" => Function::new_native(&mut store, ctx, http_request), - "http_status" => Function::new_native(&mut store, ctx, http_status), - "port_bridge" => Function::new_native(&mut store, ctx, port_bridge), - "port_unbridge" => Function::new_native(&mut store, ctx, port_unbridge), - "port_dhcp_acquire" => Function::new_native(&mut store, ctx, port_dhcp_acquire), - "port_addr_add" => Function::new_native(&mut store, ctx, port_addr_add), - "port_addr_remove" => Function::new_native(&mut store, ctx, port_addr_remove), - "port_addr_clear" => Function::new_native(&mut store, ctx, port_addr_clear), - "port_addr_list" => Function::new_native(&mut store, ctx, port_addr_list), - "port_mac" => Function::new_native(&mut store, ctx, port_mac), - "port_gateway_set" => Function::new_native(&mut store, ctx, port_gateway_set), - "port_route_add" => Function::new_native(&mut store, ctx, port_route_add), - "port_route_remove" => Function::new_native(&mut store, ctx, port_route_remove), - "port_route_clear" => Function::new_native(&mut store, ctx, port_route_clear), - "port_route_list" => Function::new_native(&mut store, ctx, port_route_list), - "sock_status" => Function::new_native(&mut store, ctx, sock_status), - "sock_addr_local" => Function::new_native(&mut store, ctx, sock_addr_local), - "sock_addr_peer" => Function::new_native(&mut store, ctx, sock_addr_peer), - "sock_open" => Function::new_native(&mut store, ctx, sock_open), - "sock_set_opt_flag" => Function::new_native(&mut store, ctx, sock_set_opt_flag), - "sock_get_opt_flag" => Function::new_native(&mut store, ctx, sock_get_opt_flag), - "sock_set_opt_time" => Function::new_native(&mut store, ctx, sock_set_opt_time), - "sock_get_opt_time" => Function::new_native(&mut store, ctx, sock_get_opt_time), - "sock_set_opt_size" => Function::new_native(&mut store, ctx, sock_set_opt_size), - "sock_get_opt_size" => Function::new_native(&mut store, ctx, sock_get_opt_size), - "sock_join_multicast_v4" => Function::new_native(&mut store, ctx, sock_join_multicast_v4), - "sock_leave_multicast_v4" => Function::new_native(&mut store, ctx, sock_leave_multicast_v4), - "sock_join_multicast_v6" => Function::new_native(&mut store, ctx, sock_join_multicast_v6), - "sock_leave_multicast_v6" => Function::new_native(&mut store, ctx, sock_leave_multicast_v6), - "sock_bind" => Function::new_native(&mut store, ctx, sock_bind), - "sock_listen" => Function::new_native(&mut store, ctx, sock_listen), - "sock_accept" => Function::new_native(&mut store, ctx, sock_accept), - "sock_connect" => Function::new_native(&mut store, ctx, sock_connect), - "sock_recv" => Function::new_native(&mut store, ctx, sock_recv), - "sock_recv_from" => Function::new_native(&mut store, ctx, sock_recv_from), - "sock_send" => Function::new_native(&mut store, ctx, sock_send), - "sock_send_to" => Function::new_native(&mut store, ctx, sock_send_to), - "sock_send_file" => Function::new_native(&mut store, ctx, sock_send_file), - "sock_shutdown" => Function::new_native(&mut store, ctx, sock_shutdown), - "resolve" => Function::new_native(&mut store, ctx, resolve), - } + "wasix_32v1" => exports_wasix_32v1 } } fn generate_import_object_wasix64_v1( - mut store: &mut impl AsStoreMut, + store: &mut impl AsStoreMut, ctx: &FunctionEnv, ) -> Imports { - use self::wasix64::*; + let exports_wasix_64v1 = wasix_exports_64(store, ctx); imports! { - "wasix_64v1" => { - "args_get" => Function::new_native(&mut store, ctx, args_get), - "args_sizes_get" => Function::new_native(&mut store, ctx, args_sizes_get), - "clock_res_get" => Function::new_native(&mut store, ctx, clock_res_get), - "clock_time_get" => Function::new_native(&mut store, ctx, clock_time_get), - "environ_get" => Function::new_native(&mut store, ctx, environ_get), - "environ_sizes_get" => Function::new_native(&mut store, ctx, environ_sizes_get), - "fd_advise" => Function::new_native(&mut store, ctx, fd_advise), - "fd_allocate" => Function::new_native(&mut store, ctx, fd_allocate), - "fd_close" => Function::new_native(&mut store, ctx, fd_close), - "fd_datasync" => Function::new_native(&mut store, ctx, fd_datasync), - "fd_fdstat_get" => Function::new_native(&mut store, ctx, fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_native(&mut store, ctx, fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_native(&mut store, ctx, fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_native(&mut store, ctx, fd_filestat_get), - "fd_filestat_set_size" => Function::new_native(&mut store, ctx, fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_native(&mut store, ctx, fd_filestat_set_times), - "fd_pread" => Function::new_native(&mut store, ctx, fd_pread), - "fd_prestat_get" => Function::new_native(&mut store, ctx, fd_prestat_get), - "fd_prestat_dir_name" => Function::new_native(&mut store, ctx, fd_prestat_dir_name), - "fd_pwrite" => Function::new_native(&mut store, ctx, fd_pwrite), - "fd_read" => Function::new_native(&mut store, ctx, fd_read), - "fd_readdir" => Function::new_native(&mut store, ctx, fd_readdir), - "fd_renumber" => Function::new_native(&mut store, ctx, fd_renumber), - "fd_dup" => Function::new_native(&mut store, ctx, fd_dup), - "fd_event" => Function::new_native(&mut store, ctx, fd_event), - "fd_seek" => Function::new_native(&mut store, ctx, fd_seek), - "fd_sync" => Function::new_native(&mut store, ctx, fd_sync), - "fd_tell" => Function::new_native(&mut store, ctx, fd_tell), - "fd_write" => Function::new_native(&mut store, ctx, fd_write), - "fd_pipe" => Function::new_native(&mut store, ctx, fd_pipe), - "path_create_directory" => Function::new_native(&mut store, ctx, path_create_directory), - "path_filestat_get" => Function::new_native(&mut store, ctx, path_filestat_get), - "path_filestat_set_times" => Function::new_native(&mut store, ctx, path_filestat_set_times), - "path_link" => Function::new_native(&mut store, ctx, path_link), - "path_open" => Function::new_native(&mut store, ctx, path_open), - "path_readlink" => Function::new_native(&mut store, ctx, path_readlink), - "path_remove_directory" => Function::new_native(&mut store, ctx, path_remove_directory), - "path_rename" => Function::new_native(&mut store, ctx, path_rename), - "path_symlink" => Function::new_native(&mut store, ctx, path_symlink), - "path_unlink_file" => Function::new_native(&mut store, ctx, path_unlink_file), - "poll_oneoff" => Function::new_native(&mut store, ctx, poll_oneoff), - "proc_exit" => Function::new_native(&mut store, ctx, proc_exit), - "proc_raise" => Function::new_native(&mut store, ctx, proc_raise), - "random_get" => Function::new_native(&mut store, ctx, random_get), - "tty_get" => Function::new_native(&mut store, ctx, tty_get), - "tty_set" => Function::new_native(&mut store, ctx, tty_set), - "getcwd" => Function::new_native(&mut store, ctx, getcwd), - "chdir" => Function::new_native(&mut store, ctx, chdir), - "thread_spawn" => Function::new_native(&mut store, ctx, thread_spawn), - "thread_sleep" => Function::new_native(&mut store, ctx, thread_sleep), - "thread_id" => Function::new_native(&mut store, ctx, thread_id), - "thread_join" => Function::new_native(&mut store, ctx, thread_join), - "thread_parallelism" => Function::new_native(&mut store, ctx, thread_parallelism), - "thread_exit" => Function::new_native(&mut store, ctx, thread_exit), - "sched_yield" => Function::new_native(&mut store, ctx, sched_yield), - "getpid" => Function::new_native(&mut store, ctx, getpid), - "process_spawn" => Function::new_native(&mut store, ctx, process_spawn), - "bus_open_local" => Function::new_native(&mut store, ctx, bus_open_local), - "bus_open_remote" => Function::new_native(&mut store, ctx, bus_open_remote), - "bus_close" => Function::new_native(&mut store, ctx, bus_close), - "bus_call" => Function::new_native(&mut store, ctx, bus_call), - "bus_subcall" => Function::new_native(&mut store, ctx, bus_subcall), - "bus_poll" => Function::new_native(&mut store, ctx, bus_poll), - "call_reply" => Function::new_native(&mut store, ctx, call_reply), - "call_fault" => Function::new_native(&mut store, ctx, call_fault), - "call_close" => Function::new_native(&mut store, ctx, call_close), - "ws_connect" => Function::new_native(&mut store, ctx, ws_connect), - "http_request" => Function::new_native(&mut store, ctx, http_request), - "http_status" => Function::new_native(&mut store, ctx, http_status), - "port_bridge" => Function::new_native(&mut store, ctx, port_bridge), - "port_unbridge" => Function::new_native(&mut store, ctx, port_unbridge), - "port_dhcp_acquire" => Function::new_native(&mut store, ctx, port_dhcp_acquire), - "port_addr_add" => Function::new_native(&mut store, ctx, port_addr_add), - "port_addr_remove" => Function::new_native(&mut store, ctx, port_addr_remove), - "port_addr_clear" => Function::new_native(&mut store, ctx, port_addr_clear), - "port_addr_list" => Function::new_native(&mut store, ctx, port_addr_list), - "port_mac" => Function::new_native(&mut store, ctx, port_mac), - "port_gateway_set" => Function::new_native(&mut store, ctx, port_gateway_set), - "port_route_add" => Function::new_native(&mut store, ctx, port_route_add), - "port_route_remove" => Function::new_native(&mut store, ctx, port_route_remove), - "port_route_clear" => Function::new_native(&mut store, ctx, port_route_clear), - "port_route_list" => Function::new_native(&mut store, ctx, port_route_list), - "sock_status" => Function::new_native(&mut store, ctx, sock_status), - "sock_addr_local" => Function::new_native(&mut store, ctx, sock_addr_local), - "sock_addr_peer" => Function::new_native(&mut store, ctx, sock_addr_peer), - "sock_open" => Function::new_native(&mut store, ctx, sock_open), - "sock_set_opt_flag" => Function::new_native(&mut store, ctx, sock_set_opt_flag), - "sock_get_opt_flag" => Function::new_native(&mut store, ctx, sock_get_opt_flag), - "sock_set_opt_time" => Function::new_native(&mut store, ctx, sock_set_opt_time), - "sock_get_opt_time" => Function::new_native(&mut store, ctx, sock_get_opt_time), - "sock_set_opt_size" => Function::new_native(&mut store, ctx, sock_set_opt_size), - "sock_get_opt_size" => Function::new_native(&mut store, ctx, sock_get_opt_size), - "sock_join_multicast_v4" => Function::new_native(&mut store, ctx, sock_join_multicast_v4), - "sock_leave_multicast_v4" => Function::new_native(&mut store, ctx, sock_leave_multicast_v4), - "sock_join_multicast_v6" => Function::new_native(&mut store, ctx, sock_join_multicast_v6), - "sock_leave_multicast_v6" => Function::new_native(&mut store, ctx, sock_leave_multicast_v6), - "sock_bind" => Function::new_native(&mut store, ctx, sock_bind), - "sock_listen" => Function::new_native(&mut store, ctx, sock_listen), - "sock_accept" => Function::new_native(&mut store, ctx, sock_accept), - "sock_connect" => Function::new_native(&mut store, ctx, sock_connect), - "sock_recv" => Function::new_native(&mut store, ctx, sock_recv), - "sock_recv_from" => Function::new_native(&mut store, ctx, sock_recv_from), - "sock_send" => Function::new_native(&mut store, ctx, sock_send), - "sock_send_to" => Function::new_native(&mut store, ctx, sock_send_to), - "sock_send_file" => Function::new_native(&mut store, ctx, sock_send_file), - "sock_shutdown" => Function::new_native(&mut store, ctx, sock_shutdown), - "resolve" => Function::new_native(&mut store, ctx, resolve), - } + "wasix_64v1" => exports_wasix_64v1 } } diff --git a/lib/wasi/src/macros.rs b/lib/wasi/src/macros.rs index bd6e6566d41..35fe919187c 100644 --- a/lib/wasi/src/macros.rs +++ b/lib/wasi/src/macros.rs @@ -7,7 +7,7 @@ macro_rules! wasi_try { let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr; match res { Ok(val) => { - tracing::trace!("wasi::wasi_try::val: {:?}", val); + //tracing::trace!("wasi::wasi_try::val: {:?}", val); val } Err(err) => { @@ -25,7 +25,7 @@ macro_rules! wasi_try_ok { let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr; match res { Ok(val) => { - tracing::trace!("wasi::wasi_try_ok::val: {:?}", val); + //tracing::trace!("wasi::wasi_try_ok::val: {:?}", val); val } Err(err) => { @@ -39,7 +39,7 @@ macro_rules! wasi_try_ok { let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr; match res { Ok(val) => { - tracing::trace!("wasi::wasi_try_ok::val: {:?}", val); + //tracing::trace!("wasi::wasi_try_ok::val: {:?}", val); val } Err(err) => { @@ -60,7 +60,7 @@ macro_rules! wasi_try_bus { let res: Result<_, crate::syscalls::types::__bus_errno_t> = $expr; match res { Ok(val) => { - tracing::trace!("wasi::wasi_try_bus::val: {:?}", val); + //tracing::trace!("wasi::wasi_try_bus::val: {:?}", val); val } Err(err) => { @@ -71,6 +71,24 @@ macro_rules! wasi_try_bus { }}; } +/// Like the `try!` macro or `?` syntax: returns the value if the computation +/// succeeded or returns the error value. +macro_rules! wasi_try_bus_ok { + ($expr:expr) => {{ + let res: Result<_, crate::syscalls::types::__bus_errno_t> = $expr; + match res { + Ok(val) => { + //tracing::trace!("wasi::wasi_try_bus::val: {:?}", val); + val + } + Err(err) => { + tracing::debug!("wasi::wasi_try_bus::err: {:?}", err); + return Ok(err); + } + } + }}; +} + /// Like `wasi_try` but converts a `MemoryAccessError` to a __wasi_errno_t`. macro_rules! wasi_try_mem { ($expr:expr) => {{ @@ -85,6 +103,13 @@ macro_rules! wasi_try_mem_bus { }}; } +/// Like `wasi_try` but converts a `MemoryAccessError` to a __bus_errno_t`. +macro_rules! wasi_try_mem_bus_ok { + ($expr:expr) => {{ + wasi_try_bus_ok!($expr.map_err($crate::mem_error_to_bus)) + }}; +} + /// Like `wasi_try` but converts a `MemoryAccessError` to a __wasi_errno_t`. macro_rules! wasi_try_mem_ok { ($expr:expr) => {{ @@ -108,3 +133,9 @@ macro_rules! get_input_str_bus { wasi_try_mem_bus!($data.read_utf8_string($ctx, $memory, $len)) }}; } + +macro_rules! get_input_str_bus_ok { + ($ctx:expr, $memory:expr, $data:expr, $len:expr) => {{ + wasi_try_mem_bus_ok!($data.read_utf8_string($ctx, $memory, $len)) + }}; +} diff --git a/lib/wasi/src/runtime.rs b/lib/wasi/src/runtime.rs index 00c208bd166..eb273b8e4d1 100644 --- a/lib/wasi/src/runtime.rs +++ b/lib/wasi/src/runtime.rs @@ -137,15 +137,29 @@ impl Default for PluggableRuntimeImplementation { } impl WasiRuntimeImplementation for PluggableRuntimeImplementation { - fn bus(&self) -> &(dyn VirtualBus) { + fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { self.bus.deref() } - fn networking(&self) -> &(dyn VirtualNetworking) { + fn networking<'a>(&'a self) -> &'a (dyn VirtualNetworking) { self.networking.deref() } fn thread_generate_id(&self) -> WasiThreadId { self.thread_id_seed.fetch_add(1, Ordering::Relaxed).into() } + + fn thread_spawn( + &self, + callback: Box, + ) -> Result<(), WasiThreadError> { + std::thread::spawn(callback); + Ok(()) + } + + fn thread_parallelism(&self) -> Result { + std::thread::available_parallelism() + .map(|a| usize::from(a)) + .map_err(|_| WasiThreadError::Unsupported) + } } diff --git a/lib/wasi/src/state/builder.rs b/lib/wasi/src/state/builder.rs index 3cacd30a24e..8111ac5b118 100644 --- a/lib/wasi/src/state/builder.rs +++ b/lib/wasi/src/state/builder.rs @@ -469,6 +469,8 @@ impl WasiStateBuilder { inodes: Arc::new(inodes), args: self.args.clone(), threading: Default::default(), + futexs: Default::default(), + bus: Default::default(), envs: self .envs .iter() diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 1f34a3f92fa..5c4efc21eb0 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -26,18 +26,23 @@ pub use self::guard::*; pub use self::pipe::*; pub use self::socket::*; pub use self::types::*; +pub use self::guard::*; +use crate::WasiThreadId; use crate::syscalls::types::*; use crate::utils::map_io_err; use crate::WasiBusProcessId; -use crate::WasiThread; -use crate::WasiThreadId; +use derivative::Derivative; use generational_arena::Arena; pub use generational_arena::Index as Inode; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; +use wasmer::ThreadControl; +use wasmer_vbus::VirtualBusCalled; +use wasmer_vbus::VirtualBusInvocation; use std::borrow::Cow; use std::collections::HashMap; use std::collections::VecDeque; +use std::sync::Condvar; use std::sync::mpsc; use std::sync::Arc; use std::{ @@ -83,7 +88,7 @@ pub const MAX_SYMLINKS: u32 = 128; pub struct InodeVal { pub stat: RwLock<__wasi_filestat_t>, pub is_preopened: bool, - pub name: String, + pub name: Cow<'static, str>, pub kind: RwLock, } @@ -668,7 +673,7 @@ impl WasiFs { inodes, kind, false, - segment_name.clone(), + segment_name.clone().into(), ); // reborrow to insert @@ -1000,7 +1005,7 @@ impl WasiFs { inodes, kind, false, - file.to_string_lossy().to_string(), + file.to_string_lossy().to_string().into(), __wasi_filestat_t { st_filetype: file_type, ..__wasi_filestat_t::default() @@ -1428,7 +1433,7 @@ impl WasiFs { name: String, ) -> Result { let stat = self.get_stat_for_kind(inodes, &kind)?; - Ok(self.create_inode_with_stat(inodes, kind, is_preopened, name, stat)) + Ok(self.create_inode_with_stat(inodes, kind, is_preopened, name.into(), stat)) } /// Creates an inode and inserts it given a Kind, does not assume the file exists. @@ -1437,7 +1442,7 @@ impl WasiFs { inodes: &mut WasiInodes, kind: Kind, is_preopened: bool, - name: String, + name: Cow<'static, str>, ) -> Inode { let stat = __wasi_filestat_t::default(); self.create_inode_with_stat(inodes, kind, is_preopened, name, stat) @@ -1449,7 +1454,7 @@ impl WasiFs { inodes: &mut WasiInodes, kind: Kind, is_preopened: bool, - name: String, + name: Cow<'static, str>, mut stat: __wasi_filestat_t, ) -> Inode { stat.st_ino = self.get_next_inode_index(); @@ -1527,7 +1532,7 @@ impl WasiFs { inodes.arena.insert(InodeVal { stat: RwLock::new(stat), is_preopened: true, - name: "/".to_string(), + name: "/".into(), kind: RwLock::new(root_kind), }) } @@ -1586,7 +1591,7 @@ impl WasiFs { inodes.arena.insert(InodeVal { stat: RwLock::new(stat), is_preopened: true, - name: name.to_string(), + name: name.to_string().into(), kind: RwLock::new(kind), }) }; @@ -1798,14 +1803,115 @@ impl WasiState { /// /// These internal implementation details are hidden away from the /// consumer who should instead implement the vbus trait on the runtime -#[derive(Debug, Default)] + +#[derive(Derivative, Default)] +#[derivative(Debug)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub(crate) struct WasiStateThreading { - pub threads: HashMap, - pub thread_seed: u32, - pub processes: HashMap, + threads: Arc>>, + thread_seed: WasiThreadId, + thread_count: Arc, + pub processes: HashMap>, pub process_reuse: HashMap, WasiBusProcessId>, pub process_seed: u32, + pub thread_local: HashMap<(WasiThreadId, u32), u64>, + pub thread_local_user_data: HashMap, + pub thread_local_seed: u32, + #[derivative(Debug = "ignore")] + pub chained_worker: Option u32 + Send + Sync>>, +} + +impl WasiStateThreading +{ + /// Creates a a thread and returns it + pub fn new_thread(&mut self) -> WasiThreadHandle { + let id = self.thread_seed.inc(); + let ctrl = ThreadControl::new(id.raw()); + { + let mut guard = self.threads.write().unwrap(); + guard.insert(id, ctrl); + } + self.thread_count.fetch_add(1, Ordering::AcqRel); + + WasiThreadHandle { + id, + threads: self.threads.clone(), + thread_count: self.thread_count.clone() + } + } + + pub fn get(&self, tid: &WasiThreadId) -> Option { + let guard = self.threads.read().unwrap(); + guard.get(tid).map(|a| a.clone()) + } + + pub fn active_threads(&self) -> u32 { + self.thread_count.load(Ordering::Acquire) + } +} + +#[derive(Debug)] +pub struct WasiThreadHandle { + id: WasiThreadId, + threads: Arc>>, + thread_count: Arc, +} + +impl WasiThreadHandle { + pub fn id(&self) -> WasiThreadId { + self.id + } +} + +impl Drop +for WasiThreadHandle { + fn drop(&mut self) { + if let Some(ctrl) = { + let mut guard = self.threads.write().unwrap(); + guard.remove(&self.id) + } { + ctrl.mark_exited(); + } + self.thread_count.fetch_sub(1, Ordering::AcqRel); + } +} + +/// Represents a futex which will make threads wait for completion in a more +/// CPU efficient manner +#[derive(Debug, Clone)] +pub struct WasiFutex { + pub(crate) refcnt: Arc, + pub(crate) inner: Arc<(Mutex<()>, Condvar)>, +} + +#[derive(Debug)] +pub struct WasiBusCall +{ + pub bid: WasiBusProcessId, + pub invocation: Box, +} + +/// Structure that holds the state of BUS calls to this process and from +/// this process. BUS calls are the equivalent of RPC's with support +/// for all the major serializers +#[derive(Debug)] +pub struct WasiBusState +{ + pub call_seed: u64, + pub called: HashMap>, + pub calls: HashMap, +} + +impl Default +for WasiBusState +{ + fn default() -> Self { + Self { + call_seed: 0, + called: Default::default(), + calls: Default::default(), + } + } } /// Top level data type containing all* the state with which WASI can @@ -1841,7 +1947,9 @@ pub(crate) struct WasiStateThreading { pub struct WasiState { pub fs: WasiFs, pub inodes: Arc>, - pub(crate) threading: Mutex, + pub(crate) threading: RwLock, + pub(crate) futexs: Mutex>, + pub(crate) bus: Mutex, pub args: Vec>, pub envs: Vec>, } @@ -1918,12 +2026,18 @@ impl WasiState { fd: __wasi_fd_t, ) -> Result>, FsError> { let ret = WasiStateFileGuard::new(self, fd)?.map(|a| { - let ret = Box::new(a); - let ret: Box = ret; - ret - }); + let ret = Box::new(a); + let ret: Box = ret; + ret + }); Ok(ret) } + + /// Grabs the next chained work (if there is one) + pub fn next_chained_worker(&self) -> Option u32 + Send + Sync>> { + let mut guard = self.threading.write().unwrap(); + guard.chained_worker.take() + } } pub fn virtual_file_type_to_wasi_file_type(file_type: wasmer_vfs::FileType) -> __wasi_filetype_t { diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 7842f68bc5d..31375da96bc 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -10,7 +10,7 @@ use std::{ sync::{Arc, Mutex}, time::Duration, }; -use wasmer_vbus::BusError; +use wasmer_vbus::VirtualBusError; #[cfg(feature = "host-fs")] pub use wasmer_vfs::host_fs::{Stderr, Stdin, Stdout}; @@ -102,8 +102,8 @@ pub fn net_error_into_wasi_err(net_error: NetworkError) -> __wasi_errno_t { } } -pub fn bus_error_into_wasi_err(bus_error: BusError) -> __bus_errno_t { - use BusError::*; +pub fn bus_error_into_wasi_err(bus_error: VirtualBusError) -> __bus_errno_t { + use VirtualBusError::*; match bus_error { Serialization => __BUS_ESER, Deserialization => __BUS_EDES, @@ -127,8 +127,8 @@ pub fn bus_error_into_wasi_err(bus_error: BusError) -> __bus_errno_t { } } -pub fn wasi_error_into_bus_err(bus_error: __bus_errno_t) -> BusError { - use BusError::*; +pub fn wasi_error_into_bus_err(bus_error: __bus_errno_t) -> VirtualBusError { + use VirtualBusError::*; match bus_error { __BUS_ESER => Serialization, __BUS_EDES => Deserialization, @@ -148,7 +148,7 @@ pub fn wasi_error_into_bus_err(bus_error: __bus_errno_t) -> BusError { __BUS_EINVOKE => InvokeFailed, __BUS_ECONSUMED => AlreadyConsumed, __BUS_EMEMVIOLATION => MemoryAccessViolation, - /*__BUS_EUNKNOWN |*/ _ => UnknownError, + __BUS_EUNKNOWN | _ => UnknownError, } } @@ -448,6 +448,20 @@ impl VirtualFile for Pipe { } } +pub(crate) fn bus_read_rights() -> __wasi_rights_t { + __WASI_RIGHT_FD_FDSTAT_SET_FLAGS + | __WASI_RIGHT_FD_FILESTAT_GET + | __WASI_RIGHT_FD_READ + | __WASI_RIGHT_POLL_FD_READWRITE +} + +pub(crate) fn bus_write_rights() -> __wasi_rights_t { + __WASI_RIGHT_FD_FDSTAT_SET_FLAGS + | __WASI_RIGHT_FD_FILESTAT_GET + | __WASI_RIGHT_FD_WRITE + | __WASI_RIGHT_POLL_FD_READWRITE +} + /* TODO: Think about using this trait WasiFdBacking: std::fmt::Debug { diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs index 33c2f1f6427..2ac35f7ffcd 100644 --- a/lib/wasi/src/syscalls/legacy/snapshot0.rs +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -1,6 +1,6 @@ use crate::syscalls; use crate::syscalls::types::{self, snapshot0}; -use crate::{mem_error_to_wasi, Memory32, MemorySize, WasiEnv, WasiError, WasiThread}; +use crate::{mem_error_to_wasi, Memory32, MemorySize, WasiEnv, WasiError}; use wasmer::{AsStoreMut, FunctionEnvMut, WasmPtr}; /// Wrapper around `syscalls::fd_filestat_get` with extra logic to handle the size @@ -27,7 +27,7 @@ pub fn fd_filestat_get( // Set up complete, make the call with the pointer that will write to the // struct and some unrelated memory after the struct. - let result = syscalls::fd_filestat_get::(ctx.as_mut(), fd, new_buf); + let result = syscalls::fd_filestat_get_internal::(&mut ctx, fd, new_buf); // reborrow memory let env = ctx.data(); @@ -130,40 +130,43 @@ pub fn poll_oneoff( // in this case the new type is smaller than the old type, so it all fits into memory, // we just need to readjust and copy it - // we start by adjusting `in_` into a format that the new code can understand - let env = ctx.data(); - let memory = env.memory(); let nsubscriptions_offset: u32 = nsubscriptions; - let in_origs = wasi_try_mem_ok!(in_.slice(&ctx, memory, nsubscriptions_offset)); - let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); - - // get a pointer to the smaller new type - let in_new_type_ptr: WasmPtr = in_.cast(); - - for (in_sub_new, orig) in - wasi_try_mem_ok!(in_new_type_ptr.slice(&ctx, memory, nsubscriptions_offset)) - .iter() - .zip(in_origs.iter()) - { - wasi_try_mem_ok!(in_sub_new.write(types::__wasi_subscription_t { - userdata: orig.userdata, - type_: orig.type_, - u: if orig.type_ == types::__WASI_EVENTTYPE_CLOCK { - types::__wasi_subscription_u { - clock: types::__wasi_subscription_clock_t { - clock_id: unsafe { orig.u.clock.clock_id }, - timeout: unsafe { orig.u.clock.timeout }, - precision: unsafe { orig.u.clock.precision }, - flags: unsafe { orig.u.clock.flags }, - }, - } - } else { - types::__wasi_subscription_u { - fd_readwrite: unsafe { orig.u.fd_readwrite }, - } - }, - })); - } + let in_new_type_ptr = { + // we start by adjusting `in_` into a format that the new code can understand + let env = ctx.data(); + let memory = env.memory(); + let in_origs = wasi_try_mem_ok!(in_.slice(&ctx, memory, nsubscriptions_offset)); + let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); + + // get a pointer to the smaller new type + let in_new_type_ptr: WasmPtr = in_.cast(); + + for (in_sub_new, orig) in + wasi_try_mem_ok!(in_new_type_ptr.slice(&ctx, memory, nsubscriptions_offset)) + .iter() + .zip(in_origs.iter()) + { + wasi_try_mem_ok!(in_sub_new.write(types::__wasi_subscription_t { + userdata: orig.userdata, + type_: orig.type_, + u: if orig.type_ == types::__WASI_EVENTTYPE_CLOCK { + types::__wasi_subscription_u { + clock: types::__wasi_subscription_clock_t { + clock_id: unsafe { orig.u.clock.clock_id }, + timeout: unsafe { orig.u.clock.timeout }, + precision: unsafe { orig.u.clock.precision }, + flags: unsafe { orig.u.clock.flags }, + }, + } + } else { + types::__wasi_subscription_u { + fd_readwrite: unsafe { orig.u.fd_readwrite }, + } + }, + })); + } + in_new_type_ptr + }; // make the call let result = syscalls::poll_oneoff::( @@ -172,11 +175,13 @@ pub fn poll_oneoff( out_, nsubscriptions, nevents, - ); + )?; // replace the old values of in, in case the calling code reuses the memory let env = ctx.data(); let memory = env.memory(); + let in_origs = wasi_try_mem_ok!(in_.slice(&ctx, memory, nsubscriptions_offset)); + let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); for (in_sub, orig) in wasi_try_mem_ok!(in_.slice(&ctx, memory, nsubscriptions_offset)) .iter() @@ -185,5 +190,5 @@ pub fn poll_oneoff( wasi_try_mem_ok!(in_sub.write(orig)); } - result + Ok(result) } diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 32e1a09492a..807723c9c3b 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -11,18 +11,15 @@ pub mod types { target_vendor = "apple" ))] pub mod unix; -#[cfg(any(target_arch = "wasm32"))] +#[cfg(any(target_family = "wasm"))] pub mod wasm32; #[cfg(any(target_os = "windows"))] pub mod windows; pub mod legacy; -//pub mod wasi; -pub mod wasix32; -pub mod wasix64; use self::types::*; -use crate::state::{bus_error_into_wasi_err, wasi_error_into_bus_err, InodeHttpSocketType}; +use crate::state::{bus_error_into_wasi_err, wasi_error_into_bus_err, InodeHttpSocketType, WasiFutex, bus_write_rights, bus_read_rights, WasiBusCall}; use crate::utils::map_io_err; use crate::WasiBusProcessId; use crate::{ @@ -32,25 +29,31 @@ use crate::{ virtual_file_type_to_wasi_file_type, Fd, Inode, InodeSocket, InodeSocketKind, InodeVal, Kind, PollEvent, PollEventBuilder, WasiPipe, WasiState, MAX_SYMLINKS, }, - WasiEnv, WasiError, WasiThread, WasiThreadId, + WasiEnv, WasiError, WasiThreadId, }; use bytes::Bytes; +use sha2::Sha256; use std::borrow::{Borrow, Cow}; +use std::collections::HashSet; +use std::collections::hash_map::Entry; use std::convert::{Infallible, TryInto}; use std::io::{self, Read, Seek, Write}; use std::mem::transmute; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::ops::{Deref, DerefMut}; -use std::sync::atomic::AtomicU64; +use std::pin::Pin; +use std::sync::atomic::{AtomicU64, AtomicU32}; use std::sync::{atomic::Ordering, Mutex}; -use std::sync::{mpsc, Arc}; +use std::sync::{mpsc, Arc, Condvar}; +use std::task::{Poll, Context}; +use std::thread::LocalKey; use std::time::Duration; use tracing::{debug, error, trace, warn}; use wasmer::{ AsStoreMut, FunctionEnvMut, Memory, Memory32, Memory64, MemorySize, RuntimeError, Value, - WasmPtr, WasmSlice, + WasmPtr, WasmSlice, FunctionEnv, }; -use wasmer_vbus::{FileDescriptor, StdioMode}; +use wasmer_vbus::{FileDescriptor, StdioMode, BusDataFormat, BusInvocationEvent}; use wasmer_vfs::{FsError, VirtualFile}; use wasmer_vnet::{SocketHttpRequest, StreamSecurity}; @@ -391,7 +394,7 @@ pub fn clock_time_get( precision: __wasi_timestamp_t, time: WasmPtr<__wasi_timestamp_t, M>, ) -> __wasi_errno_t { - debug!( + trace!( "wasi::clock_time_get clock_id: {}, precision: {}", clock_id, precision ); @@ -423,7 +426,7 @@ pub fn environ_get( environ: WasmPtr, M>, environ_buf: WasmPtr, ) -> __wasi_errno_t { - debug!( + trace!( "wasi::environ_get. Environ: {:?}, environ_buf: {:?}", environ, environ_buf ); @@ -686,7 +689,23 @@ pub fn fd_fdstat_set_rights( /// - `__wasi_filestat_t *buf` /// Where the metadata from `fd` will be written pub fn fd_filestat_get( - ctx: FunctionEnvMut<'_, WasiEnv>, + mut ctx: FunctionEnvMut<'_, WasiEnv>, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_filestat_t, M>, +) -> __wasi_errno_t { + fd_filestat_get_internal(&mut ctx, fd, buf) +} + +/// ### `fd_filestat_get()` +/// Get the metadata of an open file +/// Input: +/// - `__wasi_fd_t fd` +/// The open file descriptor whose metadata will be read +/// Output: +/// - `__wasi_filestat_t *buf` +/// Where the metadata from `fd` will be written +pub(crate) fn fd_filestat_get_internal( + ctx: &mut FunctionEnvMut<'_, WasiEnv>, fd: __wasi_fd_t, buf: WasmPtr<__wasi_filestat_t, M>, ) -> __wasi_errno_t { @@ -1461,7 +1480,7 @@ pub fn fd_event( inodes.deref_mut(), kind, false, - "event".to_string(), + "event".into(), ); let rights = __WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_POLL_FD_READWRITE; let fd = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode)); @@ -1796,13 +1815,13 @@ pub fn fd_pipe( inodes.deref_mut(), Kind::Pipe { pipe: pipe1 }, false, - "pipe".to_string(), + "pipe".into(), ); let inode2 = state.fs.create_inode_with_default_stat( inodes.deref_mut(), Kind::Pipe { pipe: pipe2 }, false, - "pipe".to_string(), + "pipe".into(), ); let rights = super::state::all_socket_rights(); @@ -2836,7 +2855,7 @@ pub fn path_symlink( inodes.deref_mut(), kind, false, - entry_name.clone(), + entry_name.clone().into(), ); { @@ -3448,9 +3467,7 @@ pub fn chdir( /// Returns the thread index of the newly created thread /// (indices always start from zero) pub fn thread_spawn( - ctx: FunctionEnvMut<'_, WasiEnv>, - method: WasmPtr, - method_len: M::Offset, + mut ctx: FunctionEnvMut<'_, WasiEnv>, user_data: u64, reactor: __wasi_bool_t, ret_tid: WasmPtr<__wasi_tid_t, M>, @@ -3458,76 +3475,235 @@ pub fn thread_spawn( debug!("wasi::thread_spawn"); let env = ctx.data(); let memory = env.memory(); - let method = unsafe { get_input_str!(&ctx, memory, method, method_len) }; // Load the callback function - if method.as_str() != "_thread_start" { - return __WASI_ENOTCAPABLE; - }; - /* - let funct = unsafe { - if env.thread_start_ref().is_none() { - return __WASI_EADDRNOTAVAIL; - } - env.thread_start_ref_unchecked() - }; - */ - let reactor = match reactor { __WASI_BOOL_FALSE => false, __WASI_BOOL_TRUE => true, _ => return __WASI_EINVAL, }; - // Create the sub-thread - let mut sub_env = env.clone(); - let mut sub_thread = env.new_thread(); - sub_env.id = sub_thread.id; - let child = { - let id = sub_thread.id; - wasi_try!(env - .runtime - .thread_spawn(Box::new(move || { - /* - if let Some(funct) = sub_env.thread_start_ref() { - if let Err(err) = funct.call(user_data) { - warn!("thread failed: {}", err); - std::mem::forget(sub_thread); - return; - } - } else { - warn!("failed to start thread: missing callback '__wasix_thread_start'"); - std::mem::forget(sub_thread); - return; - } - */ + let sub_handle = { + let mut guard = env.state.threading.write().unwrap(); + guard.new_thread() + }; - let thread = { - let mut guard = sub_env.state.threading.lock().unwrap(); - let thread = guard.threads.remove(&id); - drop(guard); - thread + // Find the function we are going to invoke + let test_func = match reactor { + true => env.inner().react.as_ref(), + false => env.inner().thread_spawn.as_ref() + }; + if test_func.is_none() + { + warn!("thread failed - the program does not export a __start_thread function"); + return __WASI_ENOTCAPABLE; + }; + + // Clone the environment and drop the reference to it + let post_runtime = env.runtime.clone(); + let post_state = env.state.clone(); + let sub_env = env.clone(); + drop(env); + + // Clone the store (after freezing it which will trigger a shallow copy) + let mut sub_store = ctx.clone_store(); + + // Create the worker thread + let child = sub_handle.id(); + let worker = move || + { + // Create a new context on the store we cloned + let mut ctx = FunctionEnv::new(&mut sub_store, sub_env) + .into_mut(&mut sub_store); + + // Set the current thread ID + crate::THREAD_ID.with(|f| { + let mut thread_id = f.borrow_mut(); + *thread_id = child.raw(); + }); + + // Enter a loop (this is only actually needed for reactors + // however duplicate code sucks) - normal threads will exit + // the loop after executing the callback once. + loop + { + // Next we get the function that it wants to invoke + let start = match reactor { + true => ctx.data().inner().react.as_ref().unwrap().clone(), + false => ctx.data().inner().thread_spawn.as_ref().unwrap().clone() }; - if let Some(thread) = thread { - let mut thread_guard = thread.exit.lock().unwrap(); - thread_guard.take(); + let mut store = ctx.as_store_mut(); + if let Err(err) = start.call(&mut store, user_data) { + debug!("thread failed: {}", err); + return __WASI_ENOEXEC as u32; + } + + // If we are a reactor we wait for something to wake us up + // otherwise if we are normal thread then we are already done + // and should not invoke the thread function again (memory that + // holds the callback already freed in RUST standard library!) + if reactor { + while ctx.data().inner().reactors.wait(Duration::from_millis(50)) == false { + if let Err(err) = ctx.data().yield_now() { + debug!("thread exited - {}", err); + return match err { + WasiError::Exit(err) => err, + _ => __WASI_ENOEXEC as u32 + }; + } + } + } else { + break; } - drop(sub_thread); - })) - .map_err(|err| { - let err: __wasi_errno_t = err.into(); - err - })); - id + } + + // Clean up the thread resources and notify joins that the thread is done + // (this forces sub_handle to be captured in the delegate so it follows the + // scope of the thread) + drop(sub_handle); + + // Success + __WASI_ESUCCESS as u32 + }; + + // When running in web assembly we are not quite ready for full multi-thread + // instead we will chain the single thread. TODO: Fix this and make JS multithreaded + if cfg!(target_family = "wasm") + { + // Defer it until the main function exits (but only for runtimes that + // support this) + let mut guard = post_state.threading.write().unwrap(); + guard.chained_worker.replace(Box::new(worker)); + } + else + { + // Now spawn a thread + wasi_try!(post_runtime + .thread_spawn(Box::new(move || { + worker(); + })) + .map_err(|err| { + let err: __wasi_errno_t = err.into(); + err + })); + } + child }; let child: __wasi_tid_t = child.into(); + let env = ctx.data(); + let memory = env.memory(); wasi_try_mem!(ret_tid.write(&ctx, memory, child)); __WASI_ESUCCESS } +/// ### `thread_local_create()` +/// Create a thread local variable +/// If The web assembly process exports function named '_thread_local_destroy' +/// then it will be invoked when the thread goes out of scope and dies. +/// +/// ## Parameters +/// +/// * `user_data` - User data that will be passed to the destructor +/// when the thread variable goes out of scope +pub fn thread_local_create( + ctx: FunctionEnvMut<'_, WasiEnv>, + user_data: u64, + ret_key: WasmPtr<__wasi_tl_key_t, M>, +) -> __wasi_errno_t { + trace!("wasi::thread_local_create (user_data={})", user_data); + let env = ctx.data(); + + let key = { + let mut guard = env.state.threading.write().unwrap(); + guard.thread_local_seed += 1; + let key = guard.thread_local_seed; + guard.thread_local_user_data.insert(key, user_data); + key + }; + + let memory = env.memory(); + wasi_try_mem!(ret_key.write(&ctx, memory, key)); + __WASI_ESUCCESS +} + +/// ### `thread_local_destroy()` +/// Destroys a thread local variable +/// +/// ## Parameters +/// +/// * `user_data` - User data that will be passed to the destructor +/// when the thread variable goes out of scope +/// * `key` - Thread key that was previously created +pub fn thread_local_destroy( + mut ctx: FunctionEnvMut<'_, WasiEnv>, + key: __wasi_tl_key_t +) -> __wasi_errno_t { + trace!("wasi::thread_local_destroy (key={})", key); + let state = ctx.data().state.clone(); + let mut guard = state.threading.write().unwrap(); + if let Some(user_data) = guard.thread_local_user_data.remove(&key) { + if let Some(thread_local_destroy) = ctx.data().inner().thread_local_destroy.as_ref().map(|a| a.clone()) { + guard.thread_local + .iter() + .filter(|((_, k), _)| *k == key) + .for_each(|((_, _), val)| { + let _ = thread_local_destroy.call(&mut ctx, user_data, *val); + }); + } + } + guard.thread_local.retain(|(_, k), _| *k != key); + __WASI_ESUCCESS +} + +/// ### `thread_local_set()` +/// Sets the value of a thread local variable +/// +/// ## Parameters +/// +/// * `key` - Thread key that this local variable will be associated with +/// * `val` - Value to be set for the thread local variable +pub fn thread_local_set( + ctx: FunctionEnvMut<'_, WasiEnv>, + key: __wasi_tl_key_t, + val: __wasi_tl_val_t +) -> __wasi_errno_t { + trace!("wasi::thread_local_set (key={}, val={})", key, val); + let env = ctx.data(); + + let current_thread = env.current_thread_id(); + let mut guard = env.state.threading.write().unwrap(); + guard.thread_local.insert((current_thread, key), val); + __WASI_ESUCCESS +} + +/// ### `thread_local_get()` +/// Gets the value of a thread local variable +/// +/// ## Parameters +/// +/// * `key` - Thread key that this local variable that was previous set +pub fn thread_local_get( + ctx: FunctionEnvMut<'_, WasiEnv>, + key: __wasi_tl_key_t, + ret_val: WasmPtr<__wasi_tl_val_t, M>, +) -> __wasi_errno_t { + trace!("wasi::thread_local_get (key={})", key); + let env = ctx.data(); + + let val = { + let current_thread = env.current_thread_id(); + let guard = env.state.threading.read().unwrap(); + guard.thread_local.get(&(current_thread, key)).map(|a| a.clone()) + }; + let val = val.unwrap_or_default(); + let memory = env.memory(); + wasi_try_mem!(ret_val.write(&ctx, memory, val)); + __WASI_ESUCCESS +} + /// ### `thread_sleep()` /// Sends the current thread to sleep for a period of time /// @@ -3577,8 +3753,8 @@ pub fn thread_join( let env = ctx.data(); let tid: WasiThreadId = tid.into(); let other_thread = { - let guard = env.state.threading.lock().unwrap(); - guard.threads.get(&tid).cloned() + let guard = env.state.threading.read().unwrap(); + guard.get(&tid) }; if let Some(other_thread) = other_thread { loop { @@ -3612,6 +3788,135 @@ pub fn thread_parallelism( __WASI_ESUCCESS } +/// Wait for a futex_wake operation to wake us. +/// Returns with EINVAL if the futex doesn't hold the expected value. +/// Returns false on timeout, and true in all other cases. +/// +/// ## Parameters +/// +/// * `futex` - Memory location that holds the value that will be checked +/// * `expected` - Expected value that should be currently held at the memory location +/// * `timeout` - Timeout should the futex not be triggered in the allocated time +pub fn futex_wait( + ctx: FunctionEnvMut<'_, WasiEnv>, + futex: WasmPtr, + expected: u32, + timeout: WasmPtr<__wasi_option_timestamp_t, M>, + ret_woken: WasmPtr<__wasi_bool_t, M>, +) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::futex_wait(offset={})", futex.offset()); + let env = ctx.data(); + let state = env.state.deref(); + + let pointer: u64 = wasi_try_ok!(futex.offset().try_into().map_err(|_| __WASI_EOVERFLOW)); + + let futex = { + use std::collections::hash_map::Entry; + let mut guard = state.futexs.lock().unwrap(); + match guard.entry(pointer) { + Entry::Occupied(entry) => { + entry.get().clone() + }, + Entry::Vacant(entry) => { + let futex = WasiFutex { + refcnt: Arc::new(AtomicU32::new(1)), + inner: Arc::new((Mutex::new(()), Condvar::new())) + }; + entry.insert(futex.clone()); + futex + } + } + }; + + loop { + let futex_lock = futex.inner.0.lock().unwrap(); + let result = futex.inner.1.wait_timeout(futex_lock, Duration::from_millis(50)).unwrap(); + if result.1.timed_out() { + env.yield_now()?; + } else { + break; + } + } + + let mut guard = state.futexs.lock().unwrap(); + if guard.get(&pointer) + .map(|futex| futex.refcnt.fetch_sub(1, Ordering::AcqRel) == 1) + .unwrap_or(false) + { + guard.remove(&pointer); + } + + Ok(__WASI_ESUCCESS) +} + +/// Wake up one thread that's blocked on futex_wait on this futex. +/// Returns true if this actually woke up such a thread, +/// or false if no thread was waiting on this futex. +/// +/// ## Parameters +/// +/// * `futex` - Memory location that holds a futex that others may be waiting on +pub fn futex_wake( + ctx: FunctionEnvMut<'_, WasiEnv>, + futex: WasmPtr, + ret_woken: WasmPtr<__wasi_bool_t, M>, +) -> __wasi_errno_t { + trace!("wasi::futex_wake(offset={})", futex.offset()); + let env = ctx.data(); + let memory = env.memory(); + let state = env.state.deref(); + + let pointer: u64 = wasi_try!(futex.offset().try_into().map_err(|_| __WASI_EOVERFLOW)); + let mut woken = false; + + let mut guard = state.futexs.lock().unwrap(); + if let Some(futex) = guard.get(&pointer) { + futex.inner.1.notify_one(); + woken = true; + } + + let woken = match woken { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE, + }; + wasi_try_mem!(ret_woken.write(&ctx, memory, woken)); + + __WASI_ESUCCESS +} + +/// Wake up all threads that are waiting on futex_wait on this futex. +/// +/// ## Parameters +/// +/// * `futex` - Memory location that holds a futex that others may be waiting on +pub fn futex_wake_all( + ctx: FunctionEnvMut<'_, WasiEnv>, + futex: WasmPtr, + ret_woken: WasmPtr<__wasi_bool_t, M>, +) -> __wasi_errno_t { + trace!("wasi::futex_wake_all(offset={})", futex.offset()); + let env = ctx.data(); + let memory = env.memory(); + let state = env.state.deref(); + + let pointer: u64 = wasi_try!(futex.offset().try_into().map_err(|_| __WASI_EOVERFLOW)); + let mut woken = false; + + let mut guard = state.futexs.lock().unwrap(); + if let Some(futex) = guard.get(&pointer) { + futex.inner.1.notify_all(); + woken = true; + } + + let woken = match woken { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE, + }; + wasi_try_mem!(ret_woken.write(&ctx, memory, woken)); + + __WASI_ESUCCESS +} + /// ### `getpid()` /// Returns the handle of the current process pub fn getpid( @@ -3703,10 +4008,10 @@ pub fn process_spawn( __WASI_STDIO_MODE_PIPED => StdioMode::Piped, __WASI_STDIO_MODE_INHERIT => StdioMode::Inherit, __WASI_STDIO_MODE_LOG => StdioMode::Log, - /*__WASI_STDIO_MODE_NULL |*/ _ => StdioMode::Null, + __WASI_STDIO_MODE_NULL | _ => StdioMode::Null, }; - let process = wasi_try_bus!(bus + let mut process = wasi_try_bus!(bus .new_spawn() .chroot(chroot) .args(args) @@ -3718,7 +4023,54 @@ pub fn process_spawn( .spawn(name.as_str()) .map_err(bus_error_into_wasi_err)); - let conv_stdio_fd = |a: Option| match a { + // Create the file descriptors used to access this process + let (fd_stdin, fd_stdout, fd_stderr) = { + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); + + // Register the inodes for the stdio for this sub process + let fd_stdin = match process.stdin.take() { + Some(handle) => Some( + wasi_try_bus!(state.fs.create_fd(bus_write_rights(), bus_write_rights(), 0, 0, + state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::File { handle: Some(handle), path: "/dev/stdin".into(), fd: None }, + false, + "stdin".into(), + ) + ).map_err(|_| __BUS_EINTERNAL)) + ), + None => None, + }; + let fd_stdout = match process.stdout.take() { + Some(handle) => Some( + wasi_try_bus!(state.fs.create_fd(bus_read_rights(), bus_read_rights(), 0, 0, + state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::File { handle: Some(handle), path: "/dev/stdout".into(), fd: None }, + false, + "stdout".into(), + ) + ).map_err(|_| __BUS_EINTERNAL)) + ), + None => None + }; + let fd_stderr = match process.stderr.take() { + Some(handle) => Some( + wasi_try_bus!(state.fs.create_fd(bus_read_rights(), bus_read_rights(), 0, 0, + state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::File { handle: Some(handle), path: "/dev/stderr".into(), fd: None }, + false, + "stderr".into(), + ) + ).map_err(|_| __BUS_EINTERNAL)) + ), + None => None + }; + (fd_stdin, fd_stdout, fd_stderr) + }; + + let conv_stdio_fd = |a: Option<__wasi_fd_t>| match a { Some(fd) => __wasi_option_fd_t { tag: __WASI_OPTION_SOME, fd: fd.into(), @@ -3728,18 +4080,18 @@ pub fn process_spawn( fd: 0, }, }; - + // Convert the stdio - let stdin = conv_stdio_fd(process.inst.stdin_fd()); - let stdout = conv_stdio_fd(process.inst.stdout_fd()); - let stderr = conv_stdio_fd(process.inst.stderr_fd()); + let stdin = conv_stdio_fd(fd_stdin); + let stdout = conv_stdio_fd(fd_stdout); + let stderr = conv_stdio_fd(fd_stderr); // Add the process to the environment state let bid = { - let mut guard = env.state.threading.lock().unwrap(); + let mut guard = env.state.threading.write().unwrap(); guard.process_seed += 1; let bid = guard.process_seed; - guard.processes.insert(bid.into(), process); + guard.processes.insert(bid.into(), Box::new(process)); bid }; @@ -3773,15 +4125,15 @@ pub fn bus_open_local( name_len: M::Offset, reuse: __wasi_bool_t, ret_bid: WasmPtr<__wasi_bid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory(); - let name = unsafe { get_input_str_bus!(&ctx, memory, name, name_len) }; + let name = unsafe { get_input_str_bus_ok!(&ctx, memory, name, name_len) }; let reuse = reuse == __WASI_BOOL_TRUE; debug!("wasi::bus_open_local (name={}, reuse={})", name, reuse); - bus_open_local_internal(ctx, name, reuse, None, None, ret_bid) + bus_open_internal(ctx, name, reuse, None, None, ret_bid) } /// Spawns a new bus process for a particular web WebAssembly @@ -3808,30 +4160,30 @@ pub fn bus_open_remote( token: WasmPtr, token_len: M::Offset, ret_bid: WasmPtr<__wasi_bid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory(); - let name = unsafe { get_input_str_bus!(&ctx, memory, name, name_len) }; - let instance = unsafe { get_input_str_bus!(&ctx, memory, instance, instance_len) }; - let token = unsafe { get_input_str_bus!(&ctx, memory, token, token_len) }; + let name = unsafe { get_input_str_bus_ok!(&ctx, memory, name, name_len) }; + let instance = unsafe { get_input_str_bus_ok!(&ctx, memory, instance, instance_len) }; + let token = unsafe { get_input_str_bus_ok!(&ctx, memory, token, token_len) }; let reuse = reuse == __WASI_BOOL_TRUE; debug!( "wasi::bus_open_remote (name={}, reuse={}, instance={})", name, reuse, instance ); - bus_open_local_internal(ctx, name, reuse, Some(instance), Some(token), ret_bid) + bus_open_internal(ctx, name, reuse, Some(instance), Some(token), ret_bid) } -fn bus_open_local_internal( +fn bus_open_internal( ctx: FunctionEnvMut<'_, WasiEnv>, name: String, reuse: bool, instance: Option, token: Option, ret_bid: WasmPtr<__wasi_bid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory(); @@ -3839,11 +4191,11 @@ fn bus_open_local_internal( // Check if it already exists if reuse { - let guard = env.state.threading.lock().unwrap(); + let guard = env.state.threading.read().unwrap(); if let Some(bid) = guard.process_reuse.get(&name) { if guard.processes.contains_key(bid) { - wasi_try_mem_bus!(ret_bid.write(&ctx, memory, (*bid).into())); - return __BUS_ESUCCESS; + wasi_try_mem_bus_ok!(ret_bid.write(&ctx, memory, bid.clone().into())); + return Ok(__BUS_ESUCCESS); } } } @@ -3863,23 +4215,54 @@ fn bus_open_local_internal( process.access_token(token); } - let process = wasi_try_bus!(process + // Spawn the process + let mut process = wasi_try_bus_ok!(process .spawn(name.as_ref()) .map_err(bus_error_into_wasi_err)); + // Wait for the process to be ready to receive commands + let reactors = &env.inner().reactors; + let waker = reactors.get_waker(); + let mut cx = Context::from_waker(&waker); + loop { + { + let inst = Pin::new(process.inst.as_mut()); + if inst.poll_ready(&mut cx) == Poll::Ready(()) { + break; + } + } + + // If its exited then abort + if let Some(code) = process.inst.exit_code() { + return Ok(__BUS_EABORTED); + } + + // Now we need to sleep for a limited amount of time + #[cfg(not(target_family = "wasm"))] + reactors.wait(Duration::from_millis(1000)); + #[cfg(not(target_family = "wasm"))] + env.yield_now()?; + #[cfg(target_family = "wasm")] + if reactors.wait(Duration::ZERO) == false { + break; + } + #[cfg(target_family = "wasm")] + env.sleep(Duration::from_millis(5))?; + } + // Add the process to the environment state let bid = { - let mut guard = env.state.threading.lock().unwrap(); + let mut guard = env.state.threading.write().unwrap(); guard.process_seed += 1; let bid: WasiBusProcessId = guard.process_seed.into(); - guard.processes.insert(bid, process); + guard.processes.insert(bid, Box::new(process)); guard.process_reuse.insert(name, bid); bid }; - wasi_try_mem_bus!(ret_bid.write(&ctx, memory, bid.into())); + wasi_try_mem_bus_ok!(ret_bid.write(&ctx, memory, bid.into())); - __BUS_ESUCCESS + Ok(__BUS_ESUCCESS) } /// Closes a bus process and releases all associated resources @@ -3892,10 +4275,13 @@ pub fn bus_close(ctx: FunctionEnvMut<'_, WasiEnv>, bid: __wasi_bid_t) -> __bus_e let bid: WasiBusProcessId = bid.into(); let env = ctx.data(); - let mut guard = env.state.threading.lock().unwrap(); - guard.processes.remove(&bid); + let mut guard = env.state.threading.write().unwrap(); + if let Some(process) = guard.processes.remove(&bid) { + let name: Cow<'static, str> = process.name.clone().into(); + guard.process_reuse.remove(&name); + } - __BUS_EUNSUPPORTED + __BUS_ESUCCESS } /// Invokes a call within a running bus process. @@ -3912,27 +4298,78 @@ pub fn bus_close(ctx: FunctionEnvMut<'_, WasiEnv>, bid: __wasi_bid_t) -> __bus_e pub fn bus_call( ctx: FunctionEnvMut<'_, WasiEnv>, bid: __wasi_bid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: M::Offset, + topic_hash: WasmPtr<__wasi_hash_t>, format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: M::Offset, ret_cid: WasmPtr<__wasi_cid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory(); - let topic = unsafe { get_input_str_bus!(&ctx, memory, topic, topic_len) }; - let keep_alive = keep_alive == __WASI_BOOL_TRUE; + let topic_hash = wasi_try_mem_bus_ok!(topic_hash.read(&ctx, memory)); + let buf_slice = wasi_try_mem_bus_ok!(buf.slice(&ctx, memory, buf_len)); trace!( - "wasi::bus_call (bid={}, topic={}, buf_len={})", + "wasi::bus_call (bid={}, buf_len={})", bid, - topic, buf_len ); - __BUS_EUNSUPPORTED + // Get the process that we'll invoke this call for + let mut guard = env.state.threading.read().unwrap(); + let bid: WasiBusProcessId = bid.into(); + let process = if let Some(process) = { + guard.processes.get(&bid).map(|p| p.clone()) + } { process } else { + return Ok(__BUS_EBADHANDLE); + }; + + // Invoke the bus process + let format = wasi_try_bus_ok!(conv_bus_format_from(format)); + + // Get the reactors object + let reactors = &env.inner().reactors; + let waker = reactors.get_waker(); + let mut cx = Context::from_waker(&waker); + + // Check if the process has finished + if let Some(code) = process.inst.exit_code() { + debug!("process has already exited (code = {})", code); + return Ok(__BUS_EABORTED); + } + + // Invoke the call + let buf = wasi_try_mem_bus_ok!(buf_slice.read_to_vec()); + let mut invoked = process.inst.invoke(topic_hash, format, buf); + + // Poll the invocation until it does its thing + let invocation; + loop { + let invoked = Pin::new(invoked.deref_mut()); + match invoked.poll_invoked(&mut cx) { + Poll::Ready(i) => { + invocation = wasi_try_bus_ok!(i + .map_err(bus_error_into_wasi_err)); + break; + }, + Poll::Pending => { + env.sleep(Duration::from_millis(5))?; + } + } + } + + // Record the invocation + let mut guard = env.state.bus.lock().unwrap(); + guard.call_seed += 1; + let cid = guard.call_seed; + guard.calls.insert(cid, WasiBusCall { + bid, + invocation + }); + + // Return the CID and success to the caller + wasi_try_mem_bus_ok!(ret_cid.write(&ctx, memory, cid)); + Ok(__BUS_ESUCCESS) } /// Invokes a call within the context of another call @@ -3949,27 +4386,96 @@ pub fn bus_call( pub fn bus_subcall( ctx: FunctionEnvMut<'_, WasiEnv>, parent: __wasi_cid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: M::Offset, + topic_hash: WasmPtr<__wasi_hash_t>, format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: M::Offset, ret_cid: WasmPtr<__wasi_cid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory(); - let topic = unsafe { get_input_str_bus!(&ctx, memory, topic, topic_len) }; - let keep_alive = keep_alive == __WASI_BOOL_TRUE; + let topic_hash = wasi_try_mem_bus_ok!(topic_hash.read(&ctx, memory)); + let buf_slice = wasi_try_mem_bus_ok!(buf.slice(&ctx, memory, buf_len)); trace!( - "wasi::bus_subcall (parent={}, topic={}, buf_len={})", + "wasi::bus_subcall (parent={}, buf_len={})", parent, - topic, buf_len ); - __BUS_EUNSUPPORTED + let format = wasi_try_bus_ok!(conv_bus_format_from(format)); + let buf = wasi_try_mem_bus_ok!(buf_slice.read_to_vec()); + + // Get the parent call that we'll invoke this call for + let mut guard = env.state.bus.lock().unwrap(); + if let Some(parent) = guard.calls.get(&parent) + { + let bid = parent.bid.clone(); + + // Get the reactors object + let reactors = &env.inner().reactors; + let waker = reactors.get_waker(); + let mut cx = Context::from_waker(&waker); + + // Invoke the sub-call in the existing parent call + let mut invoked = parent.invocation.invoke(topic_hash, format, buf); + + // Poll the invocation until it does its thing + let invocation; + loop { + let invoked = Pin::new(invoked.deref_mut()); + match invoked.poll_invoked(&mut cx) { + Poll::Ready(i) => { + invocation = wasi_try_bus_ok!(i + .map_err(bus_error_into_wasi_err)); + break; + }, + Poll::Pending => { + env.sleep(Duration::from_millis(5))?; + } + } + } + + // Add the call and return the ID + guard.call_seed += 1; + let cid = guard.call_seed; + guard.calls.insert(cid, WasiBusCall { + bid, + invocation + }); + + // Return the CID and success to the caller + wasi_try_mem_bus_ok!(ret_cid.write(&ctx, memory, cid)); + Ok(__BUS_ESUCCESS) + } else { + Ok(__BUS_EBADHANDLE) + } +} + +// Function for converting the format +fn conv_bus_format(format: BusDataFormat) -> __wasi_busdataformat_t { + match format { + BusDataFormat::Raw => __WASI_BUS_DATA_FORMAT_RAW, + BusDataFormat::Bincode => __WASI_BUS_DATA_FORMAT_BINCODE, + BusDataFormat::MessagePack => __WASI_BUS_DATA_FORMAT_MESSAGE_PACK, + BusDataFormat::Json => __WASI_BUS_DATA_FORMAT_JSON, + BusDataFormat::Yaml => __WASI_BUS_DATA_FORMAT_YAML, + BusDataFormat::Xml => __WASI_BUS_DATA_FORMAT_XML, + } +} + +fn conv_bus_format_from(format: __wasi_busdataformat_t) -> Result { + Ok( + match format { + __WASI_BUS_DATA_FORMAT_RAW => BusDataFormat::Raw, + __WASI_BUS_DATA_FORMAT_BINCODE => BusDataFormat::Bincode, + __WASI_BUS_DATA_FORMAT_MESSAGE_PACK => BusDataFormat::MessagePack, + __WASI_BUS_DATA_FORMAT_JSON => BusDataFormat::Json, + __WASI_BUS_DATA_FORMAT_YAML => BusDataFormat::Yaml, + __WASI_BUS_DATA_FORMAT_XML => BusDataFormat::Xml, + _ => { return Err(__BUS_EDES); } + } + ) } /// Polls for any outstanding events from a particular @@ -3989,19 +4495,336 @@ pub fn bus_subcall( pub fn bus_poll( ctx: FunctionEnvMut<'_, WasiEnv>, timeout: __wasi_timestamp_t, - events: WasmPtr, - nevents: M::Offset, - malloc: WasmPtr, - malloc_len: M::Offset, + events: WasmPtr<__wasi_busevent_t, M>, + maxevents: M::Offset, ret_nevents: WasmPtr, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory(); - let malloc = unsafe { get_input_str_bus!(&ctx, memory, malloc, malloc_len) }; - trace!("wasi::bus_poll (timeout={}, malloc={})", timeout, malloc); + trace!("wasi::bus_poll (timeout={})", timeout); + + // Get the reactors object + let reactors = &env.inner().reactors; + let waker = reactors.get_waker(); + let mut cx = Context::from_waker(&waker); + + // Lets start by processing events for calls that are already running + let mut nevents = M::ZERO; + let events = wasi_try_mem_bus_ok!(events.slice(&ctx, memory, maxevents)); + + let start = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as __wasi_timestamp_t; + loop + { + // Check if any of the processes have closed + let mut exited_bids = HashSet::new(); + { + let mut guard = env.state.threading.write().unwrap(); + for (pid, process) in guard.processes.iter_mut() { + let pinned_process = Pin::new(process.inst.as_mut()); + if pinned_process.poll_finished(&mut cx) == Poll::Ready(()) { + exited_bids.insert(*pid); + } + } + for pid in exited_bids.iter() { + guard.processes.remove(pid); + } + } + + { + // The waker will trigger the reactors when work arrives from the BUS + let mut guard = env.state.bus.lock().unwrap(); + + // Function that hashes the topic using SHA256 + let hash_topic = |topic: Cow<'static, str>| -> __wasi_hash_t { + use sha2::{Sha256, Digest}; + let mut hasher = Sha256::new(); + hasher.update(&topic.bytes().collect::>()); + let hash: [u8; 16] = hasher.finalize()[..16].try_into().unwrap(); + u128::from_le_bytes(hash) + }; + + // Function that turns a buffer into a readable file handle + let buf_to_fd = { + let state = env.state.clone(); + let inodes = state.inodes.clone(); + move |data: Vec| -> __wasi_fd_t { + let mut inodes = inodes.write().unwrap(); + let inode = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::Buffer { buffer: data }, + false, + "bus".into(), + ); + let rights = super::state::bus_read_rights(); + wasi_try_bus!(state.fs.create_fd(rights, rights, 0, 0, inode) + .map_err(|err| { + debug!("failed to create file descriptor for BUS event buffer - {}", err); + __BUS_EALLOC + })) + } + }; + + // Grab all the events we can from all the existing calls up to the limit of + // maximum events that the user requested + if nevents < maxevents { + let mut drop_calls = Vec::new(); + let mut call_seed = guard.call_seed; + for (key, call) in guard.calls.iter_mut() { + let cid: __wasi_cid_t = (*key).into(); + + if nevents >= maxevents { + break; + } + + // If the process that is hosting the call is finished then so is the call + if exited_bids.contains(&call.bid) { + drop_calls.push(*key); + trace!("wasi::bus_poll (aborted, cid={})", cid); + let evt = unsafe { + std::mem::transmute(__wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_FAULT, + u: __wasi_busevent_u { + fault: __wasi_busevent_fault_t { + cid, + err: __BUS_EABORTED + } + } + }) + }; + + let nevents64: u64 = wasi_try_bus_ok!(nevents.try_into().map_err(|_| __BUS_EINTERNAL)); + wasi_try_mem_bus_ok!(events.write(nevents64, evt)); + + nevents += M::ONE; + continue; + } + + // Otherwise lets poll for events + while nevents < maxevents { + let mut finished = false; + let call = Pin::new(call.invocation.as_mut()); + match call.poll_event(&mut cx) { + Poll::Ready(evt) => + { + let evt = match evt { + BusInvocationEvent::Callback { topic_hash, format, data } => { + let sub_cid = { + call_seed += 1; + call_seed + }; + + trace!("wasi::bus_poll (callback, parent={}, cid={}, topic={})", cid, sub_cid, topic_hash); + __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_CALL, + u: __wasi_busevent_u { + call: __wasi_busevent_call_t { + parent: __wasi_option_cid_t { + tag: __WASI_OPTION_SOME, + cid, + }, + cid: sub_cid, + format: conv_bus_format(format), + topic_hash, + fd: buf_to_fd(data), + } + } + } + }, + BusInvocationEvent::Response { format, data } => { + drop_calls.push(*key); + finished = true; + + trace!("wasi::bus_poll (response, cid={}, len={})", cid, data.len()); + __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_RESULT, + u: __wasi_busevent_u { + result: __wasi_busevent_result_t { + format: conv_bus_format(format), + cid, + fd: buf_to_fd(data), + } + } + } + }, + BusInvocationEvent::Fault { fault } => { + drop_calls.push(*key); + finished = true; + + trace!("wasi::bus_poll (fault, cid={}, err={})", cid, fault); + __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_FAULT, + u: __wasi_busevent_u { + fault: __wasi_busevent_fault_t { + cid, + err: bus_error_into_wasi_err(fault) + } + } + } + } + }; + let evt = unsafe { + std::mem::transmute(evt) + }; + + let nevents64: u64 = wasi_try_bus_ok!(nevents.try_into().map_err(|_| __BUS_EINTERNAL)); + wasi_try_mem_bus_ok!(events.write(nevents64, evt)); + + nevents += M::ONE; + + if finished { + break; + } + }, + Poll::Pending => { break; } + } + } + } + guard.call_seed = call_seed; + + // Drop any calls that are no longer in scope + if drop_calls.is_empty() == false { + for key in drop_calls { + guard.calls.remove(&key); + } + } + } + + if nevents < maxevents { + let mut call_seed = guard.call_seed; + let mut to_add = Vec::new(); + for (key, call) in guard.called.iter_mut() { + let cid: __wasi_cid_t = (*key).into(); + while nevents < maxevents { + let call = Pin::new(call.deref_mut()); + match call.poll(&mut cx) { + Poll::Ready(event) => { + // Register the call + let sub_cid = { + call_seed += 1; + to_add.push((call_seed, event.called)); + call_seed + }; + + let event = __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_CALL, + u: __wasi_busevent_u { + call: __wasi_busevent_call_t { + parent: __wasi_option_cid_t { + tag: __WASI_OPTION_SOME, + cid, + }, + cid: sub_cid, + format: conv_bus_format(event.format), + topic_hash: event.topic_hash, + fd: buf_to_fd(event.data), + } + } + }; + let event = unsafe { + std::mem::transmute(event) + }; + + let nevents64: u64 = wasi_try_bus_ok!(nevents.try_into().map_err(|_| __BUS_EINTERNAL)); + wasi_try_mem_bus_ok!(events.write(nevents64, event)); + nevents += M::ONE; + }, + Poll::Pending => { break; } + }; + } + if nevents >= maxevents { + break; + } + } + + guard.call_seed = call_seed; + for (cid, called) in to_add { + guard.called.insert(cid, called); + } + } + + while nevents < maxevents + { + // Check the listener (if none exists then one is created) + let event = { + let listener = wasi_try_bus_ok!(env.runtime + .bus() + .listen() + .map_err(bus_error_into_wasi_err)); + let listener = Pin::new(listener.deref()); + listener.poll(&mut cx) + }; + + // Process the event returned by the listener or exit the poll loop + let event = match event { + Poll::Ready(event) => { + + // Register the call + let sub_cid = { + guard.call_seed += 1; + let cid = guard.call_seed; + guard.called.insert(cid, event.called); + cid + }; + + __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_CALL, + u: __wasi_busevent_u { + call: __wasi_busevent_call_t { + parent: __wasi_option_cid_t { + tag: __WASI_OPTION_NONE, + cid: 0, + }, + cid: sub_cid, + format: conv_bus_format(event.format), + topic_hash: event.topic_hash, + fd: buf_to_fd(event.data), + } + } + } + }, + Poll::Pending => { break; } + }; + let event = unsafe { + std::mem::transmute(event) + }; + + let nevents64: u64 = wasi_try_bus_ok!(nevents.try_into().map_err(|_| __BUS_EINTERNAL)); + wasi_try_mem_bus_ok!(events.write(nevents64, event)); + nevents += M::ONE; + } + } + + // If we still have no events + if nevents >= M::ONE { + break; + } + + // Check for timeout (zero will mean the loop will not wait) + let now = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as __wasi_timestamp_t; + let delta = now - start; + if delta >= timeout { + break; + } + + // Now we need to sleep for a limited amount of time + #[cfg(not(target_family = "wasm"))] + if reactors.wait(Duration::from_millis(1000)) == false { + break; + } + #[cfg(not(target_family = "wasm"))] + env.yield_now()?; + #[cfg(target_family = "wasm")] + if reactors.wait(Duration::ZERO) == false { + break; + } + #[cfg(target_family = "wasm")] + env.sleep(Duration::from_millis(5))?; + } + trace!("wasi::bus_poll (return nevents={})", nevents); - __BUS_EUNSUPPORTED + wasi_try_mem_bus_ok!(ret_nevents.write(&ctx, memory, nevents)); + Ok(__BUS_ESUCCESS) } /// Replies to a call that was made to this process @@ -4022,6 +4845,7 @@ pub fn call_reply( buf_len: M::Offset, ) -> __bus_errno_t { let env = ctx.data(); + let memory = env.memory(); let bus = env.runtime.bus(); trace!( "wasi::call_reply (cid={}, format={}, data_len={})", @@ -4029,8 +4853,21 @@ pub fn call_reply( format, buf_len ); + let buf_slice = wasi_try_mem_bus!(buf.slice(&ctx, memory, buf_len)); + let buf = wasi_try_mem_bus!(buf_slice.read_to_vec()); + + let mut guard = env.state.bus.lock().unwrap(); + if let Some(call) = guard.called.get(&cid) { + + let format = wasi_try_bus!(conv_bus_format_from(format)); + call.reply(format, buf); + drop(call); - __BUS_EUNSUPPORTED + guard.called.remove(&cid); + __BUS_ESUCCESS + } else { + __BUS_EBADHANDLE + } } /// Causes a fault on a particular call that was made @@ -4044,13 +4881,19 @@ pub fn call_reply( pub fn call_fault( ctx: FunctionEnvMut<'_, WasiEnv>, cid: __wasi_cid_t, - fault: __bus_errno_t, -) -> __bus_errno_t { + fault: __bus_errno_t) +{ let env = ctx.data(); let bus = env.runtime.bus(); debug!("wasi::call_fault (cid={}, fault={})", cid, fault); - __BUS_EUNSUPPORTED + let mut guard = env.state.bus.lock().unwrap(); + guard.calls.remove(&cid); + + if let Some(call) = guard.called.remove(&cid) { + drop(guard); + call.fault(wasi_error_into_bus_err(fault)); + } } /// Closes a bus call based on its bus call handle @@ -4058,12 +4901,17 @@ pub fn call_fault( /// ## Parameters /// /// * `cid` - Handle of the bus call handle to be dropped -pub fn call_close(ctx: FunctionEnvMut<'_, WasiEnv>, cid: __wasi_cid_t) -> __bus_errno_t { +pub fn call_close( + ctx: FunctionEnvMut<'_, WasiEnv>, + cid: __wasi_cid_t +) { let env = ctx.data(); let bus = env.runtime.bus(); trace!("wasi::call_close (cid={})", cid); - __BUS_EUNSUPPORTED + let mut guard = env.state.bus.lock().unwrap(); + guard.calls.remove(&cid); + guard.called.remove(&cid); } /// ### `ws_connect()` @@ -4102,7 +4950,7 @@ pub fn ws_connect( inodes.deref_mut(), kind, false, - "socket".to_string(), + "socket".into(), ); let rights = super::state::all_socket_rights(); let fd = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode)); @@ -4200,19 +5048,19 @@ pub fn http_request( inodes.deref_mut(), kind_req, false, - "http_request".to_string(), + "http_request".into(), ); let inode_res = state.fs.create_inode_with_default_stat( inodes.deref_mut(), kind_res, false, - "http_response".to_string(), + "http_response".into(), ); let inode_hdr = state.fs.create_inode_with_default_stat( inodes.deref_mut(), kind_hdr, false, - "http_headers".to_string(), + "http_headers".into(), ); let rights = super::state::all_socket_rights(); @@ -4721,7 +5569,7 @@ pub fn sock_open( inodes.deref_mut(), kind, false, - "socket".to_string(), + "socket".into(), ); let rights = super::state::all_socket_rights(); let fd = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode)); @@ -5173,7 +6021,7 @@ pub fn sock_accept( inodes.deref_mut(), kind, false, - "socket".to_string(), + "socket".into(), ); let rights = super::state::all_socket_rights(); @@ -5204,12 +6052,10 @@ pub fn sock_accept( /// * `fd` - Socket descriptor /// * `addr` - Address of the socket to connect to pub fn sock_connect( - ctx: FunctionEnvMut<'_, WasiEnv>, + ctx: FunctionEnvMut, sock: __wasi_fd_t, addr: WasmPtr<__wasi_addr_port_t, M>, ) -> __wasi_errno_t { - debug!("wasi::sock_connect"); - let env = ctx.data(); let addr = wasi_try!(super::state::read_ip_port(&ctx, env.memory(), addr)); let addr = SocketAddr::new(addr.0, addr.1); @@ -5403,8 +6249,8 @@ pub fn sock_send_to( /// ## Return /// /// Number of bytes transmitted. -pub unsafe fn sock_send_file( - mut ctx: FunctionEnvMut<'_, WasiEnv>, +pub fn sock_send_file( + ctx: FunctionEnvMut<'_, WasiEnv>, sock: __wasi_fd_t, in_fd: __wasi_fd_t, offset: __wasi_filesize_t, diff --git a/lib/wasi/src/syscalls/wasi.rs b/lib/wasi/src/syscalls/wasi.rs deleted file mode 100644 index b2575f6e53c..00000000000 --- a/lib/wasi/src/syscalls/wasi.rs +++ /dev/null @@ -1,450 +0,0 @@ -#![deny(dead_code)] -use crate::{WasiEnv, WasiError, WasiState, WasiThread}; -use wasmer::{StoreMut, Memory, Memory32, MemorySize, WasmPtr, WasmSlice}; -use wasmer_wasi_types::*; - -type MemoryType = Memory32; -type MemoryOffset = u32; - -pub(crate) fn args_get( - ctx: FunctionEnvMut, - argv: WasmPtr, MemoryType>, - argv_buf: WasmPtr, -) -> __wasi_errno_t { - super::args_get::(ctx, argv, argv_buf) -} - -pub(crate) fn args_sizes_get( - ctx: FunctionEnvMut, - argc: WasmPtr, - argv_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::args_sizes_get::(ctx, argc, argv_buf_size) -} - -pub(crate) fn clock_res_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_res_get::(ctx, clock_id, resolution) -} - -pub(crate) fn clock_time_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - precision: __wasi_timestamp_t, - time: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_time_get::(ctx, clock_id, precision, time) -} - -pub(crate) fn environ_get( - ctx: FunctionEnvMut, - environ: WasmPtr, MemoryType>, - environ_buf: WasmPtr, -) -> __wasi_errno_t { - super::environ_get::(ctx, environ, environ_buf) -} - -pub(crate) fn environ_sizes_get( - ctx: FunctionEnvMut, - environ_count: WasmPtr, - environ_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::environ_sizes_get::(ctx, environ_count, environ_buf_size) -} - -pub(crate) fn fd_advise( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, - advice: __wasi_advice_t, -) -> __wasi_errno_t { - super::fd_advise(ctx, fd, offset, len, advice) -} - -pub(crate) fn fd_allocate( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_allocate(ctx, fd, offset, len) -} - -pub(crate) fn fd_close(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_close(ctx, fd) -} - -pub(crate) fn fd_datasync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_datasync(ctx, fd) -} - -pub(crate) fn fd_fdstat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_fdstat_get::(ctx, fd, buf_ptr) -} - -pub(crate) fn fd_fdstat_set_flags( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_fdflags_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_flags(ctx, fd, flags) -} - -pub(crate) fn fd_fdstat_set_rights( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_rights(ctx, fd, fs_rights_base, fs_rights_inheriting) -} - -pub(crate) fn fd_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_filestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_filestat_set_size( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_filestat_set_size(ctx, fd, st_size) -} - -pub(crate) fn fd_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::fd_filestat_set_times(ctx, fd, st_atim, st_mtim, fst_flags) -} - -pub(crate) fn fd_pread( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pread::(ctx, fd, iovs, iovs_len, offset, nread) -} - -pub(crate) fn fd_prestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_prestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_prestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_prestat_dir_name( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::fd_prestat_dir_name::(ctx, fd, path, path_len) -} - -pub(crate) fn fd_pwrite( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pwrite::(ctx, fd, iovs, iovs_len, offset, nwritten) -} - -pub(crate) fn fd_read( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_read::(ctx, fd, iovs, iovs_len, nread) -} - -pub(crate) fn fd_readdir( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr, - buf_len: MemoryOffset, - cookie: __wasi_dircookie_t, - bufused: WasmPtr, -) -> __wasi_errno_t { - super::fd_readdir::(ctx, fd, buf, buf_len, cookie, bufused) -} - -pub(crate) fn fd_renumber( - ctx: FunctionEnvMut, - from: __wasi_fd_t, - to: __wasi_fd_t, -) -> __wasi_errno_t { - super::fd_renumber(ctx, from, to) -} - -pub(crate) fn fd_seek( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filedelta_t, - whence: __wasi_whence_t, - newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_seek::(ctx, fd, offset, whence, newoffset) -} - -pub(crate) fn fd_sync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_sync(ctx, fd) -} - -pub(crate) fn fd_tell( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_tell::(ctx, fd, offset) -} - -pub(crate) fn fd_write( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_write::(ctx, fd, iovs, iovs_len, nwritten) -} - -pub(crate) fn path_create_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_create_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::path_filestat_get::(ctx, fd, flags, path, path_len, buf) -} - -pub(crate) fn path_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::path_filestat_set_times::( - ctx, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, - ) -} - -pub(crate) fn path_link( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_flags: __wasi_lookupflags_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_link::( - ctx, - old_fd, - old_flags, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_open( - ctx: FunctionEnvMut, - dirfd: __wasi_fd_t, - dirflags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - o_flags: __wasi_oflags_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, - fs_flags: __wasi_fdflags_t, - fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::path_open::( - ctx, - dirfd, - dirflags, - path, - path_len, - o_flags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd, - ) -} - -pub(crate) fn path_readlink( - ctx: FunctionEnvMut, - dir_fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr, - buf_len: MemoryOffset, - buf_used: WasmPtr, -) -> __wasi_errno_t { - super::path_readlink::(ctx, dir_fd, path, path_len, buf, buf_len, buf_used) -} - -pub(crate) fn path_remove_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_remove_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_rename( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_rename::( - ctx, - old_fd, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_symlink( - ctx: FunctionEnvMut, - old_path: WasmPtr, - old_path_len: MemoryOffset, - fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_symlink::(ctx, old_path, old_path_len, fd, new_path, new_path_len) -} - -pub(crate) fn path_unlink_file( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_unlink_file::(ctx, fd, path, path_len) -} - -pub(crate) fn poll_oneoff( - ctx: FunctionEnvMut, - in_: WasmPtr<__wasi_subscription_t, MemoryType>, - out_: WasmPtr<__wasi_event_t, MemoryType>, - nsubscriptions: MemoryOffset, - nevents: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::poll_oneoff::(ctx, in_, out_, nsubscriptions, nevents) -} - -pub(crate) fn proc_exit( - ctx: FunctionEnvMut, - code: __wasi_exitcode_t, -) -> Result<(), WasiError> { - super::proc_exit(ctx, code) -} - -pub(crate) fn proc_raise(ctx: FunctionEnvMut, sig: __wasi_signal_t) -> __wasi_errno_t { - super::proc_raise(ctx, sig) -} - -pub(crate) fn random_get( - ctx: FunctionEnvMut, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::random_get::(ctx, buf, buf_len) -} - -pub(crate) fn sched_yield(ctx: FunctionEnvMut) -> Result<__wasi_errno_t, WasiError> { - super::sched_yield(ctx) -} - -pub(crate) fn sock_recv( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ) -} - -pub(crate) fn sock_send( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send::(ctx, sock, si_data, si_data_len, si_flags, ret_data_len) -} - -pub(crate) fn sock_shutdown( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - how: __wasi_sdflags_t, -) -> __wasi_errno_t { - super::sock_shutdown(ctx, sock, how) -} diff --git a/lib/wasi/src/syscalls/wasix32.rs b/lib/wasi/src/syscalls/wasix32.rs deleted file mode 100644 index 5cb6899c3ef..00000000000 --- a/lib/wasi/src/syscalls/wasix32.rs +++ /dev/null @@ -1,1060 +0,0 @@ -#![deny(dead_code)] -use crate::{WasiEnv, WasiError, WasiState, WasiThread}; -use wasmer::{FunctionEnvMut, Memory, Memory32, MemorySize, StoreMut, WasmPtr, WasmSlice}; -use wasmer_wasi_types::*; - -type MemoryType = Memory32; -type MemoryOffset = u32; - -pub(crate) fn args_get( - ctx: FunctionEnvMut, - argv: WasmPtr, MemoryType>, - argv_buf: WasmPtr, -) -> __wasi_errno_t { - super::args_get::(ctx, argv, argv_buf) -} - -pub(crate) fn args_sizes_get( - ctx: FunctionEnvMut, - argc: WasmPtr, - argv_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::args_sizes_get::(ctx, argc, argv_buf_size) -} - -pub(crate) fn clock_res_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_res_get::(ctx, clock_id, resolution) -} - -pub(crate) fn clock_time_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - precision: __wasi_timestamp_t, - time: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_time_get::(ctx, clock_id, precision, time) -} - -pub(crate) fn environ_get( - ctx: FunctionEnvMut, - environ: WasmPtr, MemoryType>, - environ_buf: WasmPtr, -) -> __wasi_errno_t { - super::environ_get::(ctx, environ, environ_buf) -} - -pub(crate) fn environ_sizes_get( - ctx: FunctionEnvMut, - environ_count: WasmPtr, - environ_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::environ_sizes_get::(ctx, environ_count, environ_buf_size) -} - -pub(crate) fn fd_advise( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, - advice: __wasi_advice_t, -) -> __wasi_errno_t { - super::fd_advise(ctx, fd, offset, len, advice) -} - -pub(crate) fn fd_allocate( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_allocate(ctx, fd, offset, len) -} - -pub(crate) fn fd_close(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_close(ctx, fd) -} - -pub(crate) fn fd_datasync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_datasync(ctx, fd) -} - -pub(crate) fn fd_fdstat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_fdstat_get::(ctx, fd, buf_ptr) -} - -pub(crate) fn fd_fdstat_set_flags( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_fdflags_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_flags(ctx, fd, flags) -} - -pub(crate) fn fd_fdstat_set_rights( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_rights(ctx, fd, fs_rights_base, fs_rights_inheriting) -} - -pub(crate) fn fd_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_filestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_filestat_set_size( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_filestat_set_size(ctx, fd, st_size) -} - -pub(crate) fn fd_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::fd_filestat_set_times(ctx, fd, st_atim, st_mtim, fst_flags) -} - -pub(crate) fn fd_pread( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pread::(ctx, fd, iovs, iovs_len, offset, nread) -} - -pub(crate) fn fd_prestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_prestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_prestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_prestat_dir_name( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::fd_prestat_dir_name::(ctx, fd, path, path_len) -} - -pub(crate) fn fd_pwrite( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pwrite::(ctx, fd, iovs, iovs_len, offset, nwritten) -} - -pub(crate) fn fd_read( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_read::(ctx, fd, iovs, iovs_len, nread) -} - -pub(crate) fn fd_readdir( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr, - buf_len: MemoryOffset, - cookie: __wasi_dircookie_t, - bufused: WasmPtr, -) -> __wasi_errno_t { - super::fd_readdir::(ctx, fd, buf, buf_len, cookie, bufused) -} - -pub(crate) fn fd_renumber( - ctx: FunctionEnvMut, - from: __wasi_fd_t, - to: __wasi_fd_t, -) -> __wasi_errno_t { - super::fd_renumber(ctx, from, to) -} - -pub(crate) fn fd_seek( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filedelta_t, - whence: __wasi_whence_t, - newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_seek::(ctx, fd, offset, whence, newoffset) -} - -pub(crate) fn fd_sync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_sync(ctx, fd) -} - -pub(crate) fn fd_tell( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_tell::(ctx, fd, offset) -} - -pub(crate) fn fd_write( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_write::(ctx, fd, iovs, iovs_len, nwritten) -} - -pub(crate) fn path_create_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_create_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::path_filestat_get::(ctx, fd, flags, path, path_len, buf) -} - -pub(crate) fn path_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::path_filestat_set_times::( - ctx, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, - ) -} - -pub(crate) fn path_link( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_flags: __wasi_lookupflags_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_link::( - ctx, - old_fd, - old_flags, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_open( - ctx: FunctionEnvMut, - dirfd: __wasi_fd_t, - dirflags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - o_flags: __wasi_oflags_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, - fs_flags: __wasi_fdflags_t, - fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::path_open::( - ctx, - dirfd, - dirflags, - path, - path_len, - o_flags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd, - ) -} - -pub(crate) fn path_readlink( - ctx: FunctionEnvMut, - dir_fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr, - buf_len: MemoryOffset, - buf_used: WasmPtr, -) -> __wasi_errno_t { - super::path_readlink::(ctx, dir_fd, path, path_len, buf, buf_len, buf_used) -} - -pub(crate) fn path_remove_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_remove_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_rename( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_rename::( - ctx, - old_fd, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_symlink( - ctx: FunctionEnvMut, - old_path: WasmPtr, - old_path_len: MemoryOffset, - fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_symlink::(ctx, old_path, old_path_len, fd, new_path, new_path_len) -} - -pub(crate) fn path_unlink_file( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_unlink_file::(ctx, fd, path, path_len) -} - -pub(crate) fn poll_oneoff( - ctx: FunctionEnvMut, - in_: WasmPtr<__wasi_subscription_t, MemoryType>, - out_: WasmPtr<__wasi_event_t, MemoryType>, - nsubscriptions: MemoryOffset, - nevents: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::poll_oneoff::(ctx, in_, out_, nsubscriptions, nevents) -} - -pub(crate) fn proc_exit( - ctx: FunctionEnvMut, - code: __wasi_exitcode_t, -) -> Result<(), WasiError> { - super::proc_exit(ctx, code) -} - -pub(crate) fn proc_raise(ctx: FunctionEnvMut, sig: __wasi_signal_t) -> __wasi_errno_t { - super::proc_raise(ctx, sig) -} - -pub(crate) fn random_get( - ctx: FunctionEnvMut, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::random_get::(ctx, buf, buf_len) -} - -pub(crate) fn fd_dup( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_dup::(ctx, fd, ret_fd) -} - -pub(crate) fn fd_event( - ctx: FunctionEnvMut, - initial_val: u64, - flags: __wasi_eventfdflags, - ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_event(ctx, initial_val, flags, ret_fd) -} - -pub(crate) fn fd_pipe( - ctx: FunctionEnvMut, - ro_fd1: WasmPtr<__wasi_fd_t, MemoryType>, - ro_fd2: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_pipe::(ctx, ro_fd1, ro_fd2) -} - -pub(crate) fn tty_get( - ctx: FunctionEnvMut, - tty_state: WasmPtr<__wasi_tty_t, MemoryType>, -) -> __wasi_errno_t { - super::tty_get::(ctx, tty_state) -} - -pub(crate) fn tty_set( - ctx: FunctionEnvMut, - tty_state: WasmPtr<__wasi_tty_t, MemoryType>, -) -> __wasi_errno_t { - super::tty_set::(ctx, tty_state) -} - -pub(crate) fn getcwd( - ctx: FunctionEnvMut, - path: WasmPtr, - path_len: WasmPtr, -) -> __wasi_errno_t { - super::getcwd::(ctx, path, path_len) -} - -pub(crate) fn chdir( - ctx: FunctionEnvMut, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::chdir::(ctx, path, path_len) -} - -pub(crate) fn thread_spawn( - ctx: FunctionEnvMut, - method: WasmPtr, - method_len: MemoryOffset, - user_data: u64, - reactor: __wasi_bool_t, - ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, -) -> __wasi_errno_t { - super::thread_spawn::(ctx, method, method_len, user_data, reactor, ret_tid) -} - -pub(crate) fn thread_sleep( - ctx: FunctionEnvMut, - duration: __wasi_timestamp_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_sleep(ctx, duration) -} - -pub(crate) fn thread_id( - ctx: FunctionEnvMut, - ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, -) -> __wasi_errno_t { - super::thread_id::(ctx, ret_tid) -} - -pub(crate) fn thread_join( - ctx: FunctionEnvMut, - tid: __wasi_tid_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_join(ctx, tid) -} - -pub(crate) fn thread_parallelism( - ctx: FunctionEnvMut, - ret_parallelism: WasmPtr, -) -> __wasi_errno_t { - super::thread_parallelism::(ctx, ret_parallelism) -} - -pub(crate) fn thread_exit( - ctx: FunctionEnvMut, - exitcode: __wasi_exitcode_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_exit(ctx, exitcode) -} - -pub(crate) fn sched_yield(ctx: FunctionEnvMut) -> Result<__wasi_errno_t, WasiError> { - super::sched_yield(ctx) -} - -pub(crate) fn getpid( - ctx: FunctionEnvMut, - ret_pid: WasmPtr<__wasi_pid_t, MemoryType>, -) -> __wasi_errno_t { - super::getpid::(ctx, ret_pid) -} - -pub(crate) fn process_spawn( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - chroot: __wasi_bool_t, - args: WasmPtr, - args_len: MemoryOffset, - preopen: WasmPtr, - preopen_len: MemoryOffset, - stdin: __wasi_stdiomode_t, - stdout: __wasi_stdiomode_t, - stderr: __wasi_stdiomode_t, - working_dir: WasmPtr, - working_dir_len: MemoryOffset, - ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, -) -> __bus_errno_t { - super::process_spawn::( - ctx, - name, - name_len, - chroot, - args, - args_len, - preopen, - preopen_len, - stdin, - stdout, - stderr, - working_dir, - working_dir_len, - ret_handles, - ) -} - -pub(crate) fn bus_open_local( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - reuse: __wasi_bool_t, - ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_open_local::(ctx, name, name_len, reuse, ret_bid) -} - -pub(crate) fn bus_open_remote( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - reuse: __wasi_bool_t, - instance: WasmPtr, - instance_len: MemoryOffset, - token: WasmPtr, - token_len: MemoryOffset, - ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_open_remote::( - ctx, - name, - name_len, - reuse, - instance, - instance_len, - token, - token_len, - ret_bid, - ) -} - -pub(crate) fn bus_close(ctx: FunctionEnvMut, bid: __wasi_bid_t) -> __bus_errno_t { - super::bus_close(ctx, bid) -} - -pub(crate) fn bus_call( - ctx: FunctionEnvMut, - bid: __wasi_bid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: MemoryOffset, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, - ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_call::( - ctx, bid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, - ) -} - -pub(crate) fn bus_subcall( - ctx: FunctionEnvMut, - parent: __wasi_cid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: MemoryOffset, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, - ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_subcall::( - ctx, parent, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, - ) -} - -pub(crate) fn bus_poll( - ctx: FunctionEnvMut, - timeout: __wasi_timestamp_t, - events: WasmPtr, - nevents: MemoryOffset, - malloc: WasmPtr, - malloc_len: MemoryOffset, - ret_nevents: WasmPtr, -) -> __bus_errno_t { - super::bus_poll::( - ctx, - timeout, - events, - nevents, - malloc, - malloc_len, - ret_nevents, - ) -} - -pub(crate) fn call_reply( - ctx: FunctionEnvMut, - cid: __wasi_cid_t, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __bus_errno_t { - super::call_reply::(ctx, cid, format, buf, buf_len) -} - -pub(crate) fn call_fault( - ctx: FunctionEnvMut, - cid: __wasi_cid_t, - fault: __bus_errno_t, -) -> __bus_errno_t { - super::call_fault(ctx, cid, fault) -} - -pub(crate) fn call_close(ctx: FunctionEnvMut, cid: __wasi_cid_t) -> __bus_errno_t { - super::call_close(ctx, cid) -} - -pub(crate) fn port_bridge( - ctx: FunctionEnvMut, - network: WasmPtr, - network_len: MemoryOffset, - token: WasmPtr, - token_len: MemoryOffset, - security: __wasi_streamsecurity_t, -) -> __wasi_errno_t { - super::port_bridge::(ctx, network, network_len, token, token_len, security) -} - -pub(crate) fn port_unbridge(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_unbridge(ctx) -} - -pub(crate) fn port_dhcp_acquire(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_dhcp_acquire(ctx) -} - -pub(crate) fn port_addr_add( - ctx: FunctionEnvMut, - addr: WasmPtr<__wasi_cidr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_addr_add::(ctx, addr) -} - -pub(crate) fn port_addr_remove( - ctx: FunctionEnvMut, - addr: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_addr_remove::(ctx, addr) -} - -pub(crate) fn port_addr_clear(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_addr_clear(ctx) -} - -pub(crate) fn port_addr_list( - ctx: FunctionEnvMut, - addrs: WasmPtr<__wasi_cidr_t, MemoryType>, - naddrs: WasmPtr, -) -> __wasi_errno_t { - super::port_addr_list::(ctx, addrs, naddrs) -} - -pub(crate) fn port_mac( - ctx: FunctionEnvMut, - ret_mac: WasmPtr<__wasi_hardwareaddress_t, MemoryType>, -) -> __wasi_errno_t { - super::port_mac::(ctx, ret_mac) -} - -pub(crate) fn port_gateway_set( - ctx: FunctionEnvMut, - ip: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_gateway_set::(ctx, ip) -} - -pub(crate) fn port_route_add( - ctx: FunctionEnvMut, - cidr: WasmPtr<__wasi_cidr_t, MemoryType>, - via_router: WasmPtr<__wasi_addr_t, MemoryType>, - preferred_until: WasmPtr<__wasi_option_timestamp_t, MemoryType>, - expires_at: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::port_route_add::(ctx, cidr, via_router, preferred_until, expires_at) -} - -pub(crate) fn port_route_remove( - ctx: FunctionEnvMut, - ip: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_route_remove::(ctx, ip) -} - -pub(crate) fn port_route_clear(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_route_clear(ctx) -} - -pub(crate) fn port_route_list( - ctx: FunctionEnvMut, - routes: WasmPtr<__wasi_route_t, MemoryType>, - nroutes: WasmPtr, -) -> __wasi_errno_t { - super::port_route_list::(ctx, routes, nroutes) -} - -pub(crate) fn ws_connect( - ctx: FunctionEnvMut, - url: WasmPtr, - url_len: MemoryOffset, - ret_sock: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::ws_connect::(ctx, url, url_len, ret_sock) -} - -pub(crate) fn http_request( - ctx: FunctionEnvMut, - url: WasmPtr, - url_len: MemoryOffset, - method: WasmPtr, - method_len: MemoryOffset, - headers: WasmPtr, - headers_len: MemoryOffset, - gzip: __wasi_bool_t, - ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, -) -> __wasi_errno_t { - super::http_request::( - ctx, - url, - url_len, - method, - method_len, - headers, - headers_len, - gzip, - ret_handles, - ) -} - -pub(crate) fn http_status( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - status: WasmPtr<__wasi_http_status_t, MemoryType>, - status_text: WasmPtr, - status_text_len: WasmPtr, - headers: WasmPtr, - headers_len: WasmPtr, -) -> __wasi_errno_t { - super::http_status::(ctx, sock, status) -} - -pub(crate) fn sock_status( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_status::(ctx, sock, ret_status) -} - -pub(crate) fn sock_addr_local( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ret_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_addr_local::(ctx, sock, ret_addr) -} - -pub(crate) fn sock_addr_peer( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_addr_peer::(ctx, sock, ro_addr) -} - -pub(crate) fn sock_open( - ctx: FunctionEnvMut, - af: __wasi_addressfamily_t, - ty: __wasi_socktype_t, - pt: __wasi_sockproto_t, - ro_sock: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_open::(ctx, af, ty, pt, ro_sock) -} - -pub(crate) fn sock_set_opt_flag( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - flag: __wasi_bool_t, -) -> __wasi_errno_t { - super::sock_set_opt_flag(ctx, sock, opt, flag) -} - -pub(crate) fn sock_get_opt_flag( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_flag: WasmPtr<__wasi_bool_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_flag::(ctx, sock, opt, ret_flag) -} - -pub fn sock_set_opt_time( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_set_opt_time(ctx, sock, opt, time) -} - -pub fn sock_get_opt_time( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_time(ctx, sock, opt, ret_time) -} - -pub fn sock_set_opt_size( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::sock_set_opt_size(ctx, sock, opt, size) -} - -pub fn sock_get_opt_size( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_size: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_size(ctx, sock, opt, ret_size) -} - -pub(crate) fn sock_join_multicast_v4( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, - iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_join_multicast_v4::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_leave_multicast_v4( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, - iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_leave_multicast_v4::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_join_multicast_v6( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, - iface: u32, -) -> __wasi_errno_t { - super::sock_join_multicast_v6::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_leave_multicast_v6( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, - iface: u32, -) -> __wasi_errno_t { - super::sock_leave_multicast_v6::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_bind( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_bind::(ctx, sock, addr) -} - -pub(crate) fn sock_listen( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - backlog: MemoryOffset, -) -> __wasi_errno_t { - super::sock_listen::(ctx, sock, backlog) -} - -pub(crate) fn sock_accept( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - fd_flags: __wasi_fdflags_t, - ro_fd: WasmPtr<__wasi_fd_t, MemoryType>, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_accept::(ctx, sock, fd_flags, ro_fd, ro_addr) -} - -pub(crate) fn sock_connect( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_connect::(ctx, sock, addr) -} - -pub(crate) fn sock_recv( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ) -} - -pub(crate) fn sock_recv_from( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv_from::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ro_addr, - ) -} - -pub(crate) fn sock_send( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send::(ctx, sock, si_data, si_data_len, si_flags, ret_data_len) -} - -pub(crate) fn sock_send_to( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send_to::( - ctx, - sock, - si_data, - si_data_len, - si_flags, - addr, - ret_data_len, - ) -} - -pub(crate) fn sock_send_file( - ctx: FunctionEnvMut, - out_fd: __wasi_fd_t, - in_fd: __wasi_fd_t, - offset: __wasi_filesize_t, - count: __wasi_filesize_t, - ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - unsafe { super::sock_send_file::(ctx, out_fd, in_fd, offset, count, ret_sent) } -} - -pub(crate) fn sock_shutdown( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - how: __wasi_sdflags_t, -) -> __wasi_errno_t { - super::sock_shutdown(ctx, sock, how) -} - -pub(crate) fn resolve( - ctx: FunctionEnvMut, - host: WasmPtr, - host_len: MemoryOffset, - port: u16, - ips: WasmPtr<__wasi_addr_t, MemoryType>, - nips: MemoryOffset, - ret_nips: WasmPtr, -) -> __wasi_errno_t { - super::resolve::(ctx, host, host_len, port, ips, nips, ret_nips) -} diff --git a/lib/wasi/src/syscalls/wasix64.rs b/lib/wasi/src/syscalls/wasix64.rs deleted file mode 100644 index b42307e0da8..00000000000 --- a/lib/wasi/src/syscalls/wasix64.rs +++ /dev/null @@ -1,1060 +0,0 @@ -#![deny(dead_code)] -use crate::{WasiEnv, WasiError, WasiState, WasiThread}; -use wasmer::{FunctionEnvMut, Memory, Memory64, MemorySize, StoreMut, WasmPtr, WasmSlice}; -use wasmer_wasi_types::*; - -type MemoryType = Memory64; -type MemoryOffset = u64; - -pub(crate) fn args_get( - ctx: FunctionEnvMut, - argv: WasmPtr, MemoryType>, - argv_buf: WasmPtr, -) -> __wasi_errno_t { - super::args_get::(ctx, argv, argv_buf) -} - -pub(crate) fn args_sizes_get( - ctx: FunctionEnvMut, - argc: WasmPtr, - argv_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::args_sizes_get::(ctx, argc, argv_buf_size) -} - -pub(crate) fn clock_res_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_res_get::(ctx, clock_id, resolution) -} - -pub(crate) fn clock_time_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - precision: __wasi_timestamp_t, - time: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_time_get::(ctx, clock_id, precision, time) -} - -pub(crate) fn environ_get( - ctx: FunctionEnvMut, - environ: WasmPtr, MemoryType>, - environ_buf: WasmPtr, -) -> __wasi_errno_t { - super::environ_get::(ctx, environ, environ_buf) -} - -pub(crate) fn environ_sizes_get( - ctx: FunctionEnvMut, - environ_count: WasmPtr, - environ_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::environ_sizes_get::(ctx, environ_count, environ_buf_size) -} - -pub(crate) fn fd_advise( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, - advice: __wasi_advice_t, -) -> __wasi_errno_t { - super::fd_advise(ctx, fd, offset, len, advice) -} - -pub(crate) fn fd_allocate( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_allocate(ctx, fd, offset, len) -} - -pub(crate) fn fd_close(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_close(ctx, fd) -} - -pub(crate) fn fd_datasync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_datasync(ctx, fd) -} - -pub(crate) fn fd_fdstat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_fdstat_get::(ctx, fd, buf_ptr) -} - -pub(crate) fn fd_fdstat_set_flags( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_fdflags_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_flags(ctx, fd, flags) -} - -pub(crate) fn fd_fdstat_set_rights( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_rights(ctx, fd, fs_rights_base, fs_rights_inheriting) -} - -pub(crate) fn fd_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_filestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_filestat_set_size( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_filestat_set_size(ctx, fd, st_size) -} - -pub(crate) fn fd_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::fd_filestat_set_times(ctx, fd, st_atim, st_mtim, fst_flags) -} - -pub(crate) fn fd_pread( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pread::(ctx, fd, iovs, iovs_len, offset, nread) -} - -pub(crate) fn fd_prestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_prestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_prestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_prestat_dir_name( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::fd_prestat_dir_name::(ctx, fd, path, path_len) -} - -pub(crate) fn fd_pwrite( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pwrite::(ctx, fd, iovs, iovs_len, offset, nwritten) -} - -pub(crate) fn fd_read( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_read::(ctx, fd, iovs, iovs_len, nread) -} - -pub(crate) fn fd_readdir( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr, - buf_len: MemoryOffset, - cookie: __wasi_dircookie_t, - bufused: WasmPtr, -) -> __wasi_errno_t { - super::fd_readdir::(ctx, fd, buf, buf_len, cookie, bufused) -} - -pub(crate) fn fd_renumber( - ctx: FunctionEnvMut, - from: __wasi_fd_t, - to: __wasi_fd_t, -) -> __wasi_errno_t { - super::fd_renumber(ctx, from, to) -} - -pub(crate) fn fd_seek( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filedelta_t, - whence: __wasi_whence_t, - newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_seek::(ctx, fd, offset, whence, newoffset) -} - -pub(crate) fn fd_sync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_sync(ctx, fd) -} - -pub(crate) fn fd_tell( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_tell::(ctx, fd, offset) -} - -pub(crate) fn fd_write( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_write::(ctx, fd, iovs, iovs_len, nwritten) -} - -pub(crate) fn path_create_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_create_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::path_filestat_get::(ctx, fd, flags, path, path_len, buf) -} - -pub(crate) fn path_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::path_filestat_set_times::( - ctx, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, - ) -} - -pub(crate) fn path_link( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_flags: __wasi_lookupflags_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_link::( - ctx, - old_fd, - old_flags, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_open( - ctx: FunctionEnvMut, - dirfd: __wasi_fd_t, - dirflags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - o_flags: __wasi_oflags_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, - fs_flags: __wasi_fdflags_t, - fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::path_open::( - ctx, - dirfd, - dirflags, - path, - path_len, - o_flags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd, - ) -} - -pub(crate) fn path_readlink( - ctx: FunctionEnvMut, - dir_fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr, - buf_len: MemoryOffset, - buf_used: WasmPtr, -) -> __wasi_errno_t { - super::path_readlink::(ctx, dir_fd, path, path_len, buf, buf_len, buf_used) -} - -pub(crate) fn path_remove_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_remove_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_rename( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_rename::( - ctx, - old_fd, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_symlink( - ctx: FunctionEnvMut, - old_path: WasmPtr, - old_path_len: MemoryOffset, - fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_symlink::(ctx, old_path, old_path_len, fd, new_path, new_path_len) -} - -pub(crate) fn path_unlink_file( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_unlink_file::(ctx, fd, path, path_len) -} - -pub(crate) fn poll_oneoff( - ctx: FunctionEnvMut, - in_: WasmPtr<__wasi_subscription_t, MemoryType>, - out_: WasmPtr<__wasi_event_t, MemoryType>, - nsubscriptions: MemoryOffset, - nevents: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::poll_oneoff::(ctx, in_, out_, nsubscriptions, nevents) -} - -pub(crate) fn proc_exit( - ctx: FunctionEnvMut, - code: __wasi_exitcode_t, -) -> Result<(), WasiError> { - super::proc_exit(ctx, code) -} - -pub(crate) fn proc_raise(ctx: FunctionEnvMut, sig: __wasi_signal_t) -> __wasi_errno_t { - super::proc_raise(ctx, sig) -} - -pub(crate) fn random_get( - ctx: FunctionEnvMut, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::random_get::(ctx, buf, buf_len) -} - -pub(crate) fn fd_dup( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_dup::(ctx, fd, ret_fd) -} - -pub(crate) fn fd_event( - ctx: FunctionEnvMut, - initial_val: u64, - flags: __wasi_eventfdflags, - ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_event(ctx, initial_val, flags, ret_fd) -} - -pub(crate) fn fd_pipe( - ctx: FunctionEnvMut, - ro_fd1: WasmPtr<__wasi_fd_t, MemoryType>, - ro_fd2: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_pipe::(ctx, ro_fd1, ro_fd2) -} - -pub(crate) fn tty_get( - ctx: FunctionEnvMut, - tty_state: WasmPtr<__wasi_tty_t, MemoryType>, -) -> __wasi_errno_t { - super::tty_get::(ctx, tty_state) -} - -pub(crate) fn tty_set( - ctx: FunctionEnvMut, - tty_state: WasmPtr<__wasi_tty_t, MemoryType>, -) -> __wasi_errno_t { - super::tty_set::(ctx, tty_state) -} - -pub(crate) fn getcwd( - ctx: FunctionEnvMut, - path: WasmPtr, - path_len: WasmPtr, -) -> __wasi_errno_t { - super::getcwd::(ctx, path, path_len) -} - -pub(crate) fn chdir( - ctx: FunctionEnvMut, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::chdir::(ctx, path, path_len) -} - -pub(crate) fn thread_spawn( - ctx: FunctionEnvMut, - method: WasmPtr, - method_len: MemoryOffset, - user_data: u64, - reactor: __wasi_bool_t, - ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, -) -> __wasi_errno_t { - super::thread_spawn::(ctx, method, method_len, user_data, reactor, ret_tid) -} - -pub(crate) fn thread_sleep( - ctx: FunctionEnvMut, - duration: __wasi_timestamp_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_sleep(ctx, duration) -} - -pub(crate) fn thread_id( - ctx: FunctionEnvMut, - ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, -) -> __wasi_errno_t { - super::thread_id::(ctx, ret_tid) -} - -pub(crate) fn thread_join( - ctx: FunctionEnvMut, - tid: __wasi_tid_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_join(ctx, tid) -} - -pub(crate) fn thread_parallelism( - ctx: FunctionEnvMut, - ret_parallelism: WasmPtr, -) -> __wasi_errno_t { - super::thread_parallelism::(ctx, ret_parallelism) -} - -pub(crate) fn thread_exit( - ctx: FunctionEnvMut, - exitcode: __wasi_exitcode_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_exit(ctx, exitcode) -} - -pub(crate) fn sched_yield(ctx: FunctionEnvMut) -> Result<__wasi_errno_t, WasiError> { - super::sched_yield(ctx) -} - -pub(crate) fn getpid( - ctx: FunctionEnvMut, - ret_pid: WasmPtr<__wasi_pid_t, MemoryType>, -) -> __wasi_errno_t { - super::getpid::(ctx, ret_pid) -} - -pub(crate) fn process_spawn( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - chroot: __wasi_bool_t, - args: WasmPtr, - args_len: MemoryOffset, - preopen: WasmPtr, - preopen_len: MemoryOffset, - stdin: __wasi_stdiomode_t, - stdout: __wasi_stdiomode_t, - stderr: __wasi_stdiomode_t, - working_dir: WasmPtr, - working_dir_len: MemoryOffset, - ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, -) -> __bus_errno_t { - super::process_spawn::( - ctx, - name, - name_len, - chroot, - args, - args_len, - preopen, - preopen_len, - stdin, - stdout, - stderr, - working_dir, - working_dir_len, - ret_handles, - ) -} - -pub(crate) fn bus_open_local( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - reuse: __wasi_bool_t, - ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_open_local::(ctx, name, name_len, reuse, ret_bid) -} - -pub(crate) fn bus_open_remote( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - reuse: __wasi_bool_t, - instance: WasmPtr, - instance_len: MemoryOffset, - token: WasmPtr, - token_len: MemoryOffset, - ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_open_remote::( - ctx, - name, - name_len, - reuse, - instance, - instance_len, - token, - token_len, - ret_bid, - ) -} - -pub(crate) fn bus_close(ctx: FunctionEnvMut, bid: __wasi_bid_t) -> __bus_errno_t { - super::bus_close(ctx, bid) -} - -pub(crate) fn bus_call( - ctx: FunctionEnvMut, - bid: __wasi_bid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: MemoryOffset, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, - ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_call::( - ctx, bid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, - ) -} - -pub(crate) fn bus_subcall( - ctx: FunctionEnvMut, - parent: __wasi_cid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: MemoryOffset, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, - ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_subcall::( - ctx, parent, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, - ) -} - -pub(crate) fn bus_poll( - ctx: FunctionEnvMut, - timeout: __wasi_timestamp_t, - events: WasmPtr, - nevents: MemoryOffset, - malloc: WasmPtr, - malloc_len: MemoryOffset, - ret_nevents: WasmPtr, -) -> __bus_errno_t { - super::bus_poll::( - ctx, - timeout, - events, - nevents, - malloc, - malloc_len, - ret_nevents, - ) -} - -pub(crate) fn call_reply( - ctx: FunctionEnvMut, - cid: __wasi_cid_t, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __bus_errno_t { - super::call_reply::(ctx, cid, format, buf, buf_len) -} - -pub(crate) fn call_fault( - ctx: FunctionEnvMut, - cid: __wasi_cid_t, - fault: __bus_errno_t, -) -> __bus_errno_t { - super::call_fault(ctx, cid, fault) -} - -pub(crate) fn call_close(ctx: FunctionEnvMut, cid: __wasi_cid_t) -> __bus_errno_t { - super::call_close(ctx, cid) -} - -pub(crate) fn port_bridge( - ctx: FunctionEnvMut, - network: WasmPtr, - network_len: MemoryOffset, - token: WasmPtr, - token_len: MemoryOffset, - security: __wasi_streamsecurity_t, -) -> __wasi_errno_t { - super::port_bridge::(ctx, network, network_len, token, token_len, security) -} - -pub(crate) fn port_unbridge(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_unbridge(ctx) -} - -pub(crate) fn port_dhcp_acquire(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_dhcp_acquire(ctx) -} - -pub(crate) fn port_addr_add( - ctx: FunctionEnvMut, - addr: WasmPtr<__wasi_cidr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_addr_add::(ctx, addr) -} - -pub(crate) fn port_addr_remove( - ctx: FunctionEnvMut, - addr: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_addr_remove::(ctx, addr) -} - -pub(crate) fn port_addr_clear(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_addr_clear(ctx) -} - -pub(crate) fn port_addr_list( - ctx: FunctionEnvMut, - addrs: WasmPtr<__wasi_cidr_t, MemoryType>, - naddrs: WasmPtr, -) -> __wasi_errno_t { - super::port_addr_list::(ctx, addrs, naddrs) -} - -pub(crate) fn port_mac( - ctx: FunctionEnvMut, - ret_mac: WasmPtr<__wasi_hardwareaddress_t, MemoryType>, -) -> __wasi_errno_t { - super::port_mac::(ctx, ret_mac) -} - -pub(crate) fn port_gateway_set( - ctx: FunctionEnvMut, - ip: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_gateway_set::(ctx, ip) -} - -pub(crate) fn port_route_add( - ctx: FunctionEnvMut, - cidr: WasmPtr<__wasi_cidr_t, MemoryType>, - via_router: WasmPtr<__wasi_addr_t, MemoryType>, - preferred_until: WasmPtr<__wasi_option_timestamp_t, MemoryType>, - expires_at: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::port_route_add::(ctx, cidr, via_router, preferred_until, expires_at) -} - -pub(crate) fn port_route_remove( - ctx: FunctionEnvMut, - ip: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_route_remove::(ctx, ip) -} - -pub(crate) fn port_route_clear(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_route_clear(ctx) -} - -pub(crate) fn port_route_list( - ctx: FunctionEnvMut, - routes: WasmPtr<__wasi_route_t, MemoryType>, - nroutes: WasmPtr, -) -> __wasi_errno_t { - super::port_route_list::(ctx, routes, nroutes) -} - -pub(crate) fn ws_connect( - ctx: FunctionEnvMut, - url: WasmPtr, - url_len: MemoryOffset, - ret_sock: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::ws_connect::(ctx, url, url_len, ret_sock) -} - -pub(crate) fn http_request( - ctx: FunctionEnvMut, - url: WasmPtr, - url_len: MemoryOffset, - method: WasmPtr, - method_len: MemoryOffset, - headers: WasmPtr, - headers_len: MemoryOffset, - gzip: __wasi_bool_t, - ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, -) -> __wasi_errno_t { - super::http_request::( - ctx, - url, - url_len, - method, - method_len, - headers, - headers_len, - gzip, - ret_handles, - ) -} - -pub(crate) fn http_status( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - status: WasmPtr<__wasi_http_status_t, MemoryType>, - status_text: WasmPtr, - status_text_len: WasmPtr, - headers: WasmPtr, - headers_len: WasmPtr, -) -> __wasi_errno_t { - super::http_status::(ctx, sock, status) -} - -pub(crate) fn sock_status( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_status::(ctx, sock, ret_status) -} - -pub(crate) fn sock_addr_local( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ret_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_addr_local::(ctx, sock, ret_addr) -} - -pub(crate) fn sock_addr_peer( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_addr_peer::(ctx, sock, ro_addr) -} - -pub(crate) fn sock_open( - ctx: FunctionEnvMut, - af: __wasi_addressfamily_t, - ty: __wasi_socktype_t, - pt: __wasi_sockproto_t, - ro_sock: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_open::(ctx, af, ty, pt, ro_sock) -} - -pub(crate) fn sock_set_opt_flag( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - flag: __wasi_bool_t, -) -> __wasi_errno_t { - super::sock_set_opt_flag(ctx, sock, opt, flag) -} - -pub(crate) fn sock_get_opt_flag( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_flag: WasmPtr<__wasi_bool_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_flag::(ctx, sock, opt, ret_flag) -} - -pub fn sock_set_opt_time( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_set_opt_time(ctx, sock, opt, time) -} - -pub fn sock_get_opt_time( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_time(ctx, sock, opt, ret_time) -} - -pub fn sock_set_opt_size( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::sock_set_opt_size(ctx, sock, opt, size) -} - -pub fn sock_get_opt_size( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_size: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_size(ctx, sock, opt, ret_size) -} - -pub(crate) fn sock_join_multicast_v4( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, - iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_join_multicast_v4::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_leave_multicast_v4( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, - iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_leave_multicast_v4::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_join_multicast_v6( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, - iface: u32, -) -> __wasi_errno_t { - super::sock_join_multicast_v6::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_leave_multicast_v6( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, - iface: u32, -) -> __wasi_errno_t { - super::sock_leave_multicast_v6::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_bind( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_bind::(ctx, sock, addr) -} - -pub(crate) fn sock_listen( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - backlog: MemoryOffset, -) -> __wasi_errno_t { - super::sock_listen::(ctx, sock, backlog) -} - -pub(crate) fn sock_accept( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - fd_flags: __wasi_fdflags_t, - ro_fd: WasmPtr<__wasi_fd_t, MemoryType>, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_accept::(ctx, sock, fd_flags, ro_fd, ro_addr) -} - -pub(crate) fn sock_connect( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_connect::(ctx, sock, addr) -} - -pub(crate) fn sock_recv( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ) -} - -pub(crate) fn sock_recv_from( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv_from::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ro_addr, - ) -} - -pub(crate) fn sock_send( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send::(ctx, sock, si_data, si_data_len, si_flags, ret_data_len) -} - -pub(crate) fn sock_send_to( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send_to::( - ctx, - sock, - si_data, - si_data_len, - si_flags, - addr, - ret_data_len, - ) -} - -pub(crate) fn sock_send_file( - ctx: FunctionEnvMut, - out_fd: __wasi_fd_t, - in_fd: __wasi_fd_t, - offset: __wasi_filesize_t, - count: __wasi_filesize_t, - ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - unsafe { super::sock_send_file::(ctx, out_fd, in_fd, offset, count, ret_sent) } -} - -pub(crate) fn sock_shutdown( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - how: __wasi_sdflags_t, -) -> __wasi_errno_t { - super::sock_shutdown(ctx, sock, how) -} - -pub(crate) fn resolve( - ctx: FunctionEnvMut, - host: WasmPtr, - host_len: MemoryOffset, - port: u16, - ips: WasmPtr<__wasi_addr_t, MemoryType>, - nips: MemoryOffset, - ret_nips: WasmPtr, -) -> __wasi_errno_t { - super::resolve::(ctx, host, host_len, port, ips, nips, ret_nips) -} diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 78b93520e1a..218a477d2b4 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -23,7 +23,6 @@ mod sys { #[cfg(feature = "js")] mod js { use wasm_bindgen_test::*; - #[wasm_bindgen_test] fn test_stdout() { super::test_stdout() @@ -74,7 +73,7 @@ fn test_stdout() { // Create the `WasiEnv`. let mut stdout = Pipe::default(); - let wasi_env = WasiState::new("command-name") + let mut wasi_env = WasiState::new("command-name") .args(&["Gordon"]) .stdout(Box::new(stdout.clone())) .finalize(&mut store) @@ -85,8 +84,7 @@ fn test_stdout() { // Let's instantiate the module with the imports. let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - let memory = instance.exports.get_memory("memory").unwrap(); - wasi_env.data_mut(&mut store).set_memory(memory.clone()); + wasi_env.initialize(&mut store, &instance).unwrap(); // Let's call the `_start` function, which is our `main` function in Rust. let start = instance.exports.get_function("_start").unwrap(); @@ -118,7 +116,7 @@ fn test_env() { .env("TEST", "VALUE") .env("TEST2", "VALUE2"); // panic!("envs: {:?}", wasi_state_builder.envs); - let wasi_env = wasi_state_builder + let mut wasi_env = wasi_state_builder .stdout(Box::new(stdout.clone())) .finalize(&mut store) .unwrap(); @@ -128,8 +126,7 @@ fn test_env() { // Let's instantiate the module with the imports. let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - let memory = instance.exports.get_memory("memory").unwrap(); - wasi_env.data_mut(&mut store).set_memory(memory.clone()); + wasi_env.initialize(&mut store, &instance).unwrap(); // Let's call the `_start` function, which is our `main` function in Rust. let start = instance.exports.get_function("_start").unwrap(); @@ -147,7 +144,7 @@ fn test_stdin() { // Create the `WasiEnv`. let mut stdin = Pipe::new(); - let wasi_env = WasiState::new("command-name") + let mut wasi_env = WasiState::new("command-name") .stdin(Box::new(stdin.clone())) .finalize(&mut store) .unwrap(); @@ -161,8 +158,7 @@ fn test_stdin() { // Let's instantiate the module with the imports. let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - let memory = instance.exports.get_memory("memory").unwrap(); - wasi_env.data_mut(&mut store).set_memory(memory.clone()); + wasi_env.initialize(&mut store, &instance).unwrap(); // Let's call the `_start` function, which is our `main` function in Rust. let start = instance.exports.get_function("_start").unwrap(); diff --git a/tests/compilers/imports.rs b/tests/compilers/imports.rs index 558e4fa51bd..ac13ef79b14 100644 --- a/tests/compilers/imports.rs +++ b/tests/compilers/imports.rs @@ -170,7 +170,7 @@ fn dynamic_function_with_env(config: crate::Config) -> Result<()> { }, }, )?; - assert_eq!(env.as_mut(&mut store).load(SeqCst), 4); + assert_eq!(env.as_mut(&mut store).unwrap().load(SeqCst), 4); Ok(()) } @@ -346,7 +346,7 @@ fn static_function_with_env(config: crate::Config) -> Result<()> { }, }, )?; - assert_eq!(env.as_mut(&mut store).load(SeqCst), 4); + assert_eq!(env.as_mut(&mut store).unwrap().load(SeqCst), 4); Ok(()) } @@ -439,7 +439,7 @@ fn dynamic_function_with_env_wasmer_env_init_works(config: crate::Config) -> Res }, )?; let memory = instance.exports.get_memory("memory")?; - env.as_mut(&mut store).memory = Some(memory.clone()); + env.as_mut(&mut store).unwrap().memory = Some(memory.clone()); let f: TypedFunction<(), ()> = instance.exports.get_typed_function(&mut store, "main")?; f.call(&mut store)?; Ok(()) @@ -480,14 +480,14 @@ fn multi_use_host_fn_manages_memory_correctly(config: crate::Config) -> Result<( { let f1: TypedFunction<(), ()> = instance1.exports.get_typed_function(&mut store, "main")?; let memory = instance1.exports.get_memory("memory")?; - env.as_mut(&mut store).memory = Some(memory.clone()); + env.as_mut(&mut store).unwrap().memory = Some(memory.clone()); f1.call(&mut store)?; } drop(instance1); { let f2: TypedFunction<(), ()> = instance2.exports.get_typed_function(&mut store, "main")?; let memory = instance2.exports.get_memory("memory")?; - env.as_mut(&mut store).memory = Some(memory.clone()); + env.as_mut(&mut store).unwrap().memory = Some(memory.clone()); f2.call(&mut store)?; } drop(instance2); diff --git a/tests/compilers/issues.rs b/tests/compilers/issues.rs index 03a301e8690..4249e531f9a 100644 --- a/tests/compilers/issues.rs +++ b/tests/compilers/issues.rs @@ -25,7 +25,7 @@ fn issue_2329(mut config: crate::Config) -> Result<()> { } pub fn read_memory(mut ctx: FunctionEnvMut, guest_ptr: u32) -> u32 { - dbg!(ctx.data_mut().memory.as_ref()); + dbg!(ctx.data().memory.as_ref()); dbg!(guest_ptr); 0 } @@ -101,8 +101,8 @@ fn call_with_static_data_pointers(mut config: crate::Config) -> Result<()> { ) -> u64 { println!("{:?}", (a, b, c, d, e, f, g, h)); let mut buf = vec![0; d as usize]; - let memory = ctx.data_mut().memory.as_ref().unwrap().clone(); - memory.read(&mut ctx, e, &mut buf).unwrap(); + let memory = ctx.data().memory.as_ref().unwrap().clone(); + memory.lock(&ctx).read(e, &mut buf).unwrap(); let input_string = std::str::from_utf8(&buf).unwrap(); assert_eq!(input_string, "bananapeach"); 0 @@ -194,7 +194,7 @@ fn call_with_static_data_pointers(mut config: crate::Config) -> Result<()> { MemoryType::new(Pages(1024), Some(Pages(2048)), false), ) .unwrap(); - env.as_mut(&mut store).memory = Some(memory.clone()); + env.as_mut(&mut store).unwrap().memory = Some(memory.clone()); let mut exports = Exports::new(); exports.insert("memory", memory); exports.insert("banana", Function::new_native(&mut store, &env, banana)); diff --git a/tests/compilers/metering.rs b/tests/compilers/metering.rs index 4df524aad4b..7edba0cacfd 100644 --- a/tests/compilers/metering.rs +++ b/tests/compilers/metering.rs @@ -20,8 +20,6 @@ fn run_add_with_limit(mut config: crate::Config, limit: u64) -> Result<()> { (i32.add (local.get 0) (local.get 1))) )"#; - let mut env = FunctionEnv::new(&mut store, ()); - let import_object = imports! {}; let module = Module::new(&store, wat).unwrap(); @@ -54,8 +52,7 @@ fn run_loop(mut config: crate::Config, limit: u64, iter_count: i32) -> Result<() ) )"#; let module = Module::new(&store, wat).unwrap(); - let mut env = FunctionEnv::new(&mut store, ()); - + let import_object = imports! {}; let instance = Instance::new(&mut store, &module, &import_object)?; diff --git a/tests/compilers/native_functions.rs b/tests/compilers/native_functions.rs index 3f6ecac790c..755784b8f38 100644 --- a/tests/compilers/native_functions.rs +++ b/tests/compilers/native_functions.rs @@ -330,7 +330,7 @@ fn static_host_function_with_env(config: crate::Config) -> anyhow::Result<()> { let mut store = config.store(); fn f(mut ctx: FunctionEnvMut, a: i32, b: i64, c: f32, d: f64) -> (f64, f32, i64, i32) { - let mut guard = ctx.data_mut().0.lock().unwrap(); + let mut guard = ctx.data().0.lock().unwrap(); assert_eq!(*guard, 100); *guard = 101; @@ -344,7 +344,7 @@ fn static_host_function_with_env(config: crate::Config) -> anyhow::Result<()> { c: f32, d: f64, ) -> Result<(f64, f32, i64, i32), Infallible> { - let mut guard = ctx.data_mut().0.lock().unwrap(); + let mut guard = ctx.data().0.lock().unwrap(); assert_eq!(*guard, 100); *guard = 101; @@ -370,12 +370,12 @@ fn static_host_function_with_env(config: crate::Config) -> anyhow::Result<()> { let f_native: TypedFunction<(i32, i64, f32, f64), (f64, f32, i64, i32)> = f.native(&mut store).unwrap(); - assert_eq!(*env.as_mut(&mut store).0.lock().unwrap(), 100); + assert_eq!(*env.as_mut(&mut store).unwrap().0.lock().unwrap(), 100); let result = f_native.call(&mut store, 1, 3, 5.0, 7.0)?; assert_eq!(result, (28.0, 15.0, 6, 1)); - assert_eq!(*env.as_mut(&mut store).0.lock().unwrap(), 101); + assert_eq!(*env.as_mut(&mut store).unwrap().0.lock().unwrap(), 101); } // Native static host function that returns a result of a tuple. @@ -387,12 +387,12 @@ fn static_host_function_with_env(config: crate::Config) -> anyhow::Result<()> { let f_native: TypedFunction<(i32, i64, f32, f64), (f64, f32, i64, i32)> = f.native(&mut store).unwrap(); - assert_eq!(*env.as_mut(&mut store).0.lock().unwrap(), 100); + assert_eq!(*env.as_mut(&mut store).unwrap().0.lock().unwrap(), 100); let result = f_native.call(&mut store, 1, 3, 5.0, 7.0)?; assert_eq!(result, (28.0, 15.0, 6, 1)); - assert_eq!(*env.as_mut(&mut store).0.lock().unwrap(), 101); + assert_eq!(*env.as_mut(&mut store).unwrap().0.lock().unwrap(), 101); } Ok(()) @@ -471,7 +471,7 @@ fn dynamic_host_function_with_env(config: crate::Config) -> anyhow::Result<()> { ], ), |mut ctx, values| { - let mut guard = ctx.data_mut().0.lock().unwrap(); + let mut guard = ctx.data().0.lock().unwrap(); assert_eq!(*guard, 100); *guard = 101; @@ -488,12 +488,12 @@ fn dynamic_host_function_with_env(config: crate::Config) -> anyhow::Result<()> { let f_native: TypedFunction<(i32, i64, f32, f64), (f64, f32, i64, i32)> = f.native(&mut store).unwrap(); - assert_eq!(*env.as_mut(&mut store).0.lock().unwrap(), 100); + assert_eq!(*env.as_mut(&mut store).unwrap().0.lock().unwrap(), 100); let result = f_native.call(&mut store, 1, 3, 5.0, 7.0)?; assert_eq!(result, (28.0, 15.0, 6, 1)); - assert_eq!(*env.as_mut(&mut store).0.lock().unwrap(), 101); + assert_eq!(*env.as_mut(&mut store).unwrap().0.lock().unwrap(), 101); Ok(()) } diff --git a/tests/compilers/wast.rs b/tests/compilers/wast.rs index 0f6e3f36cb9..576e62e19fa 100644 --- a/tests/compilers/wast.rs +++ b/tests/compilers/wast.rs @@ -34,7 +34,7 @@ pub fn run_wast(mut config: crate::Config, wast_path: &str) -> anyhow::Result<() config.set_features(features); config.set_nan_canonicalization(try_nan_canonicalization); - let mut store = config.store(); + let store = config.store(); let mut wast = Wast::new_with_spectest(store); // `bulk-memory-operations/bulk.wast` checks for a message that // specifies which element is uninitialized, but our traps don't diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 6b2e13aac4c..f9064050409 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -83,15 +83,15 @@ impl<'a> WasiTest<'a> { out }; let module = Module::new(store, &wasm_bytes)?; - let (env, _tempdirs, stdout_rx, stderr_rx) = + let (mut env, _tempdirs, stdout_rx, stderr_rx) = self.create_wasi_env(store, filesystem_kind)?; let imports = self.get_imports(store, &env.env, &module)?; let instance = Instance::new(&mut store, &module, &imports)?; - + + env.initialize(&mut store, &instance).unwrap(); + let wasi_env = env.data(&store); + let start = instance.exports.get_function("_start")?; - let memory = instance.exports.get_memory("memory")?; - let wasi_env = env.data_mut(&mut store); - wasi_env.set_memory(memory.clone()); if let Some(stdin) = &self.stdin { let state = wasi_env.state();