mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-08 21:58:20 +00:00
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -4195,9 +4195,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-inline-c"
|
||||
version = "0.1.2"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c4e7a2a3363ceeb2ee60371af9460748f2bf53569b58627f1f640284ab07778"
|
||||
checksum = "e2405c99de49dc05338e5ed2eb397fe70b7128340d960507d0ba716f7d29a91a"
|
||||
dependencies = [
|
||||
"assert_cmd",
|
||||
"cc",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
use std::io::{Read, Write};
|
||||
use wasmer::{Instance, Module, Store};
|
||||
use wasmer_compiler_cranelift::Cranelift;
|
||||
use wasmer_wasi::{WasiBidirectionalSharedPipePair, WasiState};
|
||||
use wasmer_wasi::{Pipe, WasiState};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let wasm_path = concat!(
|
||||
@@ -36,8 +36,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
println!("Creating `WasiEnv`...");
|
||||
// First, we create the `WasiEnv` with the stdio pipes
|
||||
let mut input = WasiBidirectionalSharedPipePair::new().with_blocking(false);
|
||||
let mut output = WasiBidirectionalSharedPipePair::new().with_blocking(false);
|
||||
let mut input = Pipe::new();
|
||||
let mut output = Pipe::new();
|
||||
let wasi_env = WasiState::new("hello")
|
||||
.stdin(Box::new(input.clone()))
|
||||
.stdout(Box::new(output.clone()))
|
||||
|
||||
@@ -210,25 +210,28 @@ fn memory_grow() -> Result<(), String> {
|
||||
fn function_new() -> Result<(), String> {
|
||||
let mut store = Store::default();
|
||||
let function = Function::new_typed(&mut store, || {});
|
||||
assert_eq!(function.ty(&mut store), FunctionType::new(vec![], vec![]));
|
||||
assert_eq!(
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![], vec![])
|
||||
);
|
||||
let function = Function::new_typed(&mut store, |_a: i32| {});
|
||||
assert_eq!(
|
||||
function.ty(&mut store),
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![Type::I32], vec![])
|
||||
);
|
||||
let function = Function::new_typed(&mut store, |_a: i32, _b: i64, _c: f32, _d: f64| {});
|
||||
assert_eq!(
|
||||
function.ty(&mut store),
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
||||
);
|
||||
let function = Function::new_typed(&mut store, || -> i32 { 1 });
|
||||
assert_eq!(
|
||||
function.ty(&mut store),
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![], vec![Type::I32])
|
||||
);
|
||||
let function = Function::new_typed(&mut store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
||||
assert_eq!(
|
||||
function.ty(&mut store),
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
||||
);
|
||||
Ok(())
|
||||
@@ -243,11 +246,14 @@ fn function_new_env() -> Result<(), String> {
|
||||
let my_env = MyEnv {};
|
||||
let env = FunctionEnv::new(&mut store, my_env);
|
||||
let function = Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut<MyEnv>| {});
|
||||
assert_eq!(function.ty(&mut store), FunctionType::new(vec![], vec![]));
|
||||
assert_eq!(
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![], vec![])
|
||||
);
|
||||
let function =
|
||||
Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut<MyEnv>, _a: i32| {});
|
||||
assert_eq!(
|
||||
function.ty(&mut store),
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![Type::I32], vec![])
|
||||
);
|
||||
let function = Function::new_typed_with_env(
|
||||
@@ -256,13 +262,13 @@ fn function_new_env() -> Result<(), String> {
|
||||
|_env: FunctionEnvMut<MyEnv>, _a: i32, _b: i64, _c: f32, _d: f64| {},
|
||||
);
|
||||
assert_eq!(
|
||||
function.ty(&mut store),
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
||||
);
|
||||
let function =
|
||||
Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut<MyEnv>| -> i32 { 1 });
|
||||
assert_eq!(
|
||||
function.ty(&mut store),
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![], vec![Type::I32])
|
||||
);
|
||||
let function = Function::new_typed_with_env(
|
||||
@@ -271,7 +277,7 @@ fn function_new_env() -> Result<(), String> {
|
||||
|_env: FunctionEnvMut<MyEnv>| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
|
||||
);
|
||||
assert_eq!(
|
||||
function.ty(&mut store),
|
||||
function.ty(&mut store).clone(),
|
||||
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
||||
);
|
||||
Ok(())
|
||||
@@ -288,35 +294,35 @@ fn function_new_dynamic() -> Result<(), String> {
|
||||
&function_type,
|
||||
|_values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
||||
let function = Function::new(
|
||||
&mut store,
|
||||
&function_type,
|
||||
|_values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
||||
let function = Function::new(
|
||||
&mut store,
|
||||
&function_type,
|
||||
|_values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
||||
let function = Function::new(
|
||||
&mut store,
|
||||
&function_type,
|
||||
|_values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
||||
let function = Function::new(
|
||||
&mut store,
|
||||
&function_type,
|
||||
|_values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
|
||||
// Using array signature
|
||||
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
||||
@@ -350,7 +356,7 @@ fn function_new_dynamic_env() -> Result<(), String> {
|
||||
&function_type,
|
||||
|_env: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
||||
let function = Function::new_with_env(
|
||||
&mut store,
|
||||
@@ -358,7 +364,7 @@ fn function_new_dynamic_env() -> Result<(), String> {
|
||||
&function_type,
|
||||
|_env: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
||||
let function = Function::new_with_env(
|
||||
&mut store,
|
||||
@@ -366,7 +372,7 @@ fn function_new_dynamic_env() -> Result<(), String> {
|
||||
&function_type,
|
||||
|_env: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
||||
let function = Function::new_with_env(
|
||||
&mut store,
|
||||
@@ -374,7 +380,7 @@ fn function_new_dynamic_env() -> Result<(), String> {
|
||||
&function_type,
|
||||
|_env: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
||||
let function = Function::new_with_env(
|
||||
&mut store,
|
||||
@@ -382,7 +388,7 @@ fn function_new_dynamic_env() -> Result<(), String> {
|
||||
&function_type,
|
||||
|_env: FunctionEnvMut<MyEnv>, _values: &[Value]| unimplemented!(),
|
||||
);
|
||||
assert_eq!(function.ty(&mut store), function_type);
|
||||
assert_eq!(function.ty(&mut store).clone(), function_type);
|
||||
|
||||
// Using array signature
|
||||
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
||||
|
||||
@@ -367,7 +367,7 @@ pub mod reference_types {
|
||||
let global: &Global = instance.exports.get_global("global")?;
|
||||
{
|
||||
let er = ExternRef::new(&mut store, 3usize);
|
||||
global.set(&mut store, Value::ExternRef(Some(er)))?;
|
||||
global.set(&mut store, Value::ExternRef(Some(er.clone())))?;
|
||||
}
|
||||
let get_from_global: TypedFunction<(), Option<ExternRef>> = instance
|
||||
.exports
|
||||
@@ -398,7 +398,7 @@ pub mod reference_types {
|
||||
|
||||
let er = ExternRef::new(&mut store, 3usize);
|
||||
|
||||
let result = pass_extern_ref.call(&mut store, Some(er));
|
||||
let result = pass_extern_ref.call(&mut store, Some(er.clone()));
|
||||
assert!(result.is_err());
|
||||
|
||||
Ok(())
|
||||
@@ -442,7 +442,7 @@ pub mod reference_types {
|
||||
let result = grow_table_with_ref.call(&mut store, Some(er1.clone()), 10_000)?;
|
||||
assert_eq!(result, -1);
|
||||
|
||||
let result = grow_table_with_ref.call(&mut store, Some(er1), 8)?;
|
||||
let result = grow_table_with_ref.call(&mut store, Some(er1.clone()), 8)?;
|
||||
assert_eq!(result, 2);
|
||||
|
||||
for i in 2..10 {
|
||||
@@ -454,7 +454,7 @@ pub mod reference_types {
|
||||
}
|
||||
|
||||
{
|
||||
fill_table_with_ref.call(&mut store, Some(er2), 0, 2)?;
|
||||
fill_table_with_ref.call(&mut store, Some(er2.clone()), 0, 2)?;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -462,7 +462,7 @@ pub mod reference_types {
|
||||
table2.set(&mut store, 1, Value::ExternRef(Some(er3.clone())))?;
|
||||
table2.set(&mut store, 2, Value::ExternRef(Some(er3.clone())))?;
|
||||
table2.set(&mut store, 3, Value::ExternRef(Some(er3.clone())))?;
|
||||
table2.set(&mut store, 4, Value::ExternRef(Some(er3)))?;
|
||||
table2.set(&mut store, 4, Value::ExternRef(Some(er3.clone())))?;
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -357,7 +357,7 @@ impl VMMemory {
|
||||
///
|
||||
/// This creates a `Memory` with owned metadata: this can be used to create a memory
|
||||
/// that will be imported into Wasm modules.
|
||||
pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
|
||||
pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<VMMemory, MemoryError> {
|
||||
Ok(Self(Box::new(VMOwnedMemory::new(memory, style)?)))
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ impl VMMemory {
|
||||
memory: &MemoryType,
|
||||
style: &MemoryStyle,
|
||||
vm_memory_location: NonNull<VMMemoryDefinition>,
|
||||
) -> Result<Self, MemoryError> {
|
||||
) -> Result<VMMemory, MemoryError> {
|
||||
Ok(Self(Box::new(VMOwnedMemory::from_definition(
|
||||
memory,
|
||||
style,
|
||||
@@ -389,9 +389,9 @@ impl VMMemory {
|
||||
/// are natively supported
|
||||
/// - VMOwnedMemory -> VMMemory
|
||||
/// - Box<dyn LinearMemory + 'static> -> VMMemory
|
||||
pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> Self
|
||||
pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> VMMemory
|
||||
where
|
||||
IntoVMMemory: Into<Self>,
|
||||
IntoVMMemory: Into<VMMemory>,
|
||||
{
|
||||
memory.into()
|
||||
}
|
||||
|
||||
@@ -47,9 +47,8 @@ pub mod runners;
|
||||
use crate::syscalls::*;
|
||||
|
||||
pub use crate::state::{
|
||||
Fd, Pipe, Stderr, Stdin, Stdout, WasiBidirectionalPipePair, WasiBidirectionalSharedPipePair,
|
||||
WasiFs, WasiInodes, WasiPipe, WasiState, WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS,
|
||||
VIRTUAL_ROOT_FD,
|
||||
Fd, Pipe, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiState, WasiStateBuilder,
|
||||
WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD,
|
||||
};
|
||||
pub use crate::syscalls::types;
|
||||
#[cfg(feature = "wasix")]
|
||||
|
||||
@@ -2,14 +2,12 @@ use crate::syscalls::types::*;
|
||||
use crate::syscalls::{read_bytes, write_bytes};
|
||||
use bytes::{Buf, Bytes};
|
||||
use std::convert::TryInto;
|
||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||
use std::io::{self, Read};
|
||||
use std::ops::DerefMut;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use wasmer::WasmSlice;
|
||||
use wasmer::{MemorySize, MemoryView};
|
||||
use wasmer_vfs::{FsError, VirtualFile};
|
||||
use wasmer_wasi_types::wasi::Errno;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -20,70 +18,10 @@ pub struct WasiPipe {
|
||||
rx: Mutex<mpsc::Receiver<Vec<u8>>>,
|
||||
/// Buffers the last read message from the pipe while its being consumed
|
||||
read_buffer: Option<Bytes>,
|
||||
/// Whether the pipe should block or not block to wait for stdin reads
|
||||
block: bool,
|
||||
}
|
||||
|
||||
/// Pipe pair of (a, b) WasiPipes that are connected together
|
||||
#[derive(Debug)]
|
||||
pub struct WasiBidirectionalPipePair {
|
||||
pub send: WasiPipe,
|
||||
pub recv: WasiPipe,
|
||||
}
|
||||
|
||||
impl Write for WasiBidirectionalPipePair {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.send.write(buf)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.send.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for WasiBidirectionalPipePair {
|
||||
fn seek(&mut self, _: SeekFrom) -> io::Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for WasiBidirectionalPipePair {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
self.recv.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualFile for WasiBidirectionalPipePair {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
self.recv.last_accessed()
|
||||
}
|
||||
fn last_modified(&self) -> u64 {
|
||||
self.recv.last_modified()
|
||||
}
|
||||
fn created_time(&self) -> u64 {
|
||||
self.recv.created_time()
|
||||
}
|
||||
fn size(&self) -> u64 {
|
||||
self.recv.size()
|
||||
}
|
||||
fn set_len(&mut self, i: u64) -> Result<(), FsError> {
|
||||
self.recv.set_len(i)
|
||||
}
|
||||
fn unlink(&mut self) -> Result<(), FsError> {
|
||||
self.recv.unlink()
|
||||
}
|
||||
fn bytes_available_read(&self) -> Result<Option<usize>, FsError> {
|
||||
self.recv.bytes_available_read()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WasiBidirectionalPipePair {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl WasiBidirectionalPipePair {
|
||||
pub fn new() -> WasiBidirectionalPipePair {
|
||||
impl WasiPipe {
|
||||
pub fn new() -> (WasiPipe, WasiPipe) {
|
||||
let (tx1, rx1) = mpsc::channel();
|
||||
let (tx2, rx2) = mpsc::channel();
|
||||
|
||||
@@ -91,142 +29,15 @@ impl WasiBidirectionalPipePair {
|
||||
tx: Mutex::new(tx1),
|
||||
rx: Mutex::new(rx2),
|
||||
read_buffer: None,
|
||||
block: true,
|
||||
};
|
||||
|
||||
let pipe2 = WasiPipe {
|
||||
tx: Mutex::new(tx2),
|
||||
rx: Mutex::new(rx1),
|
||||
read_buffer: None,
|
||||
block: true,
|
||||
};
|
||||
|
||||
WasiBidirectionalPipePair {
|
||||
send: pipe1,
|
||||
recv: pipe2,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn with_blocking(mut self, block: bool) -> Self {
|
||||
self.set_blocking(block);
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether to block on reads (ususally for waiting for stdin keyboard input). Default: `true`
|
||||
#[allow(dead_code)]
|
||||
pub fn set_blocking(&mut self, block: bool) {
|
||||
self.send.set_blocking(block);
|
||||
self.recv.set_blocking(block);
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared version of WasiBidirectionalPipePair for situations where you need
|
||||
/// to emulate the old behaviour of `Pipe` (both send and recv on one channel).
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WasiBidirectionalSharedPipePair {
|
||||
inner: Arc<Mutex<WasiBidirectionalPipePair>>,
|
||||
}
|
||||
|
||||
impl Default for WasiBidirectionalSharedPipePair {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl WasiBidirectionalSharedPipePair {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(WasiBidirectionalPipePair::new())),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn with_blocking(mut self, block: bool) -> Self {
|
||||
self.set_blocking(block);
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether to block on reads (ususally for waiting for stdin keyboard input). Default: `true`
|
||||
#[allow(dead_code)]
|
||||
pub fn set_blocking(&mut self, block: bool) {
|
||||
self.inner.lock().unwrap().set_blocking(block);
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for WasiBidirectionalSharedPipePair {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
match self.inner.lock().as_mut().map(|l| l.write(buf)) {
|
||||
Ok(r) => r,
|
||||
Err(_) => Ok(0),
|
||||
}
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
match self.inner.lock().as_mut().map(|l| l.flush()) {
|
||||
Ok(r) => r,
|
||||
Err(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for WasiBidirectionalSharedPipePair {
|
||||
fn seek(&mut self, _: SeekFrom) -> io::Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for WasiBidirectionalSharedPipePair {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
match self.inner.lock().as_mut().map(|l| l.read(buf)) {
|
||||
Ok(r) => r,
|
||||
Err(_) => Ok(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualFile for WasiBidirectionalSharedPipePair {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
self.inner.lock().map(|l| l.last_accessed()).unwrap_or(0)
|
||||
}
|
||||
fn last_modified(&self) -> u64 {
|
||||
self.inner.lock().map(|l| l.last_modified()).unwrap_or(0)
|
||||
}
|
||||
fn created_time(&self) -> u64 {
|
||||
self.inner.lock().map(|l| l.created_time()).unwrap_or(0)
|
||||
}
|
||||
fn size(&self) -> u64 {
|
||||
self.inner.lock().map(|l| l.size()).unwrap_or(0)
|
||||
}
|
||||
fn set_len(&mut self, i: u64) -> Result<(), FsError> {
|
||||
match self.inner.lock().as_mut().map(|l| l.set_len(i)) {
|
||||
Ok(r) => r,
|
||||
Err(_) => Err(FsError::Lock),
|
||||
}
|
||||
}
|
||||
fn unlink(&mut self) -> Result<(), FsError> {
|
||||
match self.inner.lock().as_mut().map(|l| l.unlink()) {
|
||||
Ok(r) => r,
|
||||
Err(_) => Err(FsError::Lock),
|
||||
}
|
||||
}
|
||||
fn bytes_available_read(&self) -> Result<Option<usize>, FsError> {
|
||||
self.inner
|
||||
.lock()
|
||||
.map(|l| l.bytes_available_read())
|
||||
.unwrap_or(Ok(None))
|
||||
}
|
||||
}
|
||||
|
||||
impl WasiPipe {
|
||||
/// Same as `set_blocking`, but as a builder method
|
||||
pub fn with_blocking(mut self, block: bool) -> Self {
|
||||
self.set_blocking(block);
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether to block on reads (ususally for waiting for stdin keyboard input). Default: `true`
|
||||
pub fn set_blocking(&mut self, block: bool) {
|
||||
self.block = block;
|
||||
(pipe1, pipe2)
|
||||
}
|
||||
|
||||
pub fn recv<M: MemorySize>(
|
||||
@@ -283,113 +94,26 @@ impl WasiPipe {
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for WasiPipe {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
let buf_len = buf.len();
|
||||
let tx = self.tx.lock().unwrap();
|
||||
tx.send(buf.to_vec())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{e}")))?;
|
||||
Ok(buf_len)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for WasiPipe {
|
||||
fn seek(&mut self, _: SeekFrom) -> io::Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for WasiPipe {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
loop {
|
||||
if let Some(inner_buf) = self.read_buffer.as_mut() {
|
||||
let buf_len = inner_buf.len();
|
||||
if buf_len > 0 {
|
||||
if inner_buf.len() > buf.len() {
|
||||
let mut reader = inner_buf.as_ref();
|
||||
let read = reader.read_exact(buf).map(|_| buf.len())?;
|
||||
inner_buf.advance(read);
|
||||
return Ok(read);
|
||||
} else {
|
||||
let mut reader = inner_buf.as_ref();
|
||||
let read = reader.read(buf).map(|_| buf_len as usize)?;
|
||||
inner_buf.advance(read);
|
||||
return Ok(read);
|
||||
}
|
||||
}
|
||||
}
|
||||
let rx = self.rx.lock().unwrap();
|
||||
|
||||
// We need to figure out whether we need to block here.
|
||||
// The problem is that in cases of multiple buffered reads like:
|
||||
//
|
||||
// println!("abc");
|
||||
// println!("def");
|
||||
//
|
||||
// get_stdout() // would only return "abc\n" instead of "abc\ndef\n"
|
||||
|
||||
let data = match rx.try_recv() {
|
||||
Ok(mut s) => {
|
||||
s.append(&mut rx.try_iter().flat_map(|f| f.into_iter()).collect());
|
||||
s
|
||||
}
|
||||
Err(_) => {
|
||||
if !self.block {
|
||||
// If self.block is explicitly set to false, never block
|
||||
Vec::new()
|
||||
} else {
|
||||
// could not immediately receive bytes, so we need to block
|
||||
match rx.recv() {
|
||||
Ok(o) => o,
|
||||
// Errors can happen if the sender has been dropped already
|
||||
// In this case, just return 0 to indicate that we can't read any
|
||||
// bytes anymore
|
||||
Err(_) => {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if data.is_empty() && self.read_buffer.as_ref().map(|s| s.len()).unwrap_or(0) == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let data = rx.recv().map_err(|_| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::BrokenPipe,
|
||||
"the wasi pipe is not connected".to_string(),
|
||||
)
|
||||
})?;
|
||||
self.read_buffer.replace(Bytes::from(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualFile for WasiPipe {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn last_modified(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn created_time(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn size(&self) -> u64 {
|
||||
self.read_buffer
|
||||
.as_ref()
|
||||
.map(|s| s.len() as u64)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
fn set_len(&mut self, _: u64) -> Result<(), FsError> {
|
||||
Ok(())
|
||||
}
|
||||
fn unlink(&mut self) -> Result<(), FsError> {
|
||||
Ok(())
|
||||
}
|
||||
fn bytes_available_read(&self) -> Result<Option<usize>, FsError> {
|
||||
Ok(Some(
|
||||
self.read_buffer
|
||||
.as_ref()
|
||||
.map(|s| s.len())
|
||||
.unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(all(unix, feature = "sys-poll"))]
|
||||
use std::convert::TryInto;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
io::{self, Read, Seek, Write},
|
||||
sync::{Arc, Mutex},
|
||||
time::Duration,
|
||||
};
|
||||
use wasmer_vbus::BusError;
|
||||
use wasmer_wasi_types::wasi::{BusErrno, Errno};
|
||||
|
||||
@@ -371,11 +376,79 @@ pub(crate) fn poll(
|
||||
|
||||
pub trait WasiPath {}
|
||||
|
||||
#[deprecated(
|
||||
since = "3.0.0-beta.2",
|
||||
note = "Moved to `wasmer_wasi::pipe::WasiBidirectionalSharedPipePair`, `Pipe` is only a transitional reexport"
|
||||
)]
|
||||
pub use crate::state::WasiBidirectionalSharedPipePair as Pipe;
|
||||
/// For piping stdio. Stores all output / input in a byte-vector.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||
pub struct Pipe {
|
||||
buffer: Arc<Mutex<VecDeque<u8>>>,
|
||||
}
|
||||
|
||||
impl Pipe {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Pipe {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let mut buffer = self.buffer.lock().unwrap();
|
||||
let amt = std::cmp::min(buf.len(), buffer.len());
|
||||
let buf_iter = buffer.drain(..amt).enumerate();
|
||||
for (i, byte) in buf_iter {
|
||||
buf[i] = byte;
|
||||
}
|
||||
Ok(amt)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Pipe {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
let mut buffer = self.buffer.lock().unwrap();
|
||||
buffer.extend(buf);
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for Pipe {
|
||||
fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"can not seek in a pipe",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
//#[cfg_attr(feature = "enable-serde", typetag::serde)]
|
||||
impl VirtualFile for Pipe {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn last_modified(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn created_time(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn size(&self) -> u64 {
|
||||
let buffer = self.buffer.lock().unwrap();
|
||||
buffer.len() as u64
|
||||
}
|
||||
fn set_len(&mut self, len: u64) -> Result<(), FsError> {
|
||||
let mut buffer = self.buffer.lock().unwrap();
|
||||
buffer.resize(len as usize, 0);
|
||||
Ok(())
|
||||
}
|
||||
fn unlink(&mut self) -> Result<(), FsError> {
|
||||
Ok(())
|
||||
}
|
||||
fn bytes_available_read(&self) -> Result<Option<usize>, FsError> {
|
||||
let buffer = self.buffer.lock().unwrap();
|
||||
Ok(Some(buffer.len()))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Think about using this
|
||||
|
||||
@@ -43,7 +43,7 @@ use crate::{
|
||||
state::{
|
||||
self, fs_error_into_wasi_err, iterate_poll_events, net_error_into_wasi_err, poll,
|
||||
virtual_file_type_to_wasi_file_type, Inode, InodeSocket, InodeSocketKind, InodeVal, Kind,
|
||||
PollEvent, PollEventBuilder, WasiBidirectionalPipePair, WasiState, MAX_SYMLINKS,
|
||||
PollEvent, PollEventBuilder, WasiPipe, WasiState, MAX_SYMLINKS,
|
||||
},
|
||||
Fd, WasiEnv, WasiError, WasiThread, WasiThreadId,
|
||||
};
|
||||
@@ -1804,9 +1804,7 @@ pub fn fd_pipe<M: MemorySize>(
|
||||
let env = ctx.data();
|
||||
let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
|
||||
|
||||
let pipes = WasiBidirectionalPipePair::new();
|
||||
let pipe1 = pipes.send;
|
||||
let pipe2 = pipes.recv;
|
||||
let (pipe1, pipe2) = WasiPipe::new();
|
||||
|
||||
let inode1 = state.fs.create_inode_with_default_stat(
|
||||
inodes.deref_mut(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use wasmer::{Instance, Module, Store};
|
||||
use wasmer_wasi::{WasiBidirectionalSharedPipePair, WasiState};
|
||||
use wasmer_wasi::{Pipe, WasiState};
|
||||
|
||||
mod sys {
|
||||
#[test]
|
||||
@@ -73,10 +73,10 @@ fn test_stdout() {
|
||||
"#).unwrap();
|
||||
|
||||
// Create the `WasiEnv`.
|
||||
let mut pipe = WasiBidirectionalSharedPipePair::new().with_blocking(false);
|
||||
let mut stdout = Pipe::default();
|
||||
let wasi_env = WasiState::new("command-name")
|
||||
.args(&["Gordon"])
|
||||
.stdout(Box::new(pipe.clone()))
|
||||
.stdout(Box::new(stdout.clone()))
|
||||
.finalize(&mut store)
|
||||
.unwrap();
|
||||
|
||||
@@ -93,7 +93,7 @@ fn test_stdout() {
|
||||
start.call(&mut store, &[]).unwrap();
|
||||
|
||||
let mut stdout_str = String::new();
|
||||
pipe.read_to_string(&mut stdout_str).unwrap();
|
||||
stdout.read_to_string(&mut stdout_str).unwrap();
|
||||
let stdout_as_str = stdout_str.as_str();
|
||||
assert_eq!(stdout_as_str, "hello world\n");
|
||||
}
|
||||
@@ -110,7 +110,7 @@ fn test_env() {
|
||||
});
|
||||
|
||||
// Create the `WasiEnv`.
|
||||
let mut pipe = WasiBidirectionalSharedPipePair::new().with_blocking(false);
|
||||
let mut stdout = Pipe::new();
|
||||
let mut wasi_state_builder = WasiState::new("command-name");
|
||||
wasi_state_builder
|
||||
.args(&["Gordon"])
|
||||
@@ -119,7 +119,7 @@ fn test_env() {
|
||||
.env("TEST2", "VALUE2");
|
||||
// panic!("envs: {:?}", wasi_state_builder.envs);
|
||||
let wasi_env = wasi_state_builder
|
||||
.stdout(Box::new(pipe.clone()))
|
||||
.stdout(Box::new(stdout.clone()))
|
||||
.finalize(&mut store)
|
||||
.unwrap();
|
||||
|
||||
@@ -136,7 +136,7 @@ fn test_env() {
|
||||
start.call(&mut store, &[]).unwrap();
|
||||
|
||||
let mut stdout_str = String::new();
|
||||
pipe.read_to_string(&mut stdout_str).unwrap();
|
||||
stdout.read_to_string(&mut stdout_str).unwrap();
|
||||
let stdout_as_str = stdout_str.as_str();
|
||||
assert_eq!(stdout_as_str, "Env vars:\nDOG=X\nTEST2=VALUE2\nTEST=VALUE\nDOG Ok(\"X\")\nDOG_TYPE Err(NotPresent)\nSET VAR Ok(\"HELLO\")\n");
|
||||
}
|
||||
@@ -146,16 +146,15 @@ fn test_stdin() {
|
||||
let module = Module::new(&store, include_bytes!("stdin-hello.wasm")).unwrap();
|
||||
|
||||
// Create the `WasiEnv`.
|
||||
let mut pipe = WasiBidirectionalSharedPipePair::new().with_blocking(false);
|
||||
let mut stdin = Pipe::new();
|
||||
let wasi_env = WasiState::new("command-name")
|
||||
.stdin(Box::new(stdin.clone()))
|
||||
.finalize(&mut store)
|
||||
.unwrap();
|
||||
|
||||
// Write to STDIN
|
||||
let buf = "Hello, stdin!\n".as_bytes().to_owned();
|
||||
pipe.write(&buf[..]).unwrap();
|
||||
|
||||
let wasi_env = WasiState::new("command-name")
|
||||
.stdin(Box::new(pipe.clone()))
|
||||
.finalize(&mut store)
|
||||
.unwrap();
|
||||
stdin.write(&buf[..]).unwrap();
|
||||
|
||||
// Generate an `ImportObject`.
|
||||
let import_object = wasi_env.import_object(&mut store, &module).unwrap();
|
||||
@@ -168,10 +167,10 @@ fn test_stdin() {
|
||||
// Let's call the `_start` function, which is our `main` function in Rust.
|
||||
let start = instance.exports.get_function("_start").unwrap();
|
||||
let result = start.call(&mut store, &[]);
|
||||
assert!(result.is_ok());
|
||||
assert!(!result.is_err());
|
||||
|
||||
// We assure stdin is now empty
|
||||
let mut buf = Vec::new();
|
||||
pipe.read_to_end(&mut buf).unwrap();
|
||||
stdin.read_to_end(&mut buf).unwrap();
|
||||
assert_eq!(buf.len(), 0);
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ fn create_obj(args: Vec<&'static str>, keyword_needle: &str, keyword: &str) -> a
|
||||
let object_path = operating_dir.join("wasm.obj");
|
||||
|
||||
let output: Vec<u8> = WasmerCreateObj {
|
||||
current_dir: operating_dir,
|
||||
current_dir: operating_dir.clone(),
|
||||
wasm_path,
|
||||
output_object_path: object_path.clone(),
|
||||
compiler: Compiler::Cranelift,
|
||||
@@ -292,7 +292,7 @@ fn create_obj(args: Vec<&'static str>, keyword_needle: &str, keyword: &str) -> a
|
||||
"create-obj successfully completed but object output file `{}` missing",
|
||||
object_path.display()
|
||||
);
|
||||
let mut object_header_path = object_path;
|
||||
let mut object_header_path = object_path.clone();
|
||||
object_header_path.set_extension("h");
|
||||
assert!(
|
||||
object_header_path.exists(),
|
||||
|
||||
@@ -40,8 +40,9 @@ mod tests {
|
||||
*/
|
||||
let command_success = command.status.success();
|
||||
let test_success = !stderr.contains("** TEST FAILED **");
|
||||
let success = command_success && test_success;
|
||||
|
||||
command_success && test_success
|
||||
success
|
||||
}
|
||||
|
||||
fn remove_existing_artificats() -> Output {
|
||||
|
||||
@@ -7,8 +7,8 @@ use wasmer::{FunctionEnv, Imports, Instance, Module, Store};
|
||||
use wasmer_vfs::{host_fs, mem_fs, FileSystem};
|
||||
use wasmer_wasi::types::wasi::{Filesize, Timestamp};
|
||||
use wasmer_wasi::{
|
||||
generate_import_object_from_env, get_wasi_version, FsError, VirtualFile,
|
||||
WasiBidirectionalPipePair, WasiEnv, WasiFunctionEnv, WasiState, WasiVersion,
|
||||
generate_import_object_from_env, get_wasi_version, FsError, Pipe, VirtualFile, WasiEnv,
|
||||
WasiFunctionEnv, WasiState, WasiVersion,
|
||||
};
|
||||
use wast::parser::{self, Parse, ParseBuffer, Parser};
|
||||
|
||||
@@ -142,7 +142,7 @@ impl<'a> WasiTest<'a> {
|
||||
)> {
|
||||
let mut builder = WasiState::new(self.wasm_path);
|
||||
|
||||
let stdin_pipe = WasiBidirectionalPipePair::new().with_blocking(false);
|
||||
let stdin_pipe = Pipe::new();
|
||||
builder.stdin(Box::new(stdin_pipe));
|
||||
|
||||
for (name, value) in &self.envs {
|
||||
|
||||
Reference in New Issue
Block a user