Skip to content

Commit

Permalink
Modified the store so that it can be Cloned
Browse files Browse the repository at this point in the history
Added a Reactor that drives WebAssembly react pattern
Fixed multithreading
Added thread local storage
Implemented the remaining functionality for the bus
  • Loading branch information
john-sharratt committed Jul 22, 2022
1 parent 43138b5 commit 232a1c4
Show file tree
Hide file tree
Showing 67 changed files with 2,956 additions and 3,599 deletions.
82 changes: 62 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/migration_to_3.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This version introduces the following changes to make the Wasmer API more ergono

1. `ImportsObject` and the traits `Resolver`, `NamedResolver`, etc have been removed and replaced with a single simple type `Imports`. This reduces the complexity of setting up an `Instance`. The helper macro `imports!` can still be used.
2. There is a new `Context` that goes along the `Store`. The `Context` will keep track of all memory and functions used, removing old tracking and Weak/Strong pointer difference. Every function and memory that is retreive is linked to a specific `Context`, and cannot be mixed with another `Context`
3. `WasmerEnv` and associated traits and macro have been removed. To use Environenment, a simple structure now need to be attached to the `Context`, and can be retreive from current `Context`. All functions now takes a mendatory first argument that is of type `ContextMut<_>`, with `_` being either nothing `()` or the Environement type needed. the function creation `XXX_with_env(...)` don't exist anymore, simply use `Function::new(...)` or `Function::native_new(...)` with the correct `ContextMut<_>` type. Because the `WasmerEnv` and all helpers don't exists anymore, you have to import memory yourself, there isn't any per instance initialisation automatically done anymore. It's especialy important for WasiEnv context. `Env` can be accessed from a `Context` using `Context::data()` or `Context::data_mut()`.
3. `WasmerEnv` and associated traits and macro have been removed. To use Environenment, a simple structure now need to be attached to the `Context`, and can be retreive from current `Context`. All functions now takes a mendatory first argument that is of type `ContextMut<_>`, with `_` being either nothing `()` or the Environement type needed. the function creation `XXX_with_env(...)` don't exist anymore, simply use `Function::new(...)` or `Function::native_new(...)` with the correct `ContextMut<_>` type. Because the `WasmerEnv` and all helpers don't exists anymore, you have to import memory yourself, there isn't any per instance initialisation automatically done anymore. It's especialy important for WasiEnv context. `Env` can be accessed from a `Context` using `Context::data()`.
4. The `Engine`s API has been simplified, Instead of the `wasmer` user choosing and setting up an engine explicitly, everything now uses the universal engine. All functionalites of the `staticlib`,`dylib` Engines should be available unless explicitly stated as unsupported.

## How to use Wasmer 3.0.0
Expand Down
4 changes: 2 additions & 2 deletions examples/imports_function_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// 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<Mutex<i32>>,
Expand All @@ -82,7 +82,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
*env.data().counter.lock().unwrap()
}
fn add_to_counter(mut env: FunctionEnvMut<Env>, 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
Expand Down
2 changes: 2 additions & 0 deletions lib/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
88 changes: 88 additions & 0 deletions lib/api/src/common/reactors.rs
Original file line number Diff line number Diff line change
@@ -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<AtomicBool>,
waiting: Arc<Mutex<VecDeque<mpsc::Sender<()>>>>,
}

impl Default
for Reactors {
fn default() -> Self {
let woken = Arc::new(AtomicBool::new(false));
let waiting: Arc<Mutex<VecDeque<mpsc::Sender<()>>>> = 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,
}
}
}
4 changes: 3 additions & 1 deletion lib/api/src/js/function_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ impl<T: Send + 'static> 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)
}

Expand Down
Loading

0 comments on commit 232a1c4

Please sign in to comment.