Skip to content

Commit

Permalink
feat(wasmtime-cli): add async support flag
Browse files Browse the repository at this point in the history
Within the wasmtime CLI, the current default behavior
is to only inject the synchronous functions to linkers.
This will add a flag called `--async` that will inject
the asynchronous one instead.
  • Loading branch information
eduardomourar committed Aug 22, 2023
1 parent af35da6 commit b743ff2
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 22 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

38 changes: 31 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ wasmtime-wasi-http = { workspace = true, optional = true }
wasmtime-runtime = { workspace = true }
clap = { workspace = true, features = ["color", "suggestions", "derive"] }
anyhow = { workspace = true }
futures = { workspace = true }
target-lexicon = { workspace = true }
humantime = "2.0.0"
once_cell = { workspace = true }
Expand All @@ -51,14 +52,24 @@ rustix = { workspace = true, features = ["mm", "param"] }

[dev-dependencies]
# depend again on wasmtime to activate its default features for tests
wasmtime = { workspace = true, features = ['component-model', 'async', 'default', 'winch'] }
wasmtime = { workspace = true, features = [
'component-model',
'async',
'default',
'winch',
] }
env_logger = { workspace = true }
log = { workspace = true }
filecheck = { workspace = true }
tempfile = { workspace = true }
test-programs = { path = "crates/test-programs" }
wasmtime-runtime = { workspace = true }
tokio = { version = "1.8.0", features = ["rt", "time", "macros", "rt-multi-thread"] }
tokio = { version = "1.8.0", features = [
"rt",
"time",
"macros",
"rt-multi-thread",
] }
wast = { workspace = true }
criterion = "0.5.0"
num_cpus = "1.13.0"
Expand Down Expand Up @@ -187,7 +198,9 @@ byte-array-literals = { path = "crates/wasi-preview1-component-adapter/byte-arra
regalloc2 = "0.9.2"

# cap-std family:
target-lexicon = { version = "0.12.3", default-features = false, features = ["std"] }
target-lexicon = { version = "0.12.3", default-features = false, features = [
"std",
] }
cap-std = "2.0.0"
cap-rand = { version = "2.0.0", features = ["small_rng"] }
cap-fs-ext = "2.0.0"
Expand Down Expand Up @@ -215,8 +228,15 @@ wit-component = "0.13.2"

# Non-Bytecode Alliance maintained dependencies:
# --------------------------
object = { version = "0.31.1", default-features = false, features = ['read_core', 'elf', 'std'] }
gimli = { version = "0.27.0", default-features = false, features = ['read', 'std'] }
object = { version = "0.31.1", default-features = false, features = [
'read_core',
'elf',
'std',
] }
gimli = { version = "0.27.0", default-features = false, features = [
'read',
'std',
] }
anyhow = "1.0.22"
windows-sys = "0.48.0"
env_logger = "0.10"
Expand Down Expand Up @@ -255,6 +275,7 @@ default = [
"jitdump",
"wasmtime/wat",
"wasmtime/parallel-compilation",
"wasmtime/async",
"vtune",
"wasi-nn",
"wasi-threads",
Expand All @@ -266,12 +287,15 @@ vtune = ["wasmtime/vtune"]
wasi-nn = ["dep:wasmtime-wasi-nn"]
wasi-threads = ["dep:wasmtime-wasi-threads"]
wasi-http = ["dep:wasmtime-wasi-http"]
pooling-allocator = ["wasmtime/pooling-allocator", "wasmtime-cli-flags/pooling-allocator"]
pooling-allocator = [
"wasmtime/pooling-allocator",
"wasmtime-cli-flags/pooling-allocator",
]
all-arch = ["wasmtime/all-arch"]
component-model = [
"wasmtime/component-model",
"wasmtime-wast/component-model",
"wasmtime-cli-flags/component-model"
"wasmtime-cli-flags/component-model",
]
winch = ["wasmtime/winch"]
wmemcheck = ["wasmtime/wmemcheck"]
Expand Down
67 changes: 52 additions & 15 deletions src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ fn parse_profile(s: &str) -> Result<Profile> {
}
}

fn run_future<F: futures::Future>(future: F) -> F::Output {
let mut f = Box::pin(future);
futures::executor::block_on(f.as_mut())
}

static AFTER_HELP: Lazy<String> = Lazy::new(|| crate::FLAG_EXPLANATIONS.to_string());

/// Runs a WebAssembly module
Expand Down Expand Up @@ -254,6 +259,10 @@ pub struct RunCommand {
/// removed. For now this is primarily here for testing.
#[clap(long)]
preview2: bool,

/// Indicates that the async support will be enabled
#[clap(long = "async")]
async_support: bool,
}

#[derive(Clone)]
Expand Down Expand Up @@ -312,6 +321,9 @@ impl RunCommand {
}
None => {}
}
if self.async_support {
config.async_support(true);
}

config.wmemcheck(self.wmemcheck);

Expand Down Expand Up @@ -597,7 +609,12 @@ impl RunCommand {
CliLinker::Core(linker) => {
// Use "" as a default module name.
let module = module.unwrap_core();
linker.module(&mut *store, "", &module).context(format!(
if self.async_support {
run_future(linker.module_async(&mut *store, "", &module))
} else {
linker.module(&mut *store, "", &module)
}
.context(format!(
"failed to instantiate {:?}",
self.module_and_args[0]
))?;
Expand Down Expand Up @@ -626,17 +643,24 @@ impl RunCommand {

let component = module.unwrap_component();

let (command, _instance) = preview2::command::sync::Command::instantiate(
&mut *store,
&component,
&linker,
)?;

let result = command
.wasi_cli_run()
.call_run(&mut *store)
.context("failed to invoke `run` function")
.map_err(|e| self.handle_coredump(e));
let result = if self.async_support {
let (command, _instance) =
run_future(preview2::command::Command::instantiate_async(
&mut *store,
component,
linker,
))?;
run_future(command.wasi_cli_run().call_run(&mut *store))
} else {
let (command, _instance) = preview2::command::sync::Command::instantiate(
&mut *store,
component,
linker,
)?;
command.wasi_cli_run().call_run(&mut *store)
}
.context("failed to invoke `run` function")
.map_err(|e| self.handle_coredump(e));

// Translate the `Result<(),()>` produced by wasm into a feigned
// explicit exit here with status 1 if `Err(())` is returned.
Expand Down Expand Up @@ -690,7 +714,12 @@ impl RunCommand {
// Invoke the function and then afterwards print all the results that came
// out, if there are any.
let mut results = vec![Val::null(); ty.results().len()];
let invoke_res = func.call(store, &values, &mut results).with_context(|| {
let invoke_res = if self.async_support {
run_future(func.call_async(store, &values, &mut results))
} else {
func.call(store, &values, &mut results)
}
.with_context(|| {
if let Some(name) = &self.invoke {
format!("failed to invoke `{}`", name)
} else {
Expand Down Expand Up @@ -876,7 +905,11 @@ impl RunCommand {
match linker {
CliLinker::Core(linker) => {
if self.preview2 {
wasmtime_wasi::preview2::preview1::add_to_linker_sync(linker)?;
if self.async_support {
preview2::preview1::add_to_linker_async(linker)?;
} else {
preview2::preview1::add_to_linker_sync(linker)?;
}
self.set_preview2_ctx(store)?;
} else {
wasmtime_wasi::add_to_linker(linker, |host| {
Expand All @@ -887,7 +920,11 @@ impl RunCommand {
}
#[cfg(feature = "component-model")]
CliLinker::Component(linker) => {
wasmtime_wasi::preview2::command::sync::add_to_linker(linker)?;
if self.async_support {
preview2::command::add_to_linker(linker)?;
} else {
preview2::command::sync::add_to_linker(linker)?;
}
self.set_preview2_ctx(store)?;
}
}
Expand Down
35 changes: 35 additions & 0 deletions tests/all/cli_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,14 @@ fn wasi_misaligned_pointer() -> Result<()> {
Ok(())
}

#[test]
fn hello_with_async() -> Result<()> {
let wasm = build_wasm("tests/all/cli_tests/hello_wasi_snapshot1.wat")?;
let stdout = run_wasmtime(&["--disable-cache", "--async", wasm.path().to_str().unwrap()])?;
assert_eq!(stdout, "Hello, world!\n");
Ok(())
}

#[test]
#[ignore] // FIXME(#6811) currently is flaky and may produce no output
fn hello_with_preview2() -> Result<()> {
Expand All @@ -743,6 +751,20 @@ fn hello_with_preview2() -> Result<()> {
Ok(())
}

#[test]
#[ignore] // FIXME(#6811) currently is flaky and may produce no output
fn hello_with_preview2_and_async() -> Result<()> {
let wasm = build_wasm("tests/all/cli_tests/hello_wasi_snapshot1.wat")?;
let stdout = run_wasmtime(&[
"--disable-cache",
"--preview2",
"--async",
wasm.path().to_str().unwrap(),
])?;
assert_eq!(stdout, "Hello, world!\n");
Ok(())
}

#[test]
#[cfg_attr(not(feature = "component-model"), ignore)]
fn component_missing_feature() -> Result<()> {
Expand Down Expand Up @@ -808,6 +830,19 @@ fn run_basic_component() -> Result<()> {
Ok(())
}

#[test]
#[cfg_attr(not(feature = "component-model"), ignore)]
fn run_basic_component_async() -> Result<()> {
let wasm = build_wasm("tests/all/cli_tests/component-basic.wat")?;
run_wasmtime(&[
"--disable-cache",
"--wasm-features=component-model",
"--async",
wasm.path().to_str().unwrap(),
])?;
Ok(())
}

#[test]
#[cfg_attr(not(feature = "component-model"), ignore)]
fn run_precompiled_component() -> Result<()> {
Expand Down

0 comments on commit b743ff2

Please sign in to comment.