Implement RFC 11: Redesigning Wasmtime's APIs (#2897)
Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
//! This program is an example of how Wasmtime can be used with multithreaded
|
||||
//! runtimes and how various types and structures can be shared across threads.
|
||||
|
||||
// You can execute this example with `cargo run --example threads`
|
||||
|
||||
use anyhow::Result;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use wasmtime::*;
|
||||
@@ -8,57 +12,59 @@ use wasmtime::*;
|
||||
const N_THREADS: i32 = 10;
|
||||
const N_REPS: i32 = 3;
|
||||
|
||||
fn run(engine: &Engine, module: Module, id: i32) -> Result<()> {
|
||||
let store = Store::new(&engine);
|
||||
|
||||
// Create external print functions.
|
||||
println!("Creating callback...");
|
||||
let callback_func = Func::wrap(&store, |arg: i32| {
|
||||
println!("> Thread {} is running", arg);
|
||||
});
|
||||
|
||||
let id_type = GlobalType::new(ValType::I32, Mutability::Const);
|
||||
let id_global = Global::new(&store, id_type, Val::I32(id))?;
|
||||
|
||||
// Instantiate.
|
||||
println!("Instantiating module...");
|
||||
let instance = Instance::new(&store, &module, &[callback_func.into(), id_global.into()])?;
|
||||
|
||||
// Extract exports.
|
||||
println!("Extracting export...");
|
||||
let g = instance.get_typed_func::<(), ()>("run")?;
|
||||
|
||||
for _ in 0..N_REPS {
|
||||
thread::sleep(time::Duration::from_millis(100));
|
||||
// Call `$run`.
|
||||
drop(g.call(())?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
println!("Initializing...");
|
||||
|
||||
// Initialize global per-process state. This state will be shared amonst all
|
||||
// threads. Notably this includes the compiled module as well as a `Linker`,
|
||||
// which contains all our host functions we want to define.
|
||||
let engine = Engine::default();
|
||||
|
||||
// Compile.
|
||||
println!("Compiling module...");
|
||||
let module = Module::from_file(&engine, "examples/threads.wat")?;
|
||||
let mut linker = Linker::new(&engine);
|
||||
linker.func_wrap("global", "hello", || {
|
||||
println!("> Hello from {:?}", thread::current().id());
|
||||
})?;
|
||||
let linker = Arc::new(linker); // "finalize" the linker
|
||||
|
||||
let mut children = Vec::new();
|
||||
for id in 0..N_THREADS {
|
||||
let engine = engine.clone();
|
||||
let module = module.clone();
|
||||
children.push(thread::spawn(move || {
|
||||
run(&engine, module, id).expect("Success");
|
||||
}));
|
||||
}
|
||||
// Share this global state amongst a set of threads, each of which will
|
||||
// create stores and execute instances.
|
||||
let children = (0..N_THREADS)
|
||||
.map(|_| {
|
||||
let engine = engine.clone();
|
||||
let module = module.clone();
|
||||
let linker = linker.clone();
|
||||
thread::spawn(move || {
|
||||
run(&engine, &module, &linker).expect("Success");
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (i, child) in children.into_iter().enumerate() {
|
||||
if let Err(_) = child.join() {
|
||||
println!("Thread #{} errors", i);
|
||||
}
|
||||
for child in children {
|
||||
child.join().unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(engine: &Engine, module: &Module, linker: &Linker<()>) -> Result<()> {
|
||||
// Each sub-thread we have starting out by instantiating the `module`
|
||||
// provided into a fresh `Store`.
|
||||
println!("Instantiating module...");
|
||||
let mut store = Store::new(&engine, ());
|
||||
let instance = linker.instantiate(&mut store, module)?;
|
||||
let run = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
|
||||
println!("Executing...");
|
||||
for _ in 0..N_REPS {
|
||||
run.call(&mut store, ())?;
|
||||
thread::sleep(time::Duration::from_millis(100));
|
||||
}
|
||||
|
||||
// Also note that that a `Store` can also move between threads:
|
||||
println!("> Moving {:?} to a new thread", thread::current().id());
|
||||
let child = thread::spawn(move || run.call(&mut store, ()));
|
||||
|
||||
child.join().unwrap()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user