From f417bfcf0fb9c7f5c3c155781f1a8b44efdada76 Mon Sep 17 00:00:00 2001 From: John Sharratt's Shared Account Date: Fri, 10 Jun 2022 21:45:28 +0200 Subject: [PATCH] Implemented multithreading for the browser (JS) Added a Reactor that drives WebAssembly react pattern Added thread local storage Implemented the remaining functionality for the BUS Fixed an issue where the imports were missing important information about the memory size --- Cargo.lock | 82 +- docs/migration_to_3.0.0.md | 5 +- examples/imports_function_env.rs | 4 +- examples/wasi.rs | 6 +- lib/api/Cargo.toml | 2 + lib/api/src/common/reactors.rs | 88 ++ lib/api/src/js/export.rs | 19 +- lib/api/src/js/exports.rs | 16 - lib/api/src/js/externals/function.rs | 7 +- lib/api/src/js/externals/memory.rs | 21 +- lib/api/src/js/externals/table.rs | 2 +- lib/api/src/js/function_env.rs | 37 +- lib/api/src/js/imports.rs | 41 +- lib/api/src/js/instance.rs | 19 +- lib/api/src/js/mod.rs | 11 + lib/api/src/js/module.rs | 63 +- lib/api/src/js/native.rs | 2 +- lib/api/src/js/store.rs | 67 +- lib/api/src/js/thread.rs | 44 + lib/api/src/js/wasm_bindgen_polyfill.rs | 2 + lib/api/src/lib.rs | 1 + lib/api/src/sys/exports.rs | 12 - lib/api/src/sys/externals/function.rs | 18 +- lib/api/src/sys/externals/memory.rs | 13 + lib/api/src/sys/function_env.rs | 25 +- lib/api/src/sys/imports.rs | 39 +- lib/api/src/sys/instance.rs | 17 +- lib/api/src/sys/mod.rs | 7 + lib/api/src/sys/ptr.rs | 18 +- lib/api/src/sys/store.rs | 63 +- 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.rs | 5 +- lib/cli/src/commands/run/wasi.rs | 13 +- .../src/translator/code_translator.rs | 31 +- lib/compiler/src/translator/environ.rs | 9 +- lib/derive/src/value_type.rs | 14 +- lib/emscripten/src/lib.rs | 19 +- 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 | 8 +- lib/vm/src/memory.rs | 91 +- lib/vm/src/store.rs | 1 + lib/vm/src/table.rs | 187 ++- lib/vm/src/vmcontext.rs | 3 +- lib/wasi-types/src/bus.rs | 35 +- lib/wasi-types/src/file.rs | 3 + lib/wasi/Cargo.toml | 8 +- lib/wasi/src/lib.rs | 850 ++++++------ lib/wasi/src/macros.rs | 39 +- lib/wasi/src/runtime.rs | 44 +- 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 | 1172 +++++++++++++++-- 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 +- 75 files changed, 2899 insertions(+), 3583 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..d3a7ad34041 100644 --- a/docs/migration_to_3.0.0.md +++ b/docs/migration_to_3.0.0.md @@ -83,14 +83,13 @@ import_object.define("env", "host_function", host_function); let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module."); ``` -For WASI, don't forget to import memory to `WasiEnv` +For WASI, don't forget to initialize it ```rust let mut wasi_env = WasiState::new("hello").finalize()?; let import_object = wasi_env.import_object(&mut store, &module)?; let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module."); -let memory = instance.exports.get_memory("memory")?; -wasi_env.data_mut(&mut store).set_memory(memory.clone()); +wasi_env.initialize(&mut store, &instance).unwrap(); ``` #### `ChainableNamedResolver` is removed 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/examples/wasi.rs b/examples/wasi.rs index 0c47100c386..0b05c39ddaa 100644 --- a/examples/wasi.rs +++ b/examples/wasi.rs @@ -15,7 +15,7 @@ //! //! Ready? -use wasmer::{FunctionEnv, Instance, Module, Store}; +use wasmer::{Instance, Module, Store}; use wasmer_compiler::Universal; use wasmer_compiler_cranelift::Cranelift; use wasmer_wasi::WasiState; @@ -52,9 +52,7 @@ fn main() -> Result<(), Box> { let instance = Instance::new(&mut store, &module, &import_object)?; println!("Attach WASI memory..."); - // Attach the memory export - let memory = instance.exports.get_memory("memory")?; - wasi_env.data_mut(&mut store).set_memory(memory.clone()); + wasi_env.initialize(&mut store, &instance).unwrap(); println!("Call WASI `_start` function..."); // And we just call the `_start` function! 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/export.rs b/lib/api/src/js/export.rs index f396e617c53..d94f0170185 100644 --- a/lib/api/src/js/export.rs +++ b/lib/api/src/js/export.rs @@ -7,19 +7,32 @@ use std::fmt; use wasm_bindgen::{JsCast, JsValue}; use wasmer_types::{ExternType, FunctionType, GlobalType, MemoryType, TableType}; +/// Reference to the memory of the web assembly instance hosted within the javascript runtime #[derive(Clone, Debug, PartialEq)] pub struct VMMemory { pub(crate) memory: Memory, pub(crate) ty: MemoryType, } -unsafe impl Send for VMMemory {} -unsafe impl Sync for VMMemory {} +/// This is most definately not safe to pass between threads! +//unsafe impl Send for VMMemory {} +//unsafe impl Sync for VMMemory {} impl VMMemory { - pub(crate) fn new(memory: Memory, ty: MemoryType) -> Self { + /// Creates the linear memory object from an existing javascript runtime and its memory type + pub fn new(memory: Memory, ty: MemoryType) -> Self { Self { memory, ty } } + + /// Returns the type of memory held here + pub fn ty(&self) -> MemoryType { + self.ty.clone() + } + + /// Returns the memory as a JsValue so that it can be passed to other threads + pub fn as_memory(&self) -> Memory { + self.memory.clone() + } } #[derive(Clone, Debug, PartialEq)] diff --git a/lib/api/src/js/exports.rs b/lib/api/src/js/exports.rs index 6c4a8a9deb5..a8e273d5817 100644 --- a/lib/api/src/js/exports.rs +++ b/lib/api/src/js/exports.rs @@ -183,22 +183,6 @@ impl Exports { } } - /// Like `get_with_generics` but with a WeakReference to the `InstanceRef` internally. - /// This is useful for passing data into Context data, for example. - pub fn get_with_generics_weak<'a, T, Args, Rets>( - &'a self, - store: &impl AsStoreRef, - name: &str, - ) -> Result - where - Args: WasmTypeList, - Rets: WasmTypeList, - T: ExportableWithGenerics<'a, Args, Rets>, - { - let out: T = self.get_with_generics(store, name)?; - Ok(out) - } - /// Get an export as an `Extern`. pub fn get_extern(&self, name: &str) -> Option<&Extern> { self.map.get(name) diff --git a/lib/api/src/js/externals/function.rs b/lib/api/src/js/externals/function.rs index f5ee117cef9..26740a2d60a 100644 --- a/lib/api/src/js/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -115,7 +115,7 @@ impl Function { let wrapped_func: JsValue = match function_type.results().len() { 0 => Closure::wrap(Box::new(move |args: &Array| { let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) }; - let mut env: FunctionEnvMut = raw_env.clone().into_mut(&mut store); + let env: FunctionEnvMut = raw_env.clone().into_mut(&mut store); let wasm_arguments = function_type .params() .iter() @@ -129,7 +129,7 @@ impl Function { .into_js_value(), 1 => Closure::wrap(Box::new(move |args: &Array| { let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) }; - let mut env: FunctionEnvMut = raw_env.clone().into_mut(&mut store); + let env: FunctionEnvMut = raw_env.clone().into_mut(&mut store); let wasm_arguments = function_type .params() .iter() @@ -143,7 +143,7 @@ impl Function { .into_js_value(), _n => Closure::wrap(Box::new(move |args: &Array| { let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) }; - let mut env: FunctionEnvMut = raw_env.clone().into_mut(&mut store); + let env: FunctionEnvMut = raw_env.clone().into_mut(&mut store); let wasm_arguments = function_type .params() .iter() @@ -509,6 +509,7 @@ mod inner { use super::RuntimeError; use super::VMFunctionBody; use crate::js::function_env::{FunctionEnvMut, VMFunctionEnvironment}; + #[allow(unused_imports)] use crate::js::store::{AsStoreMut, InternalStoreHandle, StoreHandle, StoreInner, StoreMut}; use crate::js::FunctionEnv; use crate::js::NativeWasmTypeInto; diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index 9103eeb1814..14b7210f188 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -58,6 +58,7 @@ extern "C" { /// memory. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/grow) + #[allow(unused_doc_comments)] #[wasm_bindgen(catch, method, js_namespace = WebAssembly)] pub fn grow(this: &JSMemory, pages: u32) -> Result; } @@ -115,6 +116,17 @@ impl Memory { Ok(Self::from_vm_export(store, vm_memory)) } + /// Creates a new host `Memory` from provided JavaScript memory. + pub fn new_raw(store: &mut impl AsStoreMut, js_memory: js_sys::WebAssembly::Memory, ty: MemoryType) -> Result { + let vm_memory = VMMemory::new(js_memory, ty); + Ok(Self::from_vm_export(store, vm_memory)) + } + + /// Create a memory object from an existing memory and attaches it to the store + pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { + Self::from_vm_export(new_store, memory) + } + /// Returns the [`MemoryType`] of the `Memory`. /// /// # Example @@ -265,8 +277,7 @@ impl Memory { store: &mut impl AsStoreMut, internal: InternalStoreHandle, ) -> Self { - let view = - js_sys::Uint8Array::new(&internal.get(store.as_store_ref().objects()).memory.buffer()); + let view = js_sys::Uint8Array::new(&internal.get(store.as_store_ref().objects()).memory.buffer()); Self { handle: unsafe { StoreHandle::from_internal(store.as_store_ref().objects().id(), internal) @@ -371,6 +382,12 @@ impl Memory { pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { self.handle.store_id() == store.as_store_ref().objects().id() } + + /// Convert this external to a cloned copy of the memory + pub fn to_vm_memory(&self, store: &impl AsStoreRef) -> VMMemory { + let mem = self.handle.get(store.as_store_ref().objects()); + mem.clone() + } } impl<'a> Exportable<'a> for Memory { diff --git a/lib/api/src/js/externals/table.rs b/lib/api/src/js/externals/table.rs index ec7565a8c5c..f9b3fdcb88d 100644 --- a/lib/api/src/js/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -128,7 +128,7 @@ impl Table { /// Returns an error if the `delta` is out of bounds for the table. pub fn grow( &self, - store: &mut AsStoreMut, + _store: &mut dyn AsStoreMut, _delta: u32, _init: Value, ) -> Result { diff --git a/lib/api/src/js/function_env.rs b/lib/api/src/js/function_env.rs index 81ef590a7c2..8293dce84cc 100644 --- a/lib/api/src/js/function_env.rs +++ b/lib/api/src/js/function_env.rs @@ -1,9 +1,11 @@ use std::{any::Any, marker::PhantomData}; +use std::sync::Arc; -use crate::js::{StoreHandle, StoreObjects}; - +use crate::js::{StoreHandle, StoreObjects}; use crate::js::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; +use super::store::PackagedStore; + #[derive(Debug)] #[repr(transparent)] /// An opaque reference to a function environment. @@ -36,7 +38,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, { @@ -47,16 +49,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` @@ -93,7 +97,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) } @@ -104,6 +110,11 @@ impl FunctionEnvMut<'_, T> { func_env: self.func_env.clone(), } } + + /// Packages up an empty store that can be passed to another thread + pub fn package_store(&self) -> PackagedStore { + self.store_mut.package() + } } impl AsStoreRef for FunctionEnvMut<'_, T> { @@ -128,14 +139,14 @@ impl AsStoreMut for FunctionEnvMut<'_, T> { /// Underlying FunctionEnvironment used by a `VMFunction`. 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), } } @@ -146,8 +157,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/api/src/js/imports.rs b/lib/api/src/js/imports.rs index 94866e66842..b5205b758c8 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -5,10 +5,12 @@ use crate::js::error::InstantiationError; use crate::js::exports::Exports; use crate::js::module::Module; use crate::js::store::AsStoreRef; +use crate::js::store::AsStoreMut; 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 +132,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 +145,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 +183,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..7f55a631931 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -20,8 +20,6 @@ use std::fmt; pub struct Instance { _handle: StoreHandle, module: Module, - #[allow(dead_code)] - imports: Imports, /// The exports for an instance. pub exports: Exports, } @@ -65,12 +63,11 @@ impl Instance { module: &Module, imports: &Imports, ) -> Result { - let import_copy = imports.clone(); - let (instance, _imports): (StoreHandle, Vec) = module + let (instance, externs): (StoreHandle, Vec) = module .instantiate(&mut store, imports) .map_err(|e| InstantiationError::Start(e))?; - let self_instance = Self::from_module_and_instance(store, module, instance, import_copy)?; + let self_instance = Self::from_module_and_instance(store, module, externs, instance)?; //self_instance.init_envs(&imports.iter().map(Extern::to_export).collect::>())?; Ok(self_instance) } @@ -87,11 +84,11 @@ impl Instance { pub fn from_module_and_instance( mut store: &mut impl AsStoreMut, module: &Module, + externs: Vec, instance: StoreHandle, - imports: Imports, ) -> Result { let instance_exports = instance.get(store.as_store_ref().objects()).exports(); - let exports = module + let mut exports = module .exports() .map(|export_type| { let name = export_type.name(); @@ -110,10 +107,16 @@ impl Instance { }) .collect::>()?; + // If the memory is imported then also export it so that others can access it + if exports.get_memory("memory").is_err() { + if let Some(memory) = externs.iter().filter(|a| a.ty(store).memory().is_some()).next() { + exports.insert("memory", memory.clone()); + } + } + Ok(Self { _handle: instance, module: module.clone(), - imports, exports, }) } diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 9863123c55b..04336c735db 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, @@ -73,6 +78,12 @@ pub use crate::js::types::{ pub use crate::js::value::Value; pub use crate::js::value::Value as Val; +pub mod vm { + //! The (fake) `vm` module re-exports wasmer-vm types. + //! + pub use crate::js::export::VMMemory; +} + pub use wasmer_types::is_wasm; pub use wasmer_types::{ Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, Pages, ValueType, WASM_MAX_PAGES, diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 209f46dfd46..d1c9e16de2c 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -5,6 +5,7 @@ use crate::js::error::{CompileError, InstantiationError}; use crate::js::error::{DeserializeError, SerializeError}; use crate::js::externals::Extern; use crate::js::imports::Imports; +#[allow(unused_imports)] use crate::js::store::Store; use crate::js::store::{AsStoreMut, StoreHandle}; use crate::js::types::{AsJs, ExportType, ImportType}; @@ -21,6 +22,7 @@ use wasmer_types::{ ExportsIterator, ExternType, FunctionType, GlobalType, ImportsIterator, MemoryType, Mutability, Pages, TableType, Type, }; +use tracing::{debug, warn}; #[derive(Debug)] #[cfg_attr(feature = "std", derive(Error))] @@ -237,6 +239,18 @@ impl Module { let mut import_externs: Vec = vec![]; for import_type in self.imports() { let resolved_import = imports.get_export(import_type.module(), import_type.name()); + if let wasmer_types::ExternType::Memory(mem_ty) = import_type.ty() { + if resolved_import.is_some() { + debug!("imported shared memory {:?}", &mem_ty); + } else { + warn!( + "Error while importing {0:?}.{1:?}: memory. Expected {2:?}", + import_type.module(), + import_type.name(), + import_type.ty(), + ); + } + } if let Some(import) = resolved_import { let val = js_sys::Reflect::get(&imports_object, &import_type.module().into())?; if !val.is_undefined() { @@ -261,6 +275,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 @@ -384,7 +400,8 @@ impl Module { let imports = WebAssembly::Module::imports(&self.module); let iter = imports .iter() - .map(move |val| { + .enumerate() + .map(move |(i, val)| { let module = Reflect::get(val.as_ref(), &"module".into()) .unwrap() .as_string() @@ -397,24 +414,34 @@ impl Module { .unwrap() .as_string() .unwrap(); - let extern_type = match kind.as_str() { - "function" => { - let func_type = FunctionType::new(vec![], vec![]); - ExternType::Function(func_type) - } - "global" => { - let global_type = GlobalType::new(Type::I32, Mutability::Const); - ExternType::Global(global_type) - } - "memory" => { - let memory_type = MemoryType::new(Pages(1), None, false); - ExternType::Memory(memory_type) - } - "table" => { - let table_type = TableType::new(Type::FuncRef, 1, None); - ExternType::Table(table_type) + let type_hint = self + .type_hints + .as_ref() + .map(|hints| hints.imports.get(i).unwrap().clone()); + let extern_type = if let Some(hint) = type_hint { + hint + } else { + match kind.as_str() { + "function" => { + let func_type = FunctionType::new(vec![], vec![]); + ExternType::Function(func_type) + } + "global" => { + let global_type = GlobalType::new(Type::I32, Mutability::Const); + ExternType::Global(global_type) + } + "memory" => { + // The javascript API does not yet expose these properties so without + // the type_hints we don't know what memory to import. + let memory_type = MemoryType::new(Pages(1), None, false); + ExternType::Memory(memory_type) + } + "table" => { + let table_type = TableType::new(Type::FuncRef, 1, None); + ExternType::Table(table_type) + } + _ => unimplemented!(), } - _ => unimplemented!(), }; ImportType::new(&module, &field, extern_type) }) diff --git a/lib/api/src/js/native.rs b/lib/api/src/js/native.rs index 6d34ca82425..d2056323d03 100644 --- a/lib/api/src/js/native.rs +++ b/lib/api/src/js/native.rs @@ -39,7 +39,7 @@ where #[allow(dead_code)] pub(crate) fn new( store: &mut impl AsStoreMut, - env: &FunctionEnv, + _env: &FunctionEnv, vm_function: VMFunction, ) -> Self { Self { diff --git a/lib/api/src/js/store.rs b/lib/api/src/js/store.rs index 59bc2577fd5..058bbcc7207 100644 --- a/lib/api/src/js/store.rs +++ b/lib/api/src/js/store.rs @@ -37,6 +37,41 @@ impl Store { pub fn same(_a: &Self, _b: &Self) -> bool { true } + + /// Packages an empty copy of store so that it can be passed to other threads + pub fn package(&self) -> PackagedStore + { + self.inner.package() + } +} + +impl StoreInner +{ + /// Packages an empty copy of store so that it can be passed to other threads + pub fn package(&self) -> PackagedStore + { + PackagedStore + { + } + } +} + +/// Represents a packaged store that can be passed around and then created locally +pub struct PackagedStore +{ +} + +impl PackagedStore +{ + /// Creates a store in from an earlier packaged store + pub fn unpack(self) -> Store + { + Store { + inner: Box::new(StoreInner { + objects: StoreObjects::default(), + }) + } + } } impl PartialEq for Store { @@ -124,6 +159,11 @@ impl<'a> StoreMut<'a> { pub(crate) unsafe fn from_raw(raw: *mut StoreInner) -> Self { Self { inner: &mut *raw } } + + /// Packages the store so that it can be passed to another thread and unpackaged + pub fn package(&self) -> PackagedStore { + self.inner.package() + } } /// Helper trait for a value that is convertible to a [`StoreRef`]. @@ -182,6 +222,7 @@ impl AsStoreMut for &'_ mut T { pub use objects::*; +#[allow(unused_imports)] use crate::js::FunctionEnv; mod objects { use crate::js::{ @@ -223,19 +264,19 @@ mod objects { } macro_rules! impl_store_object { - ($($field:ident => $ty:ty,)*) => { - $( - impl StoreObject for $ty { - fn list(store: &StoreObjects) -> &Vec { - &store.$field - } - fn list_mut(store: &mut StoreObjects) -> &mut Vec { - &mut store.$field + ($($field:ident => $ty:ty,)*) => { + $( + impl StoreObject for $ty { + fn list(store: &StoreObjects) -> &Vec { + &store.$field + } + fn list_mut(store: &mut StoreObjects) -> &mut Vec { + &mut store.$field + } } - } - )* - }; -} + )* + }; + } impl_store_object! { functions => VMFunction, @@ -425,6 +466,7 @@ mod objects { /// Data used by the generated code is generally located inline within the /// `VMContext` for items defined in an instance. Host-defined objects are /// allocated separately and owned directly by the context. + #[allow(dead_code)] pub enum MaybeInstanceOwned { /// The data is owned here. Host(Box>), @@ -433,6 +475,7 @@ mod objects { Instance(NonNull), } + #[allow(dead_code)] impl MaybeInstanceOwned { /// Returns underlying pointer to the VM data. pub fn as_ptr(&self) -> NonNull { 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/js/wasm_bindgen_polyfill.rs b/lib/api/src/js/wasm_bindgen_polyfill.rs index 1b5dad63a12..80f89a6a702 100644 --- a/lib/api/src/js/wasm_bindgen_polyfill.rs +++ b/lib/api/src/js/wasm_bindgen_polyfill.rs @@ -16,6 +16,7 @@ extern "C" { /// of the given type and value. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Global) + #[allow(unused_doc_comments)] #[wasm_bindgen(constructor, js_namespace = WebAssembly, catch)] pub fn new(global_descriptor: &Object, value: &JsValue) -> Result; @@ -23,6 +24,7 @@ extern "C" { /// returns the value of the global. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Global) + #[allow(unused_doc_comments)] #[wasm_bindgen(method, getter, structural, js_namespace = WebAssembly)] pub fn value(this: &Global) -> JsValue; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 6a4686033ff..a728ce059bd 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -25,6 +25,7 @@ clippy::use_self ) )] +#![allow(deprecated_cfg_attr_crate_type_name)] #![cfg_attr(feature = "js", crate_type = "cdylib")] //! [`Wasmer`](https://wasmer.io/) is the most popular diff --git a/lib/api/src/sys/exports.rs b/lib/api/src/sys/exports.rs index 11536b9945a..d20541b419a 100644 --- a/lib/api/src/sys/exports.rs +++ b/lib/api/src/sys/exports.rs @@ -183,18 +183,6 @@ impl Exports { } } - /// Like `get_with_generics` but with a WeakReference to the `InstanceRef` internally. - /// This is useful for passing data into Context data, for example. - pub fn get_with_generics_weak<'a, T, Args, Rets>(&'a self, name: &str) -> Result - where - Args: WasmTypeList, - Rets: WasmTypeList, - T: ExportableWithGenerics<'a, Args, Rets>, - { - let out: T = self.get_with_generics(name)?; - Ok(out) - } - /// Get an export as an `Extern`. pub fn get_extern(&self, name: &str) -> Option<&Extern> { self.map.get(name) 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..675f5d12f1a 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -55,6 +55,13 @@ impl Memory { }) } + /// Create a memory object from an existing memory and attaches it to the store + pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { + Self { + handle: StoreHandle::new(new_store.objects_mut(), memory) + } + } + /// Returns the [`MemoryType`] of the `Memory`. /// /// # Example @@ -249,6 +256,12 @@ impl Memory { self.handle.store_id() == store.as_store_ref().objects().id() } + /// Convert this external to a cloned copy of the memory + pub fn to_vm_memory(&self, store: &impl AsStoreRef) -> VMMemory { + let mem = self.handle.get(store.as_store_ref().objects()); + mem.clone() + } + pub(crate) fn to_vm_extern(&self) -> VMExtern { VMExtern::Memory(self.handle.internal_handle()) } diff --git a/lib/api/src/sys/function_env.rs b/lib/api/src/sys/function_env.rs index 0dde57ea78c..13a65d6fbc9 100644 --- a/lib/api/src/sys/function_env.rs +++ b/lib/api/src/sys/function_env.rs @@ -4,6 +4,8 @@ use wasmer_vm::{StoreHandle, StoreObjects, VMFunctionEnvironment}; use crate::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; +use super::store::PackagedStore; + #[derive(Debug)] #[repr(transparent)] /// An opaque reference to a function environment. @@ -29,7 +31,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 +42,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 +89,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 +103,11 @@ impl FunctionEnvMut<'_, T> { func_env: self.func_env.clone(), } } + + /// Packages up an empty store that can be passed to another thread + pub fn package_store(&self) -> PackagedStore { + self.store_mut.package() + } } impl AsStoreRef for FunctionEnvMut<'_, T> { diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index 98fdc848c5b..02256d1f62e 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -6,6 +6,7 @@ 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,10 @@ 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, + module: &Module + ) -> Result, LinkError> { let mut ret = vec![]; for import in module.imports() { if let Some(imp) = self @@ -141,6 +145,9 @@ impl Imports { { ret.push(imp.clone()); } 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 +157,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..59968d6d168 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -114,11 +114,11 @@ impl Instance { module: &Module, imports: &Imports, ) -> Result { - let imports = imports + let externs = imports .imports_for_module(module) .map_err(InstantiationError::Link)?; - let mut handle = module.instantiate(store, &imports)?; - let exports = module + let mut handle = module.instantiate(store, &externs)?; + let mut exports = module .exports() .map(|export| { let name = export.name().to_string(); @@ -128,6 +128,13 @@ impl Instance { }) .collect::(); + // If the memory is imported then also export it so that others can access it + if exports.get_memory("memory").is_err() { + if let Some(memory) = externs.iter().filter(|a| a.ty(store).memory().is_some()).next() { + exports.insert("memory", memory.clone()); + } + } + let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), module: module.clone(), @@ -152,8 +159,8 @@ impl Instance { module: &Module, externs: &[Extern], ) -> Result { - let imports = externs.to_vec(); - let mut handle = module.instantiate(store, &imports)?; + let externs = externs.to_vec(); + let mut handle = module.instantiate(store, &externs)?; let exports = module .exports() .map(|export| { diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 9eca8454d15..454d6e8d764 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -12,6 +12,11 @@ mod ptr; mod store; mod tunables; mod value; +mod thread; +#[path = "../common/reactors.rs"] +mod reactors; +#[path = "../common/metadata.rs"] +mod metadata; pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use crate::sys::extern_ref::ExternRef; @@ -26,6 +31,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..2ce05095958 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}; @@ -13,8 +14,8 @@ use wasmer_vm::StoreObjects; 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>>, } /// The store represents all global state that can be manipulated by @@ -43,11 +44,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,11 +66,55 @@ impl Store { inner: Box::new(StoreInner { objects: Default::default(), engine: engine.cloned(), - tunables: Box::new(tunables), + tunables: Arc::new(tunables), trap_handler: None, }), } } + + /// Packages an empty copy of store so that it can be passed to other threads + pub fn package(&self) -> PackagedStore + { + self.inner.package() + } +} + +impl StoreInner +{ + /// Packages an empty copy of store so that it can be passed to other threads + pub fn package(&self) -> PackagedStore + { + PackagedStore + { + engine: self.engine.clone(), + tunables: self.tunables.clone(), + trap_handler: self.trap_handler.clone() + } + } +} + +/// Represents a packaged store that can be passed around and then created locally +pub struct PackagedStore +{ + engine: Arc, + tunables: Arc, + trap_handler: Option>>, +} + +impl PackagedStore +{ + /// Creates a store in from an earlier packaged store + pub fn unpack(self) -> Store + { + Store { + inner: Box::new(StoreInner { + objects: StoreObjects::default(), + engine: self.engine, + tunables: self.tunables, + trap_handler: self.trap_handler + }) + } + } } // impl PartialEq for Store { @@ -178,7 +224,7 @@ impl<'a> StoreRef<'a> { self.inner .trap_handler .as_ref() - .map(|handler| &*handler as *const _) + .map(|handler| handler.deref() as *const _) } } @@ -216,6 +262,11 @@ impl<'a> StoreMut<'a> { pub(crate) unsafe fn from_raw(raw: *mut StoreInner) -> Self { Self { inner: &mut *raw } } + + /// Packages the store so that it can be passed to another thread and unpackaged + pub fn package(&self) -> PackagedStore { + self.inner.package() + } } /// Helper trait for a value that is convertible to a [`StoreRef`]. 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.rs b/lib/cli/src/commands/run.rs index d6f4de250a0..18f668299ca 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -139,10 +139,10 @@ impl Run { // TODO: refactor this if is_emscripten_module(&module) { // create an EmEnv with default global - let env = FunctionEnv::new(&mut store, EmEnv::new()); + let mut env = FunctionEnv::new(&mut store, EmEnv::new()); let mut emscripten_globals = EmscriptenGlobals::new(&mut store, &env, &module) .map_err(|e| anyhow!("{}", e))?; - env.as_mut(&mut store) + env.as_mut(&mut store).unwrap() .set_data(&emscripten_globals.data, Default::default()); let import_object = generate_emscripten_env(&mut store, &env, &mut emscripten_globals); @@ -257,6 +257,7 @@ impl Run { compiler_type.to_string() ) })?; + // We set the name outside the cache, to make sure we dont cache the name module.set_name(&self.path.file_name().unwrap_or_default().to_string_lossy()); diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 3a0121a2069..c19df04adb2 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -4,7 +4,7 @@ use std::collections::BTreeSet; use std::path::PathBuf; use wasmer::{AsStoreMut, FunctionEnv, Instance, Module, RuntimeError, Value}; use wasmer_wasi::{ - get_wasi_versions, import_object_for_all_wasi_versions, is_wasix_module, WasiEnv, WasiError, + get_wasi_versions, import_object_for_all_wasi_versions, WasiEnv, WasiError, WasiState, WasiVersion, }; @@ -78,7 +78,7 @@ impl Wasi { /// Helper function for instantiating a module with Wasi imports for the `Run` command. pub fn instantiate( &self, - store: &mut impl AsStoreMut, + mut store: &mut impl AsStoreMut, module: &Module, program_name: String, args: Vec, @@ -100,15 +100,10 @@ impl Wasi { } } - let wasi_env = wasi_state_builder.finalize(store)?; - wasi_env.env.as_mut(store).state.fs.is_wasix.store( - is_wasix_module(module), - std::sync::atomic::Ordering::Release, - ); + let mut wasi_env = wasi_state_builder.finalize(store)?; let import_object = import_object_for_all_wasi_versions(store, &wasi_env.env); let instance = Instance::new(store, module, &import_object)?; - let memory = instance.exports.get_memory("memory")?; - wasi_env.data_mut(store).set_memory(memory.clone()); + wasi_env.initialize(&mut store, &instance)?; Ok((wasi_env.env, instance)) } 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/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..845afc4e46b 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 = ctx.data_mut().unwrap(); 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,12 +865,12 @@ 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 dynamictop_ptr = WasmPtr::::new(globals.dynamictop_ptr).deref(store, memory); let dynamic_base = globals.dynamic_base; 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..6701a25ad2f 100644 --- a/lib/vm/src/instance/mod.rs +++ b/lib/vm/src/instance/mod.rs @@ -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, @@ -999,16 +999,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 { diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index 098dd8501b6..2f22f6ecd14 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -11,6 +11,7 @@ use more_asserts::assert_ge; use std::cell::UnsafeCell; use std::convert::TryInto; use std::ptr::NonNull; +use std::sync::{RwLock, Arc}; use thiserror::Error; use wasmer_types::{Bytes, MemoryStyle, MemoryType, Pages}; @@ -56,10 +57,28 @@ pub enum MemoryError { Generic(String), } +/// Protected area of the memory map +#[derive(Debug)] +struct VMMemoryMmap { + // The underlying allocation. + mmap: WasmMmap, + + /// The owned memory definition used by the generated code + vm_memory_definition: MaybeInstanceOwned, +} + +// VMMemoryMmap is protected by a RwLock and Arc referencing counting +// however if the user supplies their own direct memory references then +// they need to wait for all threads to exit before they free the memory +// or else it with sigfault. +unsafe impl Send for VMMemoryMmap { } +unsafe impl Sync for VMMemoryMmap { } + /// A linear memory instance. +#[derive(Debug, Clone)] pub struct VMMemory { // The underlying allocation. - mmap: WasmMmap, + mmap: Arc>, // The optional maximum size in wasm pages of this linear memory. maximum: Option, @@ -73,9 +92,6 @@ 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)] @@ -163,23 +179,27 @@ impl VMMemory { let base_ptr = mmap.alloc.as_mut_ptr(); let mem_length = memory.minimum.bytes().0; Ok(Self { - mmap, + mmap: Arc::new(RwLock::new( + VMMemoryMmap { + mmap, + vm_memory_definition: if let Some(mem_loc) = vm_memory_location { + { + let mut ptr = mem_loc; + let md = ptr.as_mut(); + md.base = base_ptr; + md.current_length = mem_length; + } + MaybeInstanceOwned::Instance(mem_loc) + } else { + MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition { + base: base_ptr, + current_length: mem_length, + }))) + }, + } + )), maximum: memory.maximum, offset_guard_size: offset_guard_bytes, - vm_memory_definition: if let Some(mem_loc) = vm_memory_location { - { - let mut ptr = mem_loc; - let md = ptr.as_mut(); - md.base = base_ptr; - md.current_length = mem_length; - } - MaybeInstanceOwned::Instance(mem_loc) - } else { - MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition { - base: base_ptr, - current_length: mem_length, - }))) - }, memory: *memory, style: style.clone(), }) @@ -187,7 +207,8 @@ impl VMMemory { /// Get the `VMMemoryDefinition`. fn get_vm_memory_definition(&self) -> NonNull { - self.vm_memory_definition.as_ptr() + let guard = self.mmap.read().unwrap(); + guard.vm_memory_definition.as_ptr() } /// Returns the type for this memory. @@ -219,25 +240,27 @@ 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 { + let mut guard = self.mmap.write().unwrap(); + // Optimization of memory.grow 0 calls. if delta.0 == 0 { - return Ok(self.mmap.size); + return Ok(guard.mmap.size); } - let new_pages = self + let new_pages = guard .mmap .size .checked_add(delta) .ok_or(MemoryError::CouldNotGrow { - current: self.mmap.size, + current: guard.mmap.size, attempted_delta: delta, })?; - let prev_pages = self.mmap.size; + let prev_pages = guard.mmap.size; if let Some(maximum) = self.maximum { if new_pages > maximum { return Err(MemoryError::CouldNotGrow { - current: self.mmap.size, + current: guard.mmap.size, attempted_delta: delta, }); } @@ -249,7 +272,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: guard.mmap.size, attempted_delta: delta, }); } @@ -258,7 +281,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 > guard.mmap.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,27 +296,27 @@ 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 = guard.mmap.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(&guard.mmap.alloc.as_slice()[..copy_len]); - self.mmap.alloc = new_mmap; + guard.mmap.alloc = new_mmap; } else if delta_bytes > 0 { // Make the newly allocated pages accessible. - self.mmap + guard.mmap .alloc .make_accessible(prev_bytes, delta_bytes) .map_err(MemoryError::Region)?; } - self.mmap.size = new_pages; + guard.mmap.size = new_pages; // update memory definition unsafe { - let mut md_ptr = self.get_vm_memory_definition(); + let mut md_ptr = guard.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 = guard.mmap.alloc.as_mut_ptr() as _; } Ok(prev_pages) diff --git a/lib/vm/src/store.rs b/lib/vm/src/store.rs index 747154f9d50..9286702dd65 100644 --- a/lib/vm/src/store.rs +++ b/lib/vm/src/store.rs @@ -242,6 +242,7 @@ impl InternalStoreHandle { /// Data used by the generated code is generally located inline within the /// `VMContext` for items defined in an instance. Host-defined objects are /// allocated separately and owned directly by the context. +#[derive(Debug)] pub enum MaybeInstanceOwned { /// The data is owned here. Host(Box>), diff --git a/lib/vm/src/table.rs b/lib/vm/src/table.rs index bdc5e5fdbaa..115bb00bb7e 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,9 @@ impl Default for TableElement { } } -/// A table instance. -pub struct VMTable { +/// Protected area of the VMTable +pub struct VMTableProtected +{ vec: Vec, maximum: Option, /// The WebAssembly table description. @@ -79,6 +81,31 @@ pub struct VMTable { vm_table_definition: MaybeInstanceOwned, } +impl VMTableProtected +{ + /// Get the `VMTableDefinition`. + fn get_vm_table_definition(&self) -> NonNull { + self.vm_table_definition.as_ptr() + } + + /// Returns the number of allocated elements. + pub fn size(&self) -> u32 { + unsafe { + let td_ptr = self.get_vm_table_definition(); + let td = td_ptr.as_ref(); + td.current_elements + } + } +} + +/// A table instance. +#[derive(Clone)] +pub struct VMTable +{ + /// Protected area of the VM table + protected: Arc, +} + impl VMTable { /// Create a new linear table instance with specified minimum and maximum number of elements. /// @@ -130,8 +157,8 @@ impl VMTable { .map_err(|_| "Table minimum is bigger than usize".to_string())?; let mut vec = vec![RawTableElement::default(); table_minimum]; let base = vec.as_mut_ptr(); - match style { - TableStyle::CallerChecksSignature => Ok(Self { + let protected = match style { + TableStyle::CallerChecksSignature => VMTableProtected { vec, maximum: table.maximum, table: *table, @@ -150,33 +177,66 @@ impl VMTable { current_elements: table_minimum as _, }))) }, - }), - } + }, + }; + + Ok(VMTable { + protected: Arc::new(protected) + }) } - /// Get the `VMTableDefinition`. - fn get_vm_table_definition(&self) -> NonNull { - self.vm_table_definition.as_ptr() + /// Accesses this table + pub fn protected(&self) -> &VMTableProtected { + self.protected.as_ref() + } + + /// Access this table for mutability, if its been cloned then + /// we make a copy of the table first + pub fn try_protected_mut(&mut self) -> Option<&mut VMTableProtected> + { + Arc::get_mut(&mut self.protected) + } + + /// Access this table for mutability, if its been cloned then + /// we make a copy of the table first + pub fn mutate(&mut self, work: impl FnOnce(&mut VMTableProtected) -> T) -> T + { + loop { + if let Some(a) = self.try_protected_mut() { + return work(a); + } + + let mut vec = self.protected.vec.clone(); + let base = vec.as_mut_ptr(); + let protected = Arc::new(VMTableProtected { + vec, + maximum: self.protected.maximum.clone(), + table: self.protected.table.clone(), + style: self.protected.style.clone(), + vm_table_definition: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMTableDefinition { + base: base as _, + current_elements: unsafe { + self.protected.get_vm_table_definition().as_ref().current_elements + }, + }))) + }); + drop(std::mem::replace(&mut self.protected, protected)); + } } /// Returns the type for this Table. pub fn ty(&self) -> &TableType { - &self.table + &self.protected().table } /// Returns the style for this Table. pub fn style(&self) -> &TableStyle { - &self.style + &self.protected().style } /// Returns the number of allocated elements. pub fn size(&self) -> u32 { - // TODO: investigate this function for race conditions - unsafe { - let td_ptr = self.get_vm_table_definition(); - let td = td_ptr.as_ref(); - td.current_elements - } + self.protected().size() } /// Grow table by the specified amount of elements. @@ -184,35 +244,38 @@ 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 { - let size = self.size(); - let new_len = size.checked_add(delta)?; - if self.maximum.map_or(false, |max| new_len > max) { - return None; - } - if new_len == size { - debug_assert_eq!(delta, 0); - return Some(size); - } + self.mutate(|lock| { + let size = lock.size(); + let new_len = size.checked_add(delta)?; + if lock.maximum.map_or(false, |max| new_len > max) { + return None; + } + if new_len == size { + debug_assert_eq!(delta, 0); + return Some(size); + } - self.vec - .resize(usize::try_from(new_len).unwrap(), init_value.into()); + lock.vec + .resize(usize::try_from(new_len).unwrap(), init_value.into()); - // update table definition - unsafe { - let mut td_ptr = self.get_vm_table_definition(); - let td = td_ptr.as_mut(); - td.current_elements = new_len; - td.base = self.vec.as_mut_ptr() as _; - } - Some(size) + // update table definition + unsafe { + let mut td_ptr = lock.get_vm_table_definition(); + let td = td_ptr.as_mut(); + td.current_elements = new_len; + td.base = lock.vec.as_mut_ptr() as _; + } + Some(size) + }) } /// Get reference to the specified element. /// /// Returns `None` if the index is out of bounds. pub fn get(&self, index: u32) -> Option { - let raw_data = self.vec.get(index as usize).cloned()?; - Some(match self.table.ty { + let lock = self.protected(); + let raw_data = lock.vec.get(index as usize).cloned()?; + Some(match lock.table.ty { ValType::ExternRef => TableElement::ExternRef(unsafe { raw_data.extern_ref }), ValType::FuncRef => TableElement::FuncRef(unsafe { raw_data.func_ref }), _ => todo!("getting invalid type from table, handle this error"), @@ -225,34 +288,36 @@ impl VMTable { /// /// Returns an error if the index is out of bounds. pub 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) { - (ValType::ExternRef, r @ TableElement::ExternRef(_)) => { - *slot = r.into(); - } - (ValType::FuncRef, r @ TableElement::FuncRef(_)) => { - *slot = r.into(); - } - // This path should never be hit by the generated code due to Wasm - // validation. - (ty, v) => { - panic!( - "Attempted to set a table of type {} with the value {:?}", - ty, v - ) - } - }; - - Ok(()) + self.mutate(|lock| { + match lock.vec.get_mut(index as usize) { + Some(slot) => { + match (lock.table.ty, reference) { + (ValType::ExternRef, r @ TableElement::ExternRef(_)) => { + *slot = r.into(); + } + (ValType::FuncRef, r @ TableElement::FuncRef(_)) => { + *slot = r.into(); + } + // This path should never be hit by the generated code due to Wasm + // validation. + (ty, v) => { + panic!( + "Attempted to set a table of type {} with the value {:?}", + ty, v + ) + } + }; + + Ok(()) + } + None => Err(Trap::lib(TrapCode::TableAccessOutOfBounds)), } - None => Err(Trap::lib(TrapCode::TableAccessOutOfBounds)), - } + }) } /// Return a `VMTableDefinition` for exposing the table to compiled wasm code. pub fn vmtable(&self) -> NonNull { - self.get_vm_table_definition() + self.protected().get_vm_table_definition() } /// Copy `len` elements from `src_table[src_index..]` into `dst_table[dst_index..]`. diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index edc3bf4d40e..681f7d9742d 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -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 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..ad9e9cd440a 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,15 +50,17 @@ 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", "sys-thread", "host-vnet", "host-threads" ] sys-poll = [] +sys-thread = [] js = ["wasmer/js", "mem-fs", "wasmer-vfs/no-time", "getrandom/js", "chrono"] 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..5fbca70b57b 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,8 @@ pub use crate::syscalls::types; pub use crate::utils::{ get_wasi_version, get_wasi_versions, is_wasi_module, is_wasix_module, WasiVersion, }; +use bytes::Bytes; +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 +59,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, + 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 +84,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 +118,71 @@ 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, + /// Compiled bytes for the module so it can be recreated + module_bytes: Bytes, + /// 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 +196,31 @@ impl WasiEnv { /// Returns the current thread ID pub fn current_thread_id(&self) -> WasiThreadId { - self.id + THREAD_ID.with(|f| { + let thread_id = f.borrow(); + *thread_id + }).into() } - /// 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 - } - - /// 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 +243,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 +303,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 memory = instance.exports.get_memory("memory")?.clone(); + let new_inner = WasiEnvInner { + reactors: Default::default(), + module_bytes: Bytes::from(instance.module().serialize().unwrap()), + memory, + 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); + + env.state.fs.is_wasix.store( + is_wasix_module(instance.module()), + std::sync::atomic::Ordering::Release, + ); + + 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); + } + } + + 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 +409,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 +464,7 @@ 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::), @@ -495,15 +514,270 @@ fn wasi_snapshot_preview1_exports( }; 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::), + "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 +} + +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 +786,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 +796,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..b31873ee067 100644 --- a/lib/wasi/src/runtime.rs +++ b/lib/wasi/src/runtime.rs @@ -2,6 +2,8 @@ use std::fmt; use std::ops::Deref; use std::sync::atomic::{AtomicU32, Ordering}; use thiserror::Error; +use wasmer::{Module, Store}; +use wasmer::vm::VMMemory; use wasmer_vbus::{UnsupportedVirtualBus, VirtualBus}; use wasmer_vnet::VirtualNetworking; @@ -15,6 +17,11 @@ pub enum WasiThreadError { Unsupported, #[error("The method named is not an exported function")] MethodNotFound, + #[error("Failed to create the requested memory")] + MemoryCreateFailed, + /// This will happen if WASM is running in a thread has not been created by the spawn_wasm call + #[error("WASM context is invalid")] + InvalidWasmContext, } impl From for __wasi_errno_t { @@ -22,6 +29,8 @@ impl From for __wasi_errno_t { match a { WasiThreadError::Unsupported => __WASI_ENOTSUP, WasiThreadError::MethodNotFound => __WASI_EINVAL, + WasiThreadError::MemoryCreateFailed => __WASI_EFAULT, + WasiThreadError::InvalidWasmContext => __WASI_ENOEXEC, } } } @@ -76,7 +85,10 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync { /// Spawns a new thread by invoking the fn thread_spawn( &self, - _callback: Box, + _callback: Box, + _store: Store, + _module: Module, + _existing_memory: VMMemory, ) -> Result<(), WasiThreadError> { Err(WasiThreadError::Unsupported) } @@ -123,7 +135,8 @@ impl PluggableRuntimeImplementation { } } -impl Default for PluggableRuntimeImplementation { +impl Default +for PluggableRuntimeImplementation { fn default() -> Self { Self { #[cfg(not(feature = "host-vnet"))] @@ -136,16 +149,37 @@ impl Default for PluggableRuntimeImplementation { } } -impl WasiRuntimeImplementation for PluggableRuntimeImplementation { - fn bus(&self) -> &(dyn VirtualBus) { +impl WasiRuntimeImplementation +for PluggableRuntimeImplementation { + 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() } + + #[cfg(feature = "sys-thread")] + fn thread_spawn( + &self, + callback: Box, + store: Store, + module: Module, + existing_memory: VMMemory, + ) -> Result<(), WasiThreadError> { + std::thread::spawn(move || { + callback(store, module, existing_memory) + }); + 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..ffdc50d192b 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -11,20 +11,17 @@ 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::{WasiBusProcessId, WasiEnvInner, import_object_for_all_wasi_versions, WasiFunctionEnv}; use crate::{ mem_error_to_wasi, state::{ @@ -32,25 +29,32 @@ 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 wasmer::vm::VMMemory; 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, Instance, Module, Extern, }; -use wasmer_vbus::{FileDescriptor, StdioMode}; +use wasmer_vbus::{FileDescriptor, StdioMode, BusDataFormat, BusInvocationEvent}; use wasmer_vfs::{FsError, VirtualFile}; use wasmer_vnet::{SocketHttpRequest, StreamSecurity}; @@ -391,7 +395,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 +427,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 +690,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 +1481,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 +1816,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 +2856,7 @@ pub fn path_symlink( inodes.deref_mut(), kind, false, - entry_name.clone(), + entry_name.clone().into(), ); { @@ -3448,9 +3468,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 +3476,276 @@ 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() + }; + + // Find the function we are going to invoke + match reactor { + true => { + if env.inner().react.is_none() { + warn!("thread failed - the program does not export a _react function"); + return __WASI_ENOTCAPABLE; } - */ + } + false => { + if env.inner().thread_spawn.is_none() { + warn!("thread failed - the program does not export a _start_thread function"); + return __WASI_ENOTCAPABLE; + } + } + }; - let thread = { - let mut guard = sub_env.state.threading.lock().unwrap(); - let thread = guard.threads.remove(&id); - drop(guard); - thread + // We need to drop the references + let reactors = env.inner().reactors.clone(); + let state = env.state.clone(); + let runtime = env.runtime.clone(); + let wasi_env = env.clone(); + drop(env); + + // The ID of memory is used to reattach existing memory + let child_memory = ctx.data().memory().to_vm_memory(&ctx); + + // Create the module again using the bytes in a new store (which we will pass to the worker) + let store = ctx.package_store().unpack(); + let module_bytes = ctx.data().inner().module_bytes.clone(); + let module = unsafe { + Module::deserialize(&store, &module_bytes[..]).unwrap() + }; + + // Create the worker thread + let child = sub_handle.id(); + let worker = { + // Clone the environment and drop the reference to it + let reactors = reactors.clone(); + let state = state.clone(); + let wasi_env = wasi_env.clone(); + + // Package the store so it can be unpacked in a new thread and serialize the module + // so it can be deserialized also in the upcoming thread + + // Now the actual delegate that will capture the variables we just cloned + move |mut store, module, memory: VMMemory| + { + // Attach the existing memory + let memory = Memory::new_from_existing(&mut store, memory); + + // Create a new context, imports and instance + let mut ctx = { + let mut ctx = WasiFunctionEnv::new(&mut store, wasi_env); + let mut import_object = import_object_for_all_wasi_versions(&mut store, &ctx.env); + import_object.define("env", "memory", memory.clone()); + let instance = match Instance::new(&mut store, &module, &import_object) { + Ok(a) => a, + Err(err) => { + error!("thread failed - clone instance failed: {}", err); + return __WASI_ENOEXEC as u32; + } + }; + + // Set the current thread ID + crate::THREAD_ID.with(|f| { + let mut thread_id = f.borrow_mut(); + *thread_id = child.raw(); + }); + ctx.data_mut(&mut store).inner = Some( + WasiEnvInner { + reactors, + module_bytes, + memory, + 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() + } + ); + ctx + }; + + // Next we get the function that it wants to invoke + let spawn = match reactor { + true => ctx.data(&store).inner().react.clone().unwrap(), + false => ctx.data(&store).inner().thread_spawn.clone().unwrap() }; - if let Some(thread) = thread { - let mut thread_guard = thread.exit.lock().unwrap(); - thread_guard.take(); + // 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 + { + if let Err(err) = spawn.call(&mut store, user_data as i64) { + debug!("thread failed - start: {}", 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(&store).inner().reactors.wait(Duration::from_millis(50)) == false { + if let Err(err) = ctx.data(&store).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| { + + // 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 + } + }; + + // Now spawn a thread + wasi_try!(runtime + .thread_spawn(Box::new(move |store, module, memory| { + worker(store, module, memory); + }), + store, + module, + child_memory + ).map_err(|err| { let err: __wasi_errno_t = err.into(); err })); - id + + 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 as i64, *val as i64); + }); + } + } + 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 +3795,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 +3830,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 +4050,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 +4065,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 +4122,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 +4167,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 +4202,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 +4233,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 +4257,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 +4317,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 +4340,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 +4428,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 +4537,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) + }; - __BUS_EUNSUPPORTED + // 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); + + 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 +4887,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 +4895,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 +4923,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 +4943,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 +4992,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 +5090,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 +5611,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 +6063,7 @@ pub fn sock_accept( inodes.deref_mut(), kind, false, - "socket".to_string(), + "socket".into(), ); let rights = super::state::all_socket_rights(); @@ -5204,12 +6094,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 +6291,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();