Skip to content

Commit

Permalink
[feat] implement a separate VmBuilder::build method for async cas…
Browse files Browse the repository at this point in the history
…es (#3)

* chore(rust-sys): expose WasiCtx

Signed-off-by: Xin Liu <[email protected]>

* chore(rust-sdk): expose WasiCtx

Signed-off-by: Xin Liu <[email protected]>

* refactor(rust-sdk): split VmBuilder::build

Signed-off-by: Xin Liu <[email protected]>

* chore(rust-sdk): update test code

Signed-off-by: Xin Liu <[email protected]>

* chore(rust-sdk): update examples

Signed-off-by: Xin Liu <[email protected]>

* chore(rust-sdk): update test code

Signed-off-by: Xin Liu <[email protected]>

* chore(rust-sdk): update rustdoc

Signed-off-by: Xin Liu <[email protected]>

* ci(bindings-rust): update PR paths

Signed-off-by: Xin Liu <[email protected]>

* feat(async-wasi): implement new APIs in WasiCtx

Signed-off-by: Xin Liu <[email protected]>

* feat(rust-sys): implement new APIs in AsyncWasiModule

Signed-off-by: Xin Liu <[email protected]>

* feat(rust-sdk): implement new APIs in WasiInstance

Signed-off-by: Xin Liu <[email protected]>

* chore(rust-sdk): refactor build method of VmBuilder

Signed-off-by: Xin Liu <[email protected]>

* chore(rust-sdk): update examples

Signed-off-by: Xin Liu <[email protected]>

* ci(bindings-rust): rust-1.70

Signed-off-by: Xin Liu <[email protected]>

* ci(bindings-rust): update rust version

Signed-off-by: Xin Liu <[email protected]>

* chore(rust-sys): update test code

Signed-off-by: Xin Liu <[email protected]>

---------

Signed-off-by: Xin Liu <[email protected]>
  • Loading branch information
apepkuss authored Jun 12, 2023
1 parent 0d453ff commit 176dd10
Show file tree
Hide file tree
Showing 19 changed files with 468 additions and 244 deletions.
11 changes: 7 additions & 4 deletions .github/workflows/bindings-rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ on:
- main
paths:
- ".github/workflows/bindings-rust.yml"
- "examples/**"
- "src/**"
- "crates/**"

jobs:
build_ubuntu:
Expand All @@ -34,7 +37,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-22.04]
rust: [1.69, 1.68]
rust: [1.70.0, 1.69, 1.68]
container:
image: wasmedge/wasmedge:ubuntu-build-clang

Expand Down Expand Up @@ -112,7 +115,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
rust: [1.69, 1.68]
rust: [1.70.0, 1.69, 1.68]
container:
image: fedora:latest
steps:
Expand Down Expand Up @@ -197,7 +200,7 @@ jobs:
strategy:
matrix:
os: [macos-11, macos-12]
rust: [1.69, 1.68]
rust: [1.70.0, 1.69, 1.68]

steps:
- name: Checkout sources
Expand Down Expand Up @@ -260,7 +263,7 @@ jobs:
runs-on: windows-2022
strategy:
matrix:
rust: [1.69, 1.68]
rust: [1.70.0, 1.69, 1.68]
env:
WASMEDGE_DIR: ${{ github.workspace }}\WasmEdge
WASMEDGE_BUILD_DIR: ${{ github.workspace }}\WasmEdge\build
Expand Down
15 changes: 12 additions & 3 deletions crates/async-wasi/src/snapshots/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
pub mod common;
pub mod env;
pub mod preview_1;
use common::error::Errno;

use crate::object_pool::ObjectPool;
use common::error::Errno;
use env::{wasi_types::__wasi_fd_t, VFD};
use std::path::PathBuf;

#[derive(Debug)]
pub struct WasiCtx {
Expand Down Expand Up @@ -44,7 +45,7 @@ impl WasiCtx {
}
}

pub fn push_preopen(&mut self, host_path: std::path::PathBuf, guest_path: std::path::PathBuf) {
pub fn push_preopen(&mut self, host_path: PathBuf, guest_path: PathBuf) {
let preopen = env::vfs::WasiPreOpenDir::new(host_path, guest_path);
self.vfs
.push(VFD::Inode(env::vfs::INode::PreOpenDir(preopen)));
Expand All @@ -55,11 +56,19 @@ impl WasiCtx {
self.args.push(arg);
}

pub fn push_args(&mut self, args: Vec<String>) {
self.args.extend(args);
}

/// The format of the `env` argument should be "KEY=VALUE"
pub fn push_env(&mut self, env: String) {
self.envs.push(env);
}

pub fn push_envs(&mut self, envs: Vec<String>) {
self.envs.extend(envs);
}

fn remove_closed(&mut self) {
if let Some(closed) = self.closed.take() {
let _ = self.remove_vfd(closed);
Expand Down Expand Up @@ -642,7 +651,7 @@ pub mod serialize {
let mut wasi_ctx = super::WasiCtx::new();
wasi_ctx.push_arg("abc".to_string());
wasi_ctx.push_env("a=1".to_string());
wasi_ctx.push_preopen(".".parse().unwrap(), ".".parse().unwrap());
wasi_ctx.push_preopen(PathBuf::from("."), PathBuf::from("."));

// tcp4
let state = net::WasiSocketState::default();
Expand Down
4 changes: 2 additions & 2 deletions crates/wasmedge-sys/src/async_wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,9 @@ pub fn args_sizes_get(
pub fn environ_get(
frame: CallingFrame,
args: Vec<WasmValue>,
data: Option<&mut WasiCtx>,
ctx: Option<&mut WasiCtx>,
) -> std::result::Result<Vec<WasmValue>, HostFuncError> {
let data = data.unwrap();
let data = ctx.unwrap();

let mut mem = frame.memory_mut(0).ok_or(HostFuncError::Runtime(0x88))?;

Expand Down
16 changes: 2 additions & 14 deletions crates/wasmedge-sys/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,6 @@ mod tests {
AsImport, CallingFrame, Config, FuncType, Function, Global, GlobalType, ImportModule,
MemType, Memory, Statistics, Table, TableType,
};
#[cfg(all(feature = "async", target_os = "linux"))]
use async_wasi::snapshots::WasiCtx;
use std::{
sync::{Arc, Mutex},
thread,
Expand Down Expand Up @@ -593,13 +591,8 @@ mod tests {
assert!(result.is_ok());
let mut store = result.unwrap();

// create async wasi context
let mut async_wasi_ctx = WasiCtx::new();
async_wasi_ctx.push_arg("abc".into());
async_wasi_ctx.push_env("a=1".into());

// create an AsyncWasiModule
let result = AsyncWasiModule::create(Some(&mut async_wasi_ctx));
let result = AsyncWasiModule::create(Some(vec!["abc"]), Some(vec![("a", "1")]), None);
assert!(result.is_ok());
let async_wasi_module = result.unwrap();

Expand Down Expand Up @@ -650,13 +643,8 @@ mod tests {
assert!(result.is_ok());
let mut store = result.unwrap();

// create async wasi context
let mut async_wasi_ctx = WasiCtx::new();
async_wasi_ctx.push_arg("abc".into());
async_wasi_ctx.push_env("a=1".into());

// create an AsyncWasiModule
let result = AsyncWasiModule::create(Some(&mut async_wasi_ctx));
let result = AsyncWasiModule::create(Some(vec!["abc"]), Some(vec![("a", "1")]), None);
assert!(result.is_ok());
let async_wasi_module = result.unwrap();

Expand Down
168 changes: 130 additions & 38 deletions crates/wasmedge-sys/src/instance/module.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
//! Defines WasmEdge Instance and other relevant types.
#[cfg(all(feature = "async", target_os = "linux"))]
use crate::async_wasi::{wasi_impls, WasiFunc};
use crate::{
async_wasi::{wasi_impls, WasiFunc},
WasiCtx,
};
use crate::{
error::{InstanceError, WasmEdgeError},
ffi,
instance::{function::InnerFunc, global::InnerGlobal, memory::InnerMemory, table::InnerTable},
types::WasmEdgeString,
Function, Global, Memory, Table, WasmEdgeResult,
};
#[cfg(all(feature = "async", target_os = "linux"))]
use async_wasi::snapshots::WasiCtx as AsyncWasiCtx;
use std::sync::Arc;
#[cfg(all(feature = "async", target_os = "linux"))]
use std::{path::PathBuf, sync::Mutex};

/// An [Instance] represents an instantiated module. In the instantiation process, An [Instance] is created from al[Module](crate::Module). From an [Instance] the exported [functions](crate::Function), [tables](crate::Table), [memories](crate::Memory), and [globals](crate::Global) can be fetched.
#[derive(Debug)]
Expand Down Expand Up @@ -875,6 +878,7 @@ pub struct AsyncWasiModule {
pub(crate) inner: Arc<InnerInstance>,
pub(crate) registered: bool,
name: String,
wasi_ctx: Arc<Mutex<WasiCtx>>,
}
#[cfg(all(feature = "async", target_os = "linux"))]
impl Drop for AsyncWasiModule {
Expand All @@ -888,62 +892,150 @@ impl Drop for AsyncWasiModule {
}
#[cfg(all(feature = "async", target_os = "linux"))]
impl AsyncWasiModule {
pub fn create(async_wasi_ctx: Option<&mut AsyncWasiCtx>) -> WasmEdgeResult<Self> {
pub fn create(
args: Option<Vec<&str>>,
envs: Option<Vec<(&str, &str)>>,
preopens: Option<Vec<(PathBuf, PathBuf)>>,
) -> WasmEdgeResult<Self> {
// create wasi context
let mut wasi_ctx = WasiCtx::new();
if let Some(args) = args {
wasi_ctx.push_args(args.iter().map(|x| x.to_string()).collect());
}
if let Some(envs) = envs {
wasi_ctx.push_envs(envs.iter().map(|(k, v)| format!("{}={}", k, v)).collect());
}
if let Some(preopens) = preopens {
for (host_dir, guest_dir) in preopens {
wasi_ctx.push_preopen(host_dir, guest_dir)
}
}

// create wasi module
let name = "wasi_snapshot_preview1";
let raw_name = WasmEdgeString::from(name);
let ctx = unsafe { ffi::WasmEdge_ModuleInstanceCreate(raw_name.as_raw()) };

if ctx.is_null() {
return Err(Box::new(WasmEdgeError::Instance(
InstanceError::CreateImportModule,
)));
}

let mut async_wasi_module = Self {
inner: std::sync::Arc::new(InnerInstance(ctx)),
registered: false,
name: name.to_string(),
wasi_ctx: Arc::new(Mutex::new(wasi_ctx)),
};

// add sync/async host functions to the module
match async_wasi_ctx {
Some(ctx_data) => {
for wasi_func in wasi_impls() {
match wasi_func {
WasiFunc::SyncFn(name, (ty_args, ty_rets), real_fn) => {
let func_ty = crate::FuncType::create(ty_args, ty_rets)?;
let func = Function::create(&func_ty, real_fn, Some(ctx_data), 0)?;
async_wasi_module.add_func(name, func);
}
WasiFunc::AsyncFn(name, (ty_args, ty_rets), real_async_fn) => {
let func_ty = crate::FuncType::create(ty_args, ty_rets)?;
let func =
Function::create_async(&func_ty, real_async_fn, Some(ctx_data), 0)?;
async_wasi_module.add_func(name, func);
}
}
for wasi_func in wasi_impls() {
match wasi_func {
WasiFunc::SyncFn(name, (ty_args, ty_rets), real_fn) => {
let func_ty = crate::FuncType::create(ty_args, ty_rets)?;
let func = Function::create(
&func_ty,
real_fn,
Some(
&mut async_wasi_module
.wasi_ctx
.lock()
.expect("[wasmedge-sys] failed to get the lock on wasi_ctx"),
),
0,
)?;
async_wasi_module.add_func(name, func);
}
}
None => {
for wasi_func in wasi_impls() {
match wasi_func {
WasiFunc::SyncFn(name, (ty_args, ty_rets), real_fn) => {
let func_ty = crate::FuncType::create(ty_args, ty_rets)?;
let func = Function::create(&func_ty, real_fn, None, 0)?;
async_wasi_module.add_func(name, func);
}
WasiFunc::AsyncFn(name, (ty_args, ty_rets), real_async_fn) => {
let func_ty = crate::FuncType::create(ty_args, ty_rets)?;
let func = Function::create_async(&func_ty, real_async_fn, None, 0)?;
async_wasi_module.add_func(name, func);
}
}
WasiFunc::AsyncFn(name, (ty_args, ty_rets), real_async_fn) => {
let func_ty = crate::FuncType::create(ty_args, ty_rets)?;
let func = Function::create_async(
&func_ty,
real_async_fn,
Some(
&mut async_wasi_module
.wasi_ctx
.lock()
.expect("[wasmedge-sys] failed to get the lock on wasi_ctx"),
),
0,
)?;
async_wasi_module.add_func(name, func);
}
}
};
}

Ok(async_wasi_module)
}

pub fn init_wasi(
&mut self,
args: Option<Vec<&str>>,
envs: Option<Vec<(&str, &str)>>,
preopens: Option<Vec<(PathBuf, PathBuf)>>,
) -> WasmEdgeResult<()> {
// create wasi context
let mut wasi_ctx = WasiCtx::new();
if let Some(args) = args {
wasi_ctx.push_args(args.iter().map(|x| x.to_string()).collect());
}
if let Some(envs) = envs {
wasi_ctx.push_envs(envs.iter().map(|(k, v)| format!("{}={}", k, v)).collect());
}
if let Some(preopens) = preopens {
for (host_dir, guest_dir) in preopens {
wasi_ctx.push_preopen(host_dir, guest_dir)
}
}

self.wasi_ctx = Arc::new(Mutex::new(wasi_ctx));

// add sync/async host functions to the module
for wasi_func in wasi_impls() {
match wasi_func {
WasiFunc::SyncFn(name, (ty_args, ty_rets), real_fn) => {
let func_ty = crate::FuncType::create(ty_args, ty_rets)?;
let func = Function::create(
&func_ty,
real_fn,
Some(
&mut self
.wasi_ctx
.lock()
.expect("[wasmedge-sys] failed to get the lock on wasi_ctx"),
),
0,
)?;
self.add_func(name, func);
}
WasiFunc::AsyncFn(name, (ty_args, ty_rets), real_async_fn) => {
let func_ty = crate::FuncType::create(ty_args, ty_rets)?;
let func = Function::create_async(
&func_ty,
real_async_fn,
Some(
&mut self
.wasi_ctx
.lock()
.expect("[wasmedge-sys] failed to get the lock on wasi_ctx"),
),
0,
)?;
self.add_func(name, func);
}
}
}

Ok(())
}

/// Returns the WASI exit code.
///
/// The WASI exit code can be accessed after running the "_start" function of a `wasm32-wasi` program.
pub fn exit_code(&self) -> u32 {
self.wasi_ctx
.lock()
.expect("[wasmedge-sys] failed to get the lock on wasi_ctx")
.exit_code
}
}
#[cfg(all(feature = "async", target_os = "linux"))]
impl AsInstance for AsyncWasiModule {
Expand Down
3 changes: 3 additions & 0 deletions crates/wasmedge-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ pub use types::WasmValue;
pub use validator::Validator;
use wasmedge_types::{error, WasmEdgeResult};

#[cfg(all(feature = "async", target_os = "linux"))]
pub type WasiCtx = ::async_wasi::snapshots::WasiCtx;

/// The object that is used to perform a [host function](crate::Function) is required to implement this trait.
pub trait Engine {
/// Runs a host function instance and returns the results.
Expand Down
Loading

0 comments on commit 176dd10

Please sign in to comment.