Many performance and memory optimizations

- Avoiding a memory copy on all socket reads and writes using a new `copy_from_slice` instead
- File openers no longer box the implementation avoiding a memory allocation on all file access
- Polling sockets rather than using an async function which significantly reduces locking contention and removes an box operation
- Futex now uses wakers rather than broadcasts which makes them more efficient and durable
- Converted many async functions into sync functions in vnet
- Sleeping no longer allocates memory
- Avoiding a number of WasiEnv clones which was impacting performance and memory efficiency
This commit is contained in:
Johnathan Sharratt
2023-02-05 10:16:41 +11:00
parent 97445c4f0a
commit 9bc44d49a2
71 changed files with 2040 additions and 2137 deletions

View File

@@ -135,6 +135,9 @@ coverage = []
[profile.dev] [profile.dev]
split-debuginfo = "unpacked" split-debuginfo = "unpacked"
#[profile.release]
#debug = true
[[bench]] [[bench]]
name = "static_and_dynamic_functions" name = "static_and_dynamic_functions"
harness = false harness = false

View File

@@ -311,6 +311,17 @@ impl<'a, T: ValueType> WasmSlice<'a, T> {
self.buffer.write(self.offset, bytes) self.buffer.write(self.offset, bytes)
} }
/// Reads this `WasmSlice` into a `slice`.
#[inline]
pub fn read_to_slice<'b>(
self,
buf: &'b mut [MaybeUninit<u8>],
) -> Result<usize, MemoryAccessError> {
let len = self.len.try_into().expect("WasmSlice length overflow");
self.buffer.read_uninit(self.offset, buf)?;
Ok(len)
}
/// Reads this `WasmSlice` into a `Vec`. /// Reads this `WasmSlice` into a `Vec`.
#[inline] #[inline]
pub fn read_to_vec(self) -> Result<Vec<T>, MemoryAccessError> { pub fn read_to_vec(self) -> Result<Vec<T>, MemoryAccessError> {

View File

@@ -313,6 +313,17 @@ impl<'a, T: ValueType> WasmSlice<'a, T> {
self.buffer.write(self.offset, bytes) self.buffer.write(self.offset, bytes)
} }
/// Reads this `WasmSlice` into a `slice`.
#[inline]
pub fn copy_to_slice<'b>(
self,
buf: &'b mut [MaybeUninit<u8>],
) -> Result<usize, MemoryAccessError> {
let len = self.len.try_into().expect("WasmSlice length overflow");
self.buffer.read_uninit(self.offset, buf)?;
Ok(len)
}
/// Reads this `WasmSlice` into a `Vec`. /// Reads this `WasmSlice` into a `Vec`.
#[inline] #[inline]
pub fn read_to_vec(self) -> Result<Vec<T>, MemoryAccessError> { pub fn read_to_vec(self) -> Result<Vec<T>, MemoryAccessError> {

View File

@@ -41,14 +41,14 @@ impl FileSystem for EmptyFileSystem {
} }
fn new_open_options(&self) -> OpenOptions { fn new_open_options(&self) -> OpenOptions {
OpenOptions::new(Box::new(EmptyFileSystem::default())) OpenOptions::new(self)
} }
} }
impl FileOpener for EmptyFileSystem { impl FileOpener for EmptyFileSystem {
#[allow(unused_variables)] #[allow(unused_variables)]
fn open( fn open(
&mut self, &self,
path: &Path, path: &Path,
conf: &OpenOptionsConfig, conf: &OpenOptionsConfig,
) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>> { ) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>> {

View File

@@ -120,7 +120,7 @@ impl crate::FileSystem for FileSystem {
} }
fn new_open_options(&self) -> OpenOptions { fn new_open_options(&self) -> OpenOptions {
OpenOptions::new(Box::new(FileOpener)) OpenOptions::new(self)
} }
fn metadata(&self, path: &Path) -> Result<Metadata> { fn metadata(&self, path: &Path) -> Result<Metadata> {
@@ -188,12 +188,9 @@ impl TryInto<Metadata> for std::fs::Metadata {
} }
} }
#[derive(Debug, Clone)] impl crate::FileOpener for FileSystem {
pub struct FileOpener;
impl crate::FileOpener for FileOpener {
fn open( fn open(
&mut self, &self,
path: &Path, path: &Path,
conf: &OpenOptionsConfig, conf: &OpenOptionsConfig,
) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>> { ) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>> {

View File

@@ -80,7 +80,7 @@ impl dyn FileSystem + 'static {
pub trait FileOpener { pub trait FileOpener {
fn open( fn open(
&mut self, &self,
path: &Path, path: &Path,
conf: &OpenOptionsConfig, conf: &OpenOptionsConfig,
) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>>; ) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>>;
@@ -134,19 +134,19 @@ impl OpenOptionsConfig {
} }
} }
impl fmt::Debug for OpenOptions { impl<'a> fmt::Debug for OpenOptions<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.conf.fmt(f) self.conf.fmt(f)
} }
} }
pub struct OpenOptions { pub struct OpenOptions<'a> {
opener: Box<dyn FileOpener>, opener: &'a dyn FileOpener,
conf: OpenOptionsConfig, conf: OpenOptionsConfig,
} }
impl OpenOptions { impl<'a> OpenOptions<'a> {
pub fn new(opener: Box<dyn FileOpener>) -> Self { pub fn new(opener: &'a dyn FileOpener) -> Self {
Self { Self {
opener, opener,
conf: OpenOptionsConfig { conf: OpenOptionsConfig {

View File

@@ -5,17 +5,11 @@ use std::borrow::Cow;
use std::path::Path; use std::path::Path;
use tracing::*; use tracing::*;
/// The type that is responsible to open a file. impl FileSystem {
#[derive(Debug, Clone)]
pub struct FileOpener {
pub(super) filesystem: FileSystem,
}
impl FileOpener {
/// Inserts a readonly file into the file system that uses copy-on-write /// Inserts a readonly file into the file system that uses copy-on-write
/// (this is required for zero-copy creation of the same file) /// (this is required for zero-copy creation of the same file)
pub fn insert_ro_file(&mut self, path: &Path, contents: Cow<'static, [u8]>) -> Result<()> { pub fn insert_ro_file(&self, path: &Path, contents: Cow<'static, [u8]>) -> Result<()> {
let _ = crate::FileSystem::remove_file(&self.filesystem, path); let _ = crate::FileSystem::remove_file(self, path);
let (inode_of_parent, maybe_inode_of_file, name_of_file) = self.insert_inode(path)?; let (inode_of_parent, maybe_inode_of_file, name_of_file) = self.insert_inode(path)?;
let inode_of_parent = match inode_of_parent { let inode_of_parent = match inode_of_parent {
@@ -32,7 +26,7 @@ impl FileOpener {
// The file doesn't already exist; it's OK to create it if // The file doesn't already exist; it's OK to create it if
None => { None => {
// Write lock. // Write lock.
let mut fs = self.filesystem.inner.write().map_err(|_| FsError::Lock)?; let mut fs = self.inner.write().map_err(|_| FsError::Lock)?;
let file = ReadOnlyFile::new(contents); let file = ReadOnlyFile::new(contents);
let file_len = file.len() as u64; let file_len = file.len() as u64;
@@ -76,11 +70,11 @@ impl FileOpener {
/// Inserts a arc file into the file system that references another file /// Inserts a arc file into the file system that references another file
/// in another file system (does not copy the real data) /// in another file system (does not copy the real data)
pub fn insert_arc_file( pub fn insert_arc_file(
&mut self, &self,
path: PathBuf, path: PathBuf,
fs: Arc<dyn crate::FileSystem + Send + Sync>, fs: Arc<dyn crate::FileSystem + Send + Sync>,
) -> Result<()> { ) -> Result<()> {
let _ = crate::FileSystem::remove_file(&self.filesystem, path.as_path()); let _ = crate::FileSystem::remove_file(self, path.as_path());
let (inode_of_parent, maybe_inode_of_file, name_of_file) = let (inode_of_parent, maybe_inode_of_file, name_of_file) =
self.insert_inode(path.as_path())?; self.insert_inode(path.as_path())?;
@@ -98,7 +92,7 @@ impl FileOpener {
// The file doesn't already exist; it's OK to create it if // The file doesn't already exist; it's OK to create it if
None => { None => {
// Write lock. // Write lock.
let mut fs_lock = self.filesystem.inner.write().map_err(|_| FsError::Lock)?; let mut fs_lock = self.inner.write().map_err(|_| FsError::Lock)?;
// Read the metadata or generate a dummy one // Read the metadata or generate a dummy one
let meta = match fs.metadata(&path) { let meta = match fs.metadata(&path) {
@@ -145,11 +139,11 @@ impl FileOpener {
/// Inserts a arc directory into the file system that references another file /// Inserts a arc directory into the file system that references another file
/// in another file system (does not copy the real data) /// in another file system (does not copy the real data)
pub fn insert_arc_directory( pub fn insert_arc_directory(
&mut self, &self,
path: PathBuf, path: PathBuf,
fs: Arc<dyn crate::FileSystem + Send + Sync>, fs: Arc<dyn crate::FileSystem + Send + Sync>,
) -> Result<()> { ) -> Result<()> {
let _ = crate::FileSystem::remove_dir(&self.filesystem, path.as_path()); let _ = crate::FileSystem::remove_dir(self, path.as_path());
let (inode_of_parent, maybe_inode_of_file, name_of_file) = let (inode_of_parent, maybe_inode_of_file, name_of_file) =
self.insert_inode(path.as_path())?; self.insert_inode(path.as_path())?;
@@ -167,7 +161,7 @@ impl FileOpener {
// The file doesn't already exist; it's OK to create it if // The file doesn't already exist; it's OK to create it if
None => { None => {
// Write lock. // Write lock.
let mut fs_lock = self.filesystem.inner.write().map_err(|_| FsError::Lock)?; let mut fs_lock = self.inner.write().map_err(|_| FsError::Lock)?;
// Creating the file in the storage. // Creating the file in the storage.
let inode_of_file = fs_lock.storage.vacant_entry().key(); let inode_of_file = fs_lock.storage.vacant_entry().key();
@@ -209,11 +203,11 @@ impl FileOpener {
/// Inserts a arc file into the file system that references another file /// Inserts a arc file into the file system that references another file
/// in another file system (does not copy the real data) /// in another file system (does not copy the real data)
pub fn insert_custom_file( pub fn insert_custom_file(
&mut self, &self,
path: PathBuf, path: PathBuf,
file: Box<dyn crate::VirtualFile + Send + Sync>, file: Box<dyn crate::VirtualFile + Send + Sync>,
) -> Result<()> { ) -> Result<()> {
let _ = crate::FileSystem::remove_file(&self.filesystem, path.as_path()); let _ = crate::FileSystem::remove_file(self, path.as_path());
let (inode_of_parent, maybe_inode_of_file, name_of_file) = let (inode_of_parent, maybe_inode_of_file, name_of_file) =
self.insert_inode(path.as_path())?; self.insert_inode(path.as_path())?;
@@ -231,7 +225,7 @@ impl FileOpener {
// The file doesn't already exist; it's OK to create it if // The file doesn't already exist; it's OK to create it if
None => { None => {
// Write lock. // Write lock.
let mut fs_lock = self.filesystem.inner.write().map_err(|_| FsError::Lock)?; let mut fs_lock = self.inner.write().map_err(|_| FsError::Lock)?;
// Creating the file in the storage. // Creating the file in the storage.
let inode_of_file = fs_lock.storage.vacant_entry().key(); let inode_of_file = fs_lock.storage.vacant_entry().key();
@@ -269,11 +263,11 @@ impl FileOpener {
} }
fn insert_inode( fn insert_inode(
&mut self, &self,
path: &Path, path: &Path,
) -> Result<(InodeResolution, Option<InodeResolution>, OsString)> { ) -> Result<(InodeResolution, Option<InodeResolution>, OsString)> {
// Read lock. // Read lock.
let fs = self.filesystem.inner.read().map_err(|_| FsError::Lock)?; let fs = self.inner.read().map_err(|_| FsError::Lock)?;
// Check the path has a parent. // Check the path has a parent.
let parent_of_path = path.parent().ok_or(FsError::BaseNotDirectory)?; let parent_of_path = path.parent().ok_or(FsError::BaseNotDirectory)?;
@@ -309,9 +303,9 @@ impl FileOpener {
} }
} }
impl crate::FileOpener for FileOpener { impl crate::FileOpener for FileSystem {
fn open( fn open(
&mut self, &self,
path: &Path, path: &Path,
conf: &OpenOptionsConfig, conf: &OpenOptionsConfig,
) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>> { ) -> Result<Box<dyn VirtualFile + Send + Sync + 'static>> {
@@ -370,7 +364,7 @@ impl crate::FileOpener for FileOpener {
}; };
// Write lock. // Write lock.
let mut fs = self.filesystem.inner.write().map_err(|_| FsError::Lock)?; let mut fs = self.inner.write().map_err(|_| FsError::Lock)?;
let inode = fs.storage.get_mut(inode_of_file); let inode = fs.storage.get_mut(inode_of_file);
match inode { match inode {
@@ -456,7 +450,7 @@ impl crate::FileOpener for FileOpener {
// 2. `create` is used with `write` or `append`. // 2. `create` is used with `write` or `append`.
None if (create_new || create) && (write || append) => { None if (create_new || create) && (write || append) => {
// Write lock. // Write lock.
let mut fs = self.filesystem.inner.write().map_err(|_| FsError::Lock)?; let mut fs = self.inner.write().map_err(|_| FsError::Lock)?;
let file = File::new(); let file = File::new();
@@ -500,7 +494,7 @@ impl crate::FileOpener for FileOpener {
Ok(Box::new(FileHandle::new( Ok(Box::new(FileHandle::new(
inode_of_file, inode_of_file,
self.filesystem.clone(), self.clone(),
read, read,
write || append || truncate, write || append || truncate,
append, append,

View File

@@ -21,10 +21,8 @@ pub struct FileSystem {
} }
impl FileSystem { impl FileSystem {
pub fn new_open_options_ext(&self) -> FileOpener { pub fn new_open_options_ext(&self) -> &FileSystem {
FileOpener { self
filesystem: self.clone(),
}
} }
pub fn union(&self, other: &Arc<dyn crate::FileSystem + Send + Sync>) { pub fn union(&self, other: &Arc<dyn crate::FileSystem + Send + Sync>) {
@@ -526,9 +524,7 @@ impl crate::FileSystem for FileSystem {
} }
fn new_open_options(&self) -> OpenOptions { fn new_open_options(&self) -> OpenOptions {
OpenOptions::new(Box::new(FileOpener { OpenOptions::new(self)
filesystem: self.clone(),
}))
} }
} }

View File

@@ -4,7 +4,6 @@ mod filesystem;
mod stdio; mod stdio;
use file::{File, FileHandle, ReadOnlyFile}; use file::{File, FileHandle, ReadOnlyFile};
pub use file_opener::FileOpener;
pub use filesystem::FileSystem; pub use filesystem::FileSystem;
pub use stdio::{Stderr, Stdin, Stdout}; pub use stdio::{Stderr, Stdin, Stdout};

View File

@@ -43,16 +43,9 @@ impl StaticFileSystem {
} }
/// Custom file opener, returns a WebCFile /// Custom file opener, returns a WebCFile
#[derive(Debug)] impl FileOpener for StaticFileSystem {
struct WebCFileOpener {
pub package: String,
pub volumes: Arc<webc::IndexMap<String, webc::Volume<'static>>>,
pub memory: Arc<MemFileSystem>,
}
impl FileOpener for WebCFileOpener {
fn open( fn open(
&mut self, &self,
path: &Path, path: &Path,
_conf: &OpenOptionsConfig, _conf: &OpenOptionsConfig,
) -> Result<Box<dyn VirtualFile + Send + Sync>, FsError> { ) -> Result<Box<dyn VirtualFile + Send + Sync>, FsError> {
@@ -338,11 +331,7 @@ impl FileSystem for StaticFileSystem {
} }
} }
fn new_open_options(&self) -> OpenOptions { fn new_open_options(&self) -> OpenOptions {
OpenOptions::new(Box::new(WebCFileOpener { OpenOptions::new(self)
package: self.package.clone(),
volumes: self.volumes.clone(),
memory: self.memory.clone(),
}))
} }
fn symlink_metadata(&self, path: &Path) -> Result<Metadata, FsError> { fn symlink_metadata(&self, path: &Path) -> Result<Metadata, FsError> {
let path = normalizes_path(path); let path = normalizes_path(path);

View File

@@ -30,7 +30,7 @@ impl TmpFileSystem {
Self::default() Self::default()
} }
pub fn new_open_options_ext(&self) -> mem_fs::FileOpener { pub fn new_open_options_ext(&self) -> &mem_fs::FileSystem {
self.fs.new_open_options_ext() self.fs.new_open_options_ext()
} }

View File

@@ -364,10 +364,7 @@ impl FileSystem for UnionFileSystem {
Err(ret_error) Err(ret_error)
} }
fn new_open_options(&self) -> OpenOptions { fn new_open_options(&self) -> OpenOptions {
let opener = Box::new(UnionFileOpener { OpenOptions::new(self)
mounts: self.mounts.clone(),
});
OpenOptions::new(opener)
} }
} }
@@ -413,14 +410,9 @@ fn filter_mounts(
ret.into_iter() ret.into_iter()
} }
#[derive(Debug)] impl FileOpener for UnionFileSystem {
pub struct UnionFileOpener {
mounts: Vec<MountPoint>,
}
impl FileOpener for UnionFileOpener {
fn open( fn open(
&mut self, &self,
path: &Path, path: &Path,
conf: &OpenOptionsConfig, conf: &OpenOptionsConfig,
) -> Result<Box<dyn VirtualFile + Send + Sync>> { ) -> Result<Box<dyn VirtualFile + Send + Sync>> {

View File

@@ -46,23 +46,13 @@ where
} }
/// Custom file opener, returns a WebCFile /// Custom file opener, returns a WebCFile
#[derive(Debug)] impl<T> FileOpener for WebcFileSystem<T>
struct WebCFileOpener<T>
where
T: std::fmt::Debug + Send + Sync + 'static,
{
pub package: String,
pub webc: Arc<T>,
pub memory: Arc<MemFileSystem>,
}
impl<T> FileOpener for WebCFileOpener<T>
where where
T: std::fmt::Debug + Send + Sync + 'static, T: std::fmt::Debug + Send + Sync + 'static,
T: Deref<Target = WebC<'static>>, T: Deref<Target = WebC<'static>>,
{ {
fn open( fn open(
&mut self, &self,
path: &Path, path: &Path,
_conf: &OpenOptionsConfig, _conf: &OpenOptionsConfig,
) -> Result<Box<dyn VirtualFile + Send + Sync>, FsError> { ) -> Result<Box<dyn VirtualFile + Send + Sync>, FsError> {
@@ -357,11 +347,7 @@ where
} }
} }
fn new_open_options(&self) -> OpenOptions { fn new_open_options(&self) -> OpenOptions {
OpenOptions::new(Box::new(WebCFileOpener { OpenOptions::new(self)
package: self.package.clone(),
webc: self.webc.clone(),
memory: self.memory.clone(),
}))
} }
fn symlink_metadata(&self, path: &Path) -> Result<Metadata, FsError> { fn symlink_metadata(&self, path: &Path) -> Result<Metadata, FsError> {
let path = normalizes_path(path); let path = normalizes_path(path);

View File

@@ -1,10 +1,13 @@
use std::fmt; use std::fmt;
use std::mem::MaybeUninit;
use std::net::IpAddr; use std::net::IpAddr;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::net::Ipv6Addr; use std::net::Ipv6Addr;
use std::net::Shutdown; use std::net::Shutdown;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::Arc; use std::sync::Arc;
use std::task::Context;
use std::task::Poll;
use std::time::Duration; use std::time::Duration;
use thiserror::Error; use thiserror::Error;
@@ -62,37 +65,37 @@ pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static {
} }
/// Adds a static IP address to the interface with a netmask prefix /// Adds a static IP address to the interface with a netmask prefix
async fn ip_add(&self, ip: IpAddr, prefix: u8) -> Result<()> { fn ip_add(&self, ip: IpAddr, prefix: u8) -> Result<()> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
/// Removes a static (or dynamic) IP address from the interface /// Removes a static (or dynamic) IP address from the interface
async fn ip_remove(&self, ip: IpAddr) -> Result<()> { fn ip_remove(&self, ip: IpAddr) -> Result<()> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
/// Clears all the assigned IP addresses for this interface /// Clears all the assigned IP addresses for this interface
async fn ip_clear(&self) -> Result<()> { fn ip_clear(&self) -> Result<()> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
/// Lists all the IP addresses currently assigned to this interface /// Lists all the IP addresses currently assigned to this interface
async fn ip_list(&self) -> Result<Vec<IpCidr>> { fn ip_list(&self) -> Result<Vec<IpCidr>> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
/// Returns the hardware MAC address for this interface /// Returns the hardware MAC address for this interface
async fn mac(&self) -> Result<[u8; 6]> { fn mac(&self) -> Result<[u8; 6]> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
/// Adds a default gateway to the routing table /// Adds a default gateway to the routing table
async fn gateway_set(&self, ip: IpAddr) -> Result<()> { fn gateway_set(&self, ip: IpAddr) -> Result<()> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
/// Adds a specific route to the routing table /// Adds a specific route to the routing table
async fn route_add( fn route_add(
&self, &self,
cidr: IpCidr, cidr: IpCidr,
via_router: IpAddr, via_router: IpAddr,
@@ -103,17 +106,17 @@ pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static {
} }
/// Removes a routing rule from the routing table /// Removes a routing rule from the routing table
async fn route_remove(&self, cidr: IpAddr) -> Result<()> { fn route_remove(&self, cidr: IpAddr) -> Result<()> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
/// Clears the routing table for this interface /// Clears the routing table for this interface
async fn route_clear(&self) -> Result<()> { fn route_clear(&self) -> Result<()> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
/// Lists all the routes defined in the routing table for this interface /// Lists all the routes defined in the routing table for this interface
async fn route_list(&self) -> Result<Vec<IpRoute>> { fn route_list(&self) -> Result<Vec<IpRoute>> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
@@ -159,7 +162,6 @@ pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static {
&self, &self,
addr: SocketAddr, addr: SocketAddr,
peer: SocketAddr, peer: SocketAddr,
timeout: Option<Duration>,
) -> Result<Box<dyn VirtualTcpSocket + Sync>> { ) -> Result<Box<dyn VirtualTcpSocket + Sync>> {
Err(NetworkError::Unsupported) Err(NetworkError::Unsupported)
} }
@@ -177,25 +179,6 @@ pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static {
pub type DynVirtualNetworking = Arc<dyn VirtualNetworking>; pub type DynVirtualNetworking = Arc<dyn VirtualNetworking>;
#[derive(Debug, Clone)]
pub struct SocketReceive {
/// Data that was received
pub data: Bytes,
/// Indicates if the data was truncated (e.g. UDP packet)
pub truncated: bool,
}
#[derive(Debug, Clone)]
pub struct SocketReceiveFrom {
/// Data that was received
pub data: Bytes,
/// Indicates if the data was truncated (e.g. UDP packet)
pub truncated: bool,
/// Peer sender address of the data
pub addr: SocketAddr,
}
#[async_trait::async_trait]
pub trait VirtualTcpListener: fmt::Debug + Send + Sync + 'static { pub trait VirtualTcpListener: fmt::Debug + Send + Sync + 'static {
/// Tries to accept a new connection /// Tries to accept a new connection
fn try_accept(&mut self) -> Option<Result<(Box<dyn VirtualTcpSocket + Sync>, SocketAddr)>>; fn try_accept(&mut self) -> Option<Result<(Box<dyn VirtualTcpSocket + Sync>, SocketAddr)>>;
@@ -212,38 +195,19 @@ pub trait VirtualTcpListener: fmt::Debug + Send + Sync + 'static {
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<usize>>; ) -> std::task::Poll<Result<usize>>;
/// Sets the accept timeout
fn set_timeout(&mut self, timeout: Option<Duration>) -> Result<()>;
/// Gets the accept timeout
fn timeout(&self) -> Result<Option<Duration>>;
/// Returns the local address of this TCP listener /// Returns the local address of this TCP listener
fn addr_local(&self) -> Result<SocketAddr>; fn addr_local(&self) -> Result<SocketAddr>;
/// Sets how many network hops the packets are permitted for new connections /// Sets how many network hops the packets are permitted for new connections
async fn set_ttl(&mut self, ttl: u8) -> Result<()>; fn set_ttl(&mut self, ttl: u8) -> Result<()>;
/// Returns the maximum number of network hops before packets are dropped /// Returns the maximum number of network hops before packets are dropped
fn ttl(&self) -> Result<u8>; fn ttl(&self) -> Result<u8>;
/// Determines if the socket is blocking or not
fn set_nonblocking(&mut self, nonblocking: bool) -> Result<()>;
// Returns true if the socket is nonblocking
fn nonblocking(&self) -> Result<bool>;
} }
#[async_trait::async_trait]
pub trait VirtualSocket: fmt::Debug + Send + Sync + 'static { pub trait VirtualSocket: fmt::Debug + Send + Sync + 'static {
/// Sets how many network hops the packets are permitted for new connections /// Sets how many network hops the packets are permitted for new connections
async fn set_ttl(&mut self, ttl: u32) -> Result<()>; fn set_ttl(&mut self, ttl: u32) -> Result<()>;
/// Determines if the socket is blocking or not
fn set_nonblocking(&mut self, nonblocking: bool) -> Result<()>;
// Returns true if the socket is nonblocking
fn nonblocking(&self) -> Result<bool>;
/// Returns the maximum number of network hops before packets are dropped /// Returns the maximum number of network hops before packets are dropped
fn ttl(&self) -> Result<u32>; fn ttl(&self) -> Result<u32>;
@@ -284,19 +248,22 @@ pub enum StreamSecurity {
} }
/// Interface used for sending and receiving data from a web socket /// Interface used for sending and receiving data from a web socket
#[async_trait::async_trait]
pub trait VirtualWebSocket: fmt::Debug + Send + Sync + 'static { pub trait VirtualWebSocket: fmt::Debug + Send + Sync + 'static {
/// Sends out a datagram or stream of bytes on this socket /// Sends out a datagram or stream of bytes on this socket
async fn send(&mut self, data: Bytes) -> Result<usize>; fn poll_send(&mut self, cx: &mut Context<'_>, data: &[u8]) -> Poll<Result<usize>>;
/// FLushes all the datagrams /// FLushes all the datagrams
fn flush(&mut self) -> Result<()>; fn flush(&mut self) -> Result<()>;
/// Recv a packet from the socket /// Recv a packet from the socket
async fn recv(&mut self) -> Result<SocketReceive>; fn poll_recv<'a>(
&mut self,
cx: &mut Context<'_>,
buf: &'a mut [MaybeUninit<u8>],
) -> Poll<Result<usize>>;
/// Recv a packet from the socket /// Recv a packet from the socket
fn try_recv(&mut self) -> Result<Option<SocketReceive>>; fn try_recv<'a>(&mut self, buf: &'a mut [MaybeUninit<u8>]) -> Result<usize>;
/// Polls the socket for when there is data to be received /// Polls the socket for when there is data to be received
fn poll_read_ready( fn poll_read_ready(
@@ -312,7 +279,6 @@ pub trait VirtualWebSocket: fmt::Debug + Send + Sync + 'static {
} }
/// Connected sockets have a persistent connection to a remote peer /// Connected sockets have a persistent connection to a remote peer
#[async_trait::async_trait]
pub trait VirtualConnectedSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static { pub trait VirtualConnectedSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static {
/// Determines how long the socket will remain in a TIME_WAIT /// Determines how long the socket will remain in a TIME_WAIT
/// after it disconnects (only the one that initiates the close will /// after it disconnects (only the one that initiates the close will
@@ -324,63 +290,93 @@ pub trait VirtualConnectedSocket: VirtualSocket + fmt::Debug + Send + Sync + 'st
/// after it disconnects /// after it disconnects
fn linger(&self) -> Result<Option<Duration>>; fn linger(&self) -> Result<Option<Duration>>;
/// Sends out a datagram or stream of bytes on this socket /// Tries to send out a datagram or stream of bytes on this socket
async fn send(&mut self, data: Bytes) -> Result<usize>; fn try_send(&mut self, data: &[u8]) -> Result<usize>;
/// FLushes all the datagrams /// Sends out a datagram or stream of bytes on this socket
async fn flush(&mut self) -> Result<()>; fn poll_send(&mut self, cx: &mut Context<'_>, data: &[u8]) -> Poll<Result<usize>>;
/// Attempts to flush the object, ensuring that any buffered data reach
/// their destination.
fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>>;
/// Closes the socket /// Closes the socket
fn close(&mut self) -> Result<()>; fn close(&mut self) -> Result<()>;
/// Recv a packet from the socket /// Recv a packet from the socket
async fn recv(&mut self) -> Result<SocketReceive>; fn poll_recv<'a>(
&mut self,
cx: &mut Context<'_>,
buf: &'a mut [MaybeUninit<u8>],
) -> Poll<Result<usize>>;
/// Recv a packet from the socket /// Recv a packet from the socket
fn try_recv(&mut self) -> Result<Option<SocketReceive>>; fn try_recv<'a>(&mut self, buf: &'a mut [MaybeUninit<u8>]) -> Result<usize>;
} }
/// Connectionless sockets are able to send and receive datagrams and stream /// Connectionless sockets are able to send and receive datagrams and stream
/// bytes to multiple addresses at the same time (peer-to-peer) /// bytes to multiple addresses at the same time (peer-to-peer)
#[async_trait::async_trait]
pub trait VirtualConnectionlessSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static { pub trait VirtualConnectionlessSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static {
/// Sends out a datagram or stream of bytes on this socket /// Sends out a datagram or stream of bytes on this socket
/// to a specific address /// to a specific address
async fn send_to(&mut self, data: Bytes, addr: SocketAddr) -> Result<usize>; fn poll_send_to(
&mut self,
cx: &mut Context<'_>,
data: &[u8],
addr: SocketAddr,
) -> Poll<Result<usize>>;
/// Sends out a datagram or stream of bytes on this socket
/// to a specific address
fn try_send_to(&mut self, data: &[u8], addr: SocketAddr) -> Result<usize>;
/// Recv a packet from the socket /// Recv a packet from the socket
async fn recv_from(&mut self) -> Result<SocketReceiveFrom>; fn poll_recv_from<'a>(
&mut self,
cx: &mut Context<'_>,
buf: &'a mut [MaybeUninit<u8>],
) -> Poll<Result<(usize, SocketAddr)>>;
/// Recv a packet from the socket /// Recv a packet from the socket
fn try_recv_from(&mut self) -> Result<Option<SocketReceiveFrom>>; fn try_recv_from<'a>(&mut self, buf: &'a mut [MaybeUninit<u8>]) -> Result<(usize, SocketAddr)>;
} }
/// ICMP sockets are low level devices bound to a specific address /// ICMP sockets are low level devices bound to a specific address
/// that can send and receive ICMP packets /// that can send and receive ICMP packets
#[async_trait::async_trait]
pub trait VirtualIcmpSocket: pub trait VirtualIcmpSocket:
VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static
{ {
} }
#[async_trait::async_trait]
pub trait VirtualRawSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static { pub trait VirtualRawSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static {
/// Sends out a raw packet on this socket /// Sends out a datagram or stream of bytes on this socket
async fn send(&mut self, data: Bytes) -> Result<usize>; fn poll_send(&mut self, cx: &mut Context<'_>, data: &[u8]) -> Poll<Result<usize>>;
/// FLushes all the datagrams /// Sends out a datagram or stream of bytes on this socket
async fn flush(&mut self) -> Result<()>; fn try_send(&mut self, data: &[u8]) -> Result<usize>;
/// Attempts to flush the object, ensuring that any buffered data reach
/// their destination.
fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>>;
/// Attempts to flush the object, ensuring that any buffered data reach
/// their destination.
fn try_flush(&mut self) -> Result<()>;
/// Recv a packet from the socket /// Recv a packet from the socket
async fn recv(&mut self) -> Result<SocketReceive>; fn poll_recv<'a>(
&mut self,
cx: &mut Context<'_>,
buf: &'a mut [MaybeUninit<u8>],
) -> Poll<Result<usize>>;
/// Recv a packet from the socket /// Recv a packet from the socket
fn try_recv(&mut self) -> Result<Option<SocketReceive>>; fn try_recv<'a>(&mut self, buf: &'a mut [MaybeUninit<u8>]) -> Result<usize>;
/// Tells the raw socket and its backing switch that all packets /// Tells the raw socket and its backing switch that all packets
/// should be received by this socket even if they are not /// should be received by this socket even if they are not
/// destined for this device /// destined for this device
async fn set_promiscuous(&mut self, promiscuous: bool) -> Result<()>; fn set_promiscuous(&mut self, promiscuous: bool) -> Result<()>;
/// Returns if the socket is running in promiscuous mode whereby it /// Returns if the socket is running in promiscuous mode whereby it
/// will receive all packets even if they are not destined for the /// will receive all packets even if they are not destined for the
@@ -388,23 +384,7 @@ pub trait VirtualRawSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static {
fn promiscuous(&self) -> Result<bool>; fn promiscuous(&self) -> Result<bool>;
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TimeType {
ReadTimeout,
WriteTimeout,
AcceptTimeout,
ConnectTimeout,
Linger,
}
#[async_trait::async_trait]
pub trait VirtualTcpSocket: VirtualConnectedSocket + fmt::Debug + Send + Sync + 'static { pub trait VirtualTcpSocket: VirtualConnectedSocket + fmt::Debug + Send + Sync + 'static {
/// Sets the timeout for a specific action on the socket
fn set_opt_time(&mut self, ty: TimeType, timeout: Option<Duration>) -> Result<()>;
/// Returns one of the previous set timeouts
fn opt_time(&self, ty: TimeType) -> Result<Option<Duration>>;
/// Sets the receive buffer size which acts as a trottle for how /// Sets the receive buffer size which acts as a trottle for how
/// much data is buffered on this side of the pipe /// much data is buffered on this side of the pipe
fn set_recv_buf_size(&mut self, size: usize) -> Result<()>; fn set_recv_buf_size(&mut self, size: usize) -> Result<()>;
@@ -425,7 +405,7 @@ pub trait VirtualTcpSocket: VirtualConnectedSocket + fmt::Debug + Send + Sync +
/// the peer is sent immediately rather than waiting for a bigger /// the peer is sent immediately rather than waiting for a bigger
/// batch of data, this reduces latency but increases encapsulation /// batch of data, this reduces latency but increases encapsulation
/// overhead. /// overhead.
async fn set_nodelay(&mut self, reuse: bool) -> Result<()>; fn set_nodelay(&mut self, reuse: bool) -> Result<()>;
/// Indicates if the NO_DELAY flag is set which means that data /// Indicates if the NO_DELAY flag is set which means that data
/// is immediately sent to the peer without waiting. This reduces /// is immediately sent to the peer without waiting. This reduces
@@ -438,20 +418,15 @@ pub trait VirtualTcpSocket: VirtualConnectedSocket + fmt::Debug + Send + Sync +
/// Shuts down either the READER or WRITER sides of the socket /// Shuts down either the READER or WRITER sides of the socket
/// connection. /// connection.
async fn shutdown(&mut self, how: Shutdown) -> Result<()>; fn shutdown(&mut self, how: Shutdown) -> Result<()>;
/// Return true if the socket is closed /// Return true if the socket is closed
fn is_closed(&self) -> bool; fn is_closed(&self) -> bool;
} }
#[async_trait::async_trait]
pub trait VirtualUdpSocket: pub trait VirtualUdpSocket:
VirtualConnectedSocket + VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static
{ {
/// Connects to a destination peer so that the normal
/// send/recv operations can be used.
async fn connect(&mut self, addr: SocketAddr) -> Result<()>;
/// Sets a flag that means that the UDP socket is able /// Sets a flag that means that the UDP socket is able
/// to receive and process broadcast packets. /// to receive and process broadcast packets.
fn set_broadcast(&mut self, broadcast: bool) -> Result<()>; fn set_broadcast(&mut self, broadcast: bool) -> Result<()>;

File diff suppressed because it is too large Load Diff

View File

@@ -247,6 +247,8 @@ impl ModuleCache {
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "sys")] #[cfg(feature = "sys")]
mod tests { mod tests {
use std::time::Duration;
use tracing_subscriber::{ use tracing_subscriber::{
filter, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, Layer, filter, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, Layer,
}; };
@@ -275,7 +277,9 @@ mod tests {
for _ in 0..2 { for _ in 0..2 {
let webc = cache.get_webc("sharrattj/dash", &rt, &tasks).unwrap(); let webc = cache.get_webc("sharrattj/dash", &rt, &tasks).unwrap();
store.push(webc); store.push(webc);
tasks.runtime().block_on(tasks.sleep_now(0.into(), 1000)); tasks
.runtime()
.block_on(tasks.sleep_now(Duration::from_secs(1)));
} }
} }
} }

View File

@@ -1,5 +1,4 @@
use std::{ use std::{
collections::HashMap,
future::Future, future::Future,
io::{IoSlice, SeekFrom}, io::{IoSlice, SeekFrom},
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
@@ -39,36 +38,23 @@ pub(crate) enum InodeValFilePollGuardMode {
counter: Arc<AtomicU64>, counter: Arc<AtomicU64>,
}, },
Socket { Socket {
inner: Arc<tokio::sync::RwLock<InodeSocketInner>>, inner: Arc<RwLock<InodeSocketInner>>,
lock_state: InodeValFilePollGuardSocketLocking,
}, },
} }
pub(crate) enum InodeValFilePollGuardSocketLocking {
Locking(
Pin<
Box<
dyn Future<Output = tokio::sync::OwnedRwLockWriteGuard<InodeSocketInner>>
+ Send
+ Sync
+ 'static,
>,
>,
),
Locked(tokio::sync::OwnedRwLockWriteGuard<InodeSocketInner>),
}
pub(crate) struct InodeValFilePollGuard { pub(crate) struct InodeValFilePollGuard {
pub(crate) fd: u32, pub(crate) fd: u32,
pub(crate) peb: PollEventSet,
pub(crate) subscription: Subscription,
pub(crate) mode: InodeValFilePollGuardMode, pub(crate) mode: InodeValFilePollGuardMode,
pub(crate) subscriptions: HashMap<PollEventSet, Subscription>,
} }
impl InodeValFilePollGuard { impl InodeValFilePollGuard {
pub(crate) fn new( pub(crate) fn new(
fd: u32, fd: u32,
peb: PollEventSet,
subscription: Subscription,
guard: &Kind, guard: &Kind,
subscriptions: HashMap<PollEventSet, Subscription>,
) -> Option<Self> { ) -> Option<Self> {
let mode = match guard.deref() { let mode = match guard.deref() {
Kind::EventNotifications { Kind::EventNotifications {
@@ -91,22 +77,9 @@ impl InodeValFilePollGuard {
counter: counter.clone(), counter: counter.clone(),
} }
} }
Kind::Socket { socket } => { Kind::Socket { socket } => InodeValFilePollGuardMode::Socket {
if let Ok(guard) = socket.inner.clone().try_write_owned() {
InodeValFilePollGuardMode::Socket {
inner: socket.inner.clone(), inner: socket.inner.clone(),
lock_state: InodeValFilePollGuardSocketLocking::Locked(guard), },
}
} else {
let socket = socket.clone();
InodeValFilePollGuardMode::Socket {
inner: socket.inner.clone(),
lock_state: InodeValFilePollGuardSocketLocking::Locking(Box::pin(
socket.inner.write_owned(),
)),
}
}
}
Kind::File { Kind::File {
handle: Some(handle), handle: Some(handle),
.. ..
@@ -118,7 +91,8 @@ impl InodeValFilePollGuard {
Some(Self { Some(Self {
fd, fd,
mode, mode,
subscriptions, peb,
subscription,
}) })
} }
} }
@@ -130,23 +104,23 @@ impl std::fmt::Debug for InodeValFilePollGuard {
InodeValFilePollGuardMode::EventNotifications { .. } => { InodeValFilePollGuardMode::EventNotifications { .. } => {
write!(f, "guard-notifications") write!(f, "guard-notifications")
} }
InodeValFilePollGuardMode::Socket { lock_state, .. } => match lock_state { InodeValFilePollGuardMode::Socket { inner } => {
InodeValFilePollGuardSocketLocking::Locked(guard) => match guard.kind { let inner = inner.read().unwrap();
InodeSocketKind::TcpListener(..) => write!(f, "guard-tcp-listener"), match inner.kind {
InodeSocketKind::TcpStream(ref stream) => { InodeSocketKind::TcpListener { .. } => write!(f, "guard-tcp-listener"),
if stream.is_closed() { InodeSocketKind::TcpStream { ref socket, .. } => {
if socket.is_closed() {
write!(f, "guard-tcp-stream (closed)") write!(f, "guard-tcp-stream (closed)")
} else { } else {
write!(f, "guard-tcp-stream") write!(f, "guard-tcp-stream")
} }
} }
InodeSocketKind::UdpSocket(..) => write!(f, "guard-udp-socket"), InodeSocketKind::UdpSocket { .. } => write!(f, "guard-udp-socket"),
InodeSocketKind::Raw(..) => write!(f, "guard-raw-socket"), InodeSocketKind::Raw(..) => write!(f, "guard-raw-socket"),
InodeSocketKind::WebSocket(..) => write!(f, "guard-web-socket"), InodeSocketKind::WebSocket(..) => write!(f, "guard-web-socket"),
_ => write!(f, "guard-socket"), _ => write!(f, "guard-socket"),
}, }
_ => write!(f, "guard-socket (locked)"), }
},
} }
} }
} }
@@ -168,7 +142,8 @@ impl InodeValFilePollGuard {
pub(crate) struct InodeValFilePollGuardJoin<'a> { pub(crate) struct InodeValFilePollGuardJoin<'a> {
mode: &'a mut InodeValFilePollGuardMode, mode: &'a mut InodeValFilePollGuardMode,
fd: u32, fd: u32,
subscriptions: HashMap<PollEventSet, Subscription>, peb: PollEventSet,
subscription: Subscription,
} }
impl<'a> InodeValFilePollGuardJoin<'a> { impl<'a> InodeValFilePollGuardJoin<'a> {
@@ -176,7 +151,8 @@ impl<'a> InodeValFilePollGuardJoin<'a> {
Self { Self {
mode: &mut guard.mode, mode: &mut guard.mode,
fd: guard.fd, fd: guard.fd,
subscriptions: guard.subscriptions.clone(), peb: guard.peb,
subscription: guard.subscription,
} }
} }
pub(crate) fn fd(&self) -> u32 { pub(crate) fn fd(&self) -> u32 {
@@ -185,37 +161,34 @@ impl<'a> InodeValFilePollGuardJoin<'a> {
} }
impl<'a> Future for InodeValFilePollGuardJoin<'a> { impl<'a> Future for InodeValFilePollGuardJoin<'a> {
type Output = Vec<Event>; type Output = Event;
fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
let mut has_read = None; let mut has_read = false;
let mut has_write = None; let mut has_write = false;
let mut has_close = None; let mut has_close = false;
let mut has_hangup = false; let mut has_hangup = false;
let mut ret = Vec::new(); for in_event in iterate_poll_events(self.peb) {
for (set, s) in self.subscriptions.iter() {
for in_event in iterate_poll_events(*set) {
match in_event { match in_event {
PollEvent::PollIn => { PollEvent::PollIn => {
has_read = Some(*s); has_read = true;
} }
PollEvent::PollOut => { PollEvent::PollOut => {
has_write = Some(*s); has_write = true;
} }
PollEvent::PollHangUp => { PollEvent::PollHangUp => {
has_hangup = true; has_hangup = true;
has_close = Some(*s); has_close = true;
} }
PollEvent::PollError | PollEvent::PollInvalid => { PollEvent::PollError | PollEvent::PollInvalid => {
if !has_hangup { if !has_hangup {
has_close = Some(*s); has_close = true;
} }
} }
} }
} }
} if has_close {
if let Some(s) = has_close.as_ref() {
let is_closed = match &mut self.mode { let is_closed = match &mut self.mode {
InodeValFilePollGuardMode::File(file) => { InodeValFilePollGuardMode::File(file) => {
let mut guard = file.write().unwrap(); let mut guard = file.write().unwrap();
@@ -223,29 +196,11 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
file.poll_shutdown(cx).is_ready() file.poll_shutdown(cx).is_ready()
} }
InodeValFilePollGuardMode::EventNotifications { .. } => false, InodeValFilePollGuardMode::EventNotifications { .. } => false,
InodeValFilePollGuardMode::Socket { InodeValFilePollGuardMode::Socket { ref inner } => {
ref inner, let mut guard = inner.write().unwrap();
ref mut lock_state,
..
} => {
let guard = match lock_state {
InodeValFilePollGuardSocketLocking::Locking(locking) => {
match locking.as_mut().poll(cx) {
Poll::Ready(guard) => {
*lock_state = InodeValFilePollGuardSocketLocking::Locked(guard);
match lock_state {
InodeValFilePollGuardSocketLocking::Locked(guard) => guard,
_ => unreachable!(),
}
}
Poll::Pending => return Poll::Pending,
}
}
InodeValFilePollGuardSocketLocking::Locked(guard) => guard,
};
let is_closed = if let InodeSocketKind::Closed = guard.kind { let is_closed = if let InodeSocketKind::Closed = guard.kind {
true true
} else if has_read.is_some() || has_write.is_some() { } else if has_read || has_write {
// this will be handled in the read/write poll instead // this will be handled in the read/write poll instead
false false
} else { } else {
@@ -262,21 +217,15 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
_ => false, _ => false,
} }
}; };
// Release the lock so we don't cause any blocking issues
drop(guard);
*lock_state = InodeValFilePollGuardSocketLocking::Locking(Box::pin(
inner.clone().write_owned(),
));
is_closed is_closed
} }
}; };
if is_closed { if is_closed {
ret.push(Event { return Poll::Ready(Event {
userdata: s.userdata, userdata: self.subscription.userdata,
error: Errno::Success, error: Errno::Success,
type_: s.type_, type_: self.subscription.type_,
u: match s.type_ { u: match self.subscription.type_ {
Eventtype::FdRead | Eventtype::FdWrite => EventUnion { Eventtype::FdRead | Eventtype::FdWrite => EventUnion {
fd_readwrite: EventFdReadwrite { fd_readwrite: EventFdReadwrite {
nbytes: 0, nbytes: 0,
@@ -292,7 +241,7 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
}); });
} }
} }
if let Some(s) = has_read { if has_read {
let mut poll_result = match &mut self.mode { let mut poll_result = match &mut self.mode {
InodeValFilePollGuardMode::File(file) => { InodeValFilePollGuardMode::File(file) => {
let mut guard = file.write().unwrap(); let mut guard = file.write().unwrap();
@@ -318,37 +267,12 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
}) })
} }
} }
InodeValFilePollGuardMode::Socket { InodeValFilePollGuardMode::Socket { ref inner } => {
ref inner, let mut guard = inner.write().unwrap();
ref mut lock_state, guard.poll_read_ready(cx).map_err(net_error_into_io_err)
} => {
let guard = match lock_state {
InodeValFilePollGuardSocketLocking::Locking(locking) => {
match locking.as_mut().poll(cx) {
Poll::Ready(guard) => {
*lock_state = InodeValFilePollGuardSocketLocking::Locked(guard);
match lock_state {
InodeValFilePollGuardSocketLocking::Locked(guard) => guard,
_ => unreachable!(),
}
}
Poll::Pending => return Poll::Pending,
}
}
InodeValFilePollGuardSocketLocking::Locked(guard) => guard,
};
let res = guard.poll_read_ready(cx).map_err(net_error_into_io_err);
// drop the lock so we don't block things
drop(guard);
*lock_state = InodeValFilePollGuardSocketLocking::Locking(Box::pin(
inner.clone().write_owned(),
));
res
} }
}; };
if let Some(s) = has_close.as_ref() { if has_close {
poll_result = match poll_result { poll_result = match poll_result {
Poll::Ready(Err(err)) Poll::Ready(Err(err))
if err.kind() == std::io::ErrorKind::ConnectionAborted if err.kind() == std::io::ErrorKind::ConnectionAborted
@@ -358,11 +282,11 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
|| err.kind() == std::io::ErrorKind::NotConnected || err.kind() == std::io::ErrorKind::NotConnected
|| err.kind() == std::io::ErrorKind::UnexpectedEof => || err.kind() == std::io::ErrorKind::UnexpectedEof =>
{ {
ret.push(Event { return Poll::Ready(Event {
userdata: s.userdata, userdata: self.subscription.userdata,
error: Errno::Success, error: Errno::Success,
type_: s.type_, type_: self.subscription.type_,
u: match s.type_ { u: match self.subscription.type_ {
Eventtype::FdRead | Eventtype::FdWrite => EventUnion { Eventtype::FdRead | Eventtype::FdWrite => EventUnion {
fd_readwrite: EventFdReadwrite { fd_readwrite: EventFdReadwrite {
nbytes: 0, nbytes: 0,
@@ -376,7 +300,6 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
Eventtype::Clock => EventUnion { clock: 0 }, Eventtype::Clock => EventUnion { clock: 0 },
}, },
}); });
Poll::Pending
} }
a => a, a => a,
}; };
@@ -390,11 +313,11 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
0 0
} }
}; };
ret.push(Event { return Poll::Ready(Event {
userdata: s.userdata, userdata: self.subscription.userdata,
error, error,
type_: s.type_, type_: self.subscription.type_,
u: match s.type_ { u: match self.subscription.type_ {
Eventtype::FdRead | Eventtype::FdWrite => EventUnion { Eventtype::FdRead | Eventtype::FdWrite => EventUnion {
fd_readwrite: EventFdReadwrite { fd_readwrite: EventFdReadwrite {
nbytes: bytes_available as u64, nbytes: bytes_available as u64,
@@ -410,7 +333,7 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
}); });
} }
} }
if let Some(s) = has_write { if has_write {
let mut poll_result = match &mut self.mode { let mut poll_result = match &mut self.mode {
InodeValFilePollGuardMode::File(file) => { InodeValFilePollGuardMode::File(file) => {
let mut guard = file.write().unwrap(); let mut guard = file.write().unwrap();
@@ -436,37 +359,12 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
}) })
} }
} }
InodeValFilePollGuardMode::Socket { InodeValFilePollGuardMode::Socket { ref inner } => {
ref inner, let mut guard = inner.write().unwrap();
ref mut lock_state, guard.poll_write_ready(cx).map_err(net_error_into_io_err)
} => {
let guard = match lock_state {
InodeValFilePollGuardSocketLocking::Locking(locking) => {
match locking.as_mut().poll(cx) {
Poll::Ready(guard) => {
*lock_state = InodeValFilePollGuardSocketLocking::Locked(guard);
match lock_state {
InodeValFilePollGuardSocketLocking::Locked(guard) => guard,
_ => unreachable!(),
}
}
Poll::Pending => return Poll::Pending,
}
}
InodeValFilePollGuardSocketLocking::Locked(guard) => guard,
};
let res = guard.poll_write_ready(cx).map_err(net_error_into_io_err);
// drop the lock so we don't block things
drop(guard);
*lock_state = InodeValFilePollGuardSocketLocking::Locking(Box::pin(
inner.clone().write_owned(),
));
res
} }
}; };
if let Some(s) = has_close.as_ref() { if has_close {
poll_result = match poll_result { poll_result = match poll_result {
Poll::Ready(Err(err)) Poll::Ready(Err(err))
if err.kind() == std::io::ErrorKind::ConnectionAborted if err.kind() == std::io::ErrorKind::ConnectionAborted
@@ -476,11 +374,11 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
|| err.kind() == std::io::ErrorKind::NotConnected || err.kind() == std::io::ErrorKind::NotConnected
|| err.kind() == std::io::ErrorKind::UnexpectedEof => || err.kind() == std::io::ErrorKind::UnexpectedEof =>
{ {
ret.push(Event { return Poll::Ready(Event {
userdata: s.userdata, userdata: self.subscription.userdata,
error: Errno::Success, error: Errno::Success,
type_: s.type_, type_: self.subscription.type_,
u: match s.type_ { u: match self.subscription.type_ {
Eventtype::FdRead | Eventtype::FdWrite => EventUnion { Eventtype::FdRead | Eventtype::FdWrite => EventUnion {
fd_readwrite: EventFdReadwrite { fd_readwrite: EventFdReadwrite {
nbytes: 0, nbytes: 0,
@@ -494,7 +392,6 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
Eventtype::Clock => EventUnion { clock: 0 }, Eventtype::Clock => EventUnion { clock: 0 },
}, },
}); });
Poll::Pending
} }
a => a, a => a,
}; };
@@ -508,11 +405,11 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
0 0
} }
}; };
ret.push(Event { return Poll::Ready(Event {
userdata: s.userdata, userdata: self.subscription.userdata,
error, error,
type_: s.type_, type_: self.subscription.type_,
u: match s.type_ { u: match self.subscription.type_ {
Eventtype::FdRead | Eventtype::FdWrite => EventUnion { Eventtype::FdRead | Eventtype::FdWrite => EventUnion {
fd_readwrite: EventFdReadwrite { fd_readwrite: EventFdReadwrite {
nbytes: bytes_available as u64, nbytes: bytes_available as u64,
@@ -528,13 +425,9 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
}); });
} }
} }
if !ret.is_empty() {
Poll::Ready(ret)
} else {
Poll::Pending Poll::Pending
} }
} }
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct InodeValFileReadGuard { pub(crate) struct InodeValFileReadGuard {
@@ -557,11 +450,13 @@ impl InodeValFileReadGuard {
pub fn into_poll_guard( pub fn into_poll_guard(
self, self,
fd: u32, fd: u32,
subscriptions: HashMap<PollEventSet, Subscription>, peb: PollEventSet,
subscription: Subscription,
) -> InodeValFilePollGuard { ) -> InodeValFilePollGuard {
InodeValFilePollGuard { InodeValFilePollGuard {
fd, fd,
subscriptions, peb,
subscription,
mode: InodeValFilePollGuardMode::File(self.file), mode: InodeValFilePollGuardMode::File(self.file),
} }
} }

View File

@@ -515,8 +515,10 @@ impl WasiFs {
if path.starts_with("./") { if path.starts_with("./") {
let current_dir = self.current_dir.lock().unwrap(); let current_dir = self.current_dir.lock().unwrap();
path = format!("{}{}", current_dir.as_str(), &path[1..]); path = format!("{}{}", current_dir.as_str(), &path[1..]);
if path.contains("//") {
path = path.replace("//", "/"); path = path.replace("//", "/");
} }
}
path path
} }

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@ use std::{
collections::HashMap, collections::HashMap,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
sync::{Arc, Mutex, RwLock}, sync::{Arc, Mutex, RwLock},
task::Waker,
}; };
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
@@ -88,7 +89,7 @@ struct WasiThreadState {
is_main: bool, is_main: bool,
pid: WasiProcessId, pid: WasiProcessId,
id: WasiThreadId, id: WasiThreadId,
signals: Mutex<(Vec<Signal>, tokio::sync::broadcast::Sender<()>)>, signals: Mutex<(Vec<Signal>, Vec<Waker>)>,
stack: Mutex<ThreadStack>, stack: Mutex<ThreadStack>,
finished: Arc<TaskJoinHandle>, finished: Arc<TaskJoinHandle>,
@@ -113,7 +114,7 @@ impl WasiThread {
pid, pid,
id, id,
finished, finished,
signals: Mutex::new((Vec::new(), tokio::sync::broadcast::channel(1).0)), signals: Mutex::new((Vec::new(), Vec::new())),
stack: Mutex::new(ThreadStack::default()), stack: Mutex::new(ThreadStack::default()),
_task_count_guard: guard, _task_count_guard: guard,
}), }),
@@ -136,7 +137,7 @@ impl WasiThread {
} }
// TODO: this should be private, access should go through utility methods. // TODO: this should be private, access should go through utility methods.
pub fn signals(&self) -> &Mutex<(Vec<Signal>, tokio::sync::broadcast::Sender<()>)> { pub fn signals(&self) -> &Mutex<(Vec<Signal>, Vec<Waker>)> {
&self.state.signals &self.state.signals
} }
@@ -162,7 +163,7 @@ impl WasiThread {
if !guard.0.contains(&signal) { if !guard.0.contains(&signal) {
guard.0.push(signal); guard.0.push(signal);
} }
let _ = guard.1.send(()); guard.1.drain(..).for_each(|w| w.wake());
} }
/// Returns all the signals that are waiting to be processed /// Returns all the signals that are waiting to be processed
@@ -177,16 +178,39 @@ impl WasiThread {
} }
/// Returns all the signals that are waiting to be processed /// Returns all the signals that are waiting to be processed
pub fn pop_signals_or_subscribe( pub fn pop_signals_or_subscribe(&self, waker: &Waker) -> Option<Vec<Signal>> {
&self,
) -> Result<Vec<Signal>, tokio::sync::broadcast::Receiver<()>> {
let mut guard = self.state.signals.lock().unwrap(); let mut guard = self.state.signals.lock().unwrap();
let mut ret = Vec::new(); let mut ret = Vec::new();
std::mem::swap(&mut ret, &mut guard.0); std::mem::swap(&mut ret, &mut guard.0);
match ret.is_empty() { match ret.is_empty() {
true => Err(guard.1.subscribe()), true => {
false => Ok(ret), if guard.1.iter().any(|w| w.will_wake(waker)) == false {
guard.1.push(waker.clone());
} }
None
}
false => Some(ret),
}
}
/// Returns all the signals that are waiting to be processed
pub fn has_signals_or_subscribe(&self, waker: &Waker) -> bool {
let mut guard = self.state.signals.lock().unwrap();
let has_signals = !guard.0.is_empty();
if has_signals == false {
if guard.1.iter().any(|w| w.will_wake(waker)) == false {
guard.1.push(waker.clone());
}
}
has_signals
}
/// Returns all the signals that are waiting to be processed
pub fn pop_signals(&self) -> Vec<Signal> {
let mut guard = self.state.signals.lock().unwrap();
let mut ret = Vec::new();
std::mem::swap(&mut ret, &mut guard.0);
ret
} }
/// Adds a stack snapshot and removes dead ones /// Adds a stack snapshot and removes dead ones

View File

@@ -2,7 +2,7 @@
#[cfg(feature = "sys-thread")] #[cfg(feature = "sys-thread")]
pub mod tokio; pub mod tokio;
use std::pin::Pin; use std::{pin::Pin, time::Duration};
use ::tokio::runtime::Runtime; use ::tokio::runtime::Runtime;
use futures::Future; use futures::Future;
@@ -10,7 +10,7 @@ use wasmer::{vm::VMMemory, MemoryType, Module, Store};
#[cfg(feature = "sys")] #[cfg(feature = "sys")]
use wasmer_types::MemoryStyle; use wasmer_types::MemoryStyle;
use crate::{os::task::thread::WasiThreadError, WasiCallingId}; use crate::os::task::thread::WasiThreadError;
#[derive(Debug)] #[derive(Debug)]
pub struct SpawnedMemory { pub struct SpawnedMemory {
@@ -28,16 +28,13 @@ pub enum SpawnType {
} }
/// An implementation of task management /// An implementation of task management
#[async_trait::async_trait]
#[allow(unused_variables)] #[allow(unused_variables)]
pub trait VirtualTaskManager: std::fmt::Debug + Send + Sync + 'static { pub trait VirtualTaskManager: std::fmt::Debug + Send + Sync + 'static {
/// Invokes whenever a WASM thread goes idle. In some runtimes (like singlethreaded /// Invokes whenever a WASM thread goes idle. In some runtimes (like singlethreaded
/// execution environments) they will need to do asynchronous work whenever the main /// execution environments) they will need to do asynchronous work whenever the main
/// thread goes idle and this is the place to hook for that. /// thread goes idle and this is the place to hook for that.
fn sleep_now( async fn sleep_now(&self, time: Duration);
&self,
_id: WasiCallingId,
ms: u128,
) -> Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>>;
/// Starts an asynchronous task that will run on a shared worker pool /// Starts an asynchronous task that will run on a shared worker pool
/// This task must not block the execution or it could cause a deadlock /// This task must not block the execution or it could cause a deadlock
@@ -82,19 +79,15 @@ pub trait VirtualTaskManager: std::fmt::Debug + Send + Sync + 'static {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StubTaskManager; pub struct StubTaskManager;
#[async_trait::async_trait]
impl VirtualTaskManager for StubTaskManager { impl VirtualTaskManager for StubTaskManager {
#[allow(unused_variables)] #[allow(unused_variables)]
fn sleep_now( async fn sleep_now(&self, time: Duration) {
&self, if time == Duration::ZERO {
id: WasiCallingId,
ms: u128,
) -> Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>> {
if ms == 0 {
std::thread::yield_now(); std::thread::yield_now();
} else { } else {
std::thread::sleep(std::time::Duration::from_millis(ms as u64)); std::thread::sleep(time);
} }
Box::pin(async move {})
} }
#[allow(unused_variables)] #[allow(unused_variables)]

View File

@@ -1,11 +1,11 @@
use std::pin::Pin; use std::{pin::Pin, time::Duration};
use futures::Future; use futures::Future;
#[cfg(feature = "sys-thread")] #[cfg(feature = "sys-thread")]
use tokio::runtime::{Builder, Runtime}; use tokio::runtime::{Builder, Runtime};
use wasmer::{vm::VMMemory, Module, Store}; use wasmer::{vm::VMMemory, Module, Store};
use crate::{os::task::thread::WasiThreadError, WasiCallingId}; use crate::os::task::thread::WasiThreadError;
use super::{SpawnType, VirtualTaskManager}; use super::{SpawnType, VirtualTaskManager};
@@ -39,20 +39,15 @@ impl<'g> Drop for TokioRuntimeGuard<'g> {
fn drop(&mut self) {} fn drop(&mut self) {}
} }
#[async_trait::async_trait]
impl VirtualTaskManager for TokioTaskManager { impl VirtualTaskManager for TokioTaskManager {
/// See [`VirtualTaskManager::sleep_now`]. /// See [`VirtualTaskManager::sleep_now`].
fn sleep_now( async fn sleep_now(&self, time: Duration) {
&self, if time == Duration::ZERO {
_id: WasiCallingId,
ms: u128,
) -> Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>> {
Box::pin(async move {
if ms == 0 {
tokio::task::yield_now().await; tokio::task::yield_now().await;
} else { } else {
tokio::time::sleep(std::time::Duration::from_millis(ms as u64)).await; tokio::time::sleep(time).await;
} }
})
} }
/// See [`VirtualTaskManager::task_shared`]. /// See [`VirtualTaskManager::task_shared`].

View File

@@ -338,7 +338,7 @@ impl WasiEnv {
// differently // differently
let env = ctx.data(); let env = ctx.data();
if !env.inner().signal_set { if !env.inner().signal_set {
if let Ok(signals) = env.thread.pop_signals_or_subscribe() { let signals = env.thread.pop_signals();
let signal_cnt = signals.len(); let signal_cnt = signals.len();
for sig in signals { for sig in signals {
if sig == Signal::Sigint || sig == Signal::Sigquit || sig == Signal::Sigkill { if sig == Signal::Sigint || sig == Signal::Sigquit || sig == Signal::Sigkill {
@@ -349,9 +349,6 @@ impl WasiEnv {
} }
} }
return Ok(Ok(signal_cnt > 0)); return Ok(Ok(signal_cnt > 0));
} else {
return Ok(Ok(false));
}
} }
// Check for forced exit // Check for forced exit
@@ -381,16 +378,28 @@ impl WasiEnv {
// Check for any signals that we need to trigger // Check for any signals that we need to trigger
// (but only if a signal handler is registered) // (but only if a signal handler is registered)
if let Some(_) = env.inner().signal.as_ref() {
let signals = env.thread.pop_signals();
Ok(Ok(Self::process_signals_internal(ctx, signals)?))
} else {
Ok(Ok(false))
}
}
pub fn process_signals_internal(
ctx: &mut FunctionEnvMut<'_, Self>,
mut signals: Vec<Signal>,
) -> Result<bool, WasiError> {
let env = ctx.data();
if let Some(handler) = env.inner().signal.clone() { if let Some(handler) = env.inner().signal.clone() {
if let Ok(mut signals) = env.thread.pop_signals_or_subscribe() {
// We might also have signals that trigger on timers // We might also have signals that trigger on timers
let mut now = 0; let mut now = 0;
let has_signal_interval = { let has_signal_interval = {
let mut any = false; let mut any = false;
let inner = env.process.inner.read().unwrap(); let inner = env.process.inner.read().unwrap();
if !inner.signal_intervals.is_empty() { if !inner.signal_intervals.is_empty() {
now = platform_clock_time_get(Snapshot0Clockid::Monotonic, 1_000_000) now = platform_clock_time_get(Snapshot0Clockid::Monotonic, 1_000_000).unwrap()
.unwrap() as u128; as u128;
for signal in inner.signal_intervals.values() { for signal in inner.signal_intervals.values() {
let elapsed = now - signal.last_signal; let elapsed = now - signal.last_signal;
if elapsed >= signal.interval.as_nanos() { if elapsed >= signal.interval.as_nanos() {
@@ -439,10 +448,11 @@ impl WasiEnv {
} }
} }
} }
Ok(true)
} else {
Ok(false)
} }
} }
Ok(Ok(true))
}
/// Returns an exit code if the thread or process has been forced to exit /// Returns an exit code if the thread or process has been forced to exit
pub fn should_exit(&self) -> Option<u32> { pub fn should_exit(&self) -> Option<u32> {

View File

@@ -25,7 +25,7 @@ use std::{
cell::RefCell, cell::RefCell,
collections::HashMap, collections::HashMap,
path::Path, path::Path,
sync::{atomic::AtomicU32, Arc, Mutex, MutexGuard, RwLock}, sync::{Arc, Mutex, MutexGuard, RwLock},
task::Waker, task::Waker,
time::Duration, time::Duration,
}; };
@@ -102,9 +102,7 @@ impl WasiState {
} }
pub(crate) fn fs_new_open_options(&self) -> OpenOptions { pub(crate) fn fs_new_open_options(&self) -> OpenOptions {
OpenOptions::new(Box::new(WasiStateOpener { self.fs.root_fs.new_open_options()
root_fs: self.fs.root_fs.clone(),
}))
} }
} }
@@ -114,7 +112,7 @@ struct WasiStateOpener {
impl FileOpener for WasiStateOpener { impl FileOpener for WasiStateOpener {
fn open( fn open(
&mut self, &self,
path: &Path, path: &Path,
conf: &wasmer_vfs::OpenOptionsConfig, conf: &wasmer_vfs::OpenOptionsConfig,
) -> wasmer_vfs::Result<Box<dyn VirtualFile + Send + Sync + 'static>> { ) -> wasmer_vfs::Result<Box<dyn VirtualFile + Send + Sync + 'static>> {
@@ -155,8 +153,7 @@ pub(crate) struct WasiStateThreading {
/// CPU efficient manner /// CPU efficient manner
#[derive(Debug)] #[derive(Debug)]
pub struct WasiFutex { pub struct WasiFutex {
pub(crate) refcnt: AtomicU32, pub(crate) wakers: Vec<Waker>,
pub(crate) waker: tokio::sync::broadcast::Sender<()>,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -250,7 +247,7 @@ pub struct WasiState {
// TODO: review allow... // TODO: review allow...
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) threading: RwLock<WasiStateThreading>, pub(crate) threading: RwLock<WasiStateThreading>,
pub(crate) futexs: RwLock<HashMap<u64, WasiFutex>>, pub(crate) futexs: Mutex<HashMap<u64, WasiFutex>>,
pub(crate) clock_offset: Mutex<HashMap<Snapshot0Clockid, i64>>, pub(crate) clock_offset: Mutex<HashMap<Snapshot0Clockid, i64>>,
pub(crate) bus: WasiBusState, pub(crate) bus: WasiBusState,
pub args: Vec<String>, pub args: Vec<String>,

View File

@@ -6,8 +6,12 @@ use wasmer_wasi_types::wasi::{
}; };
use crate::{ use crate::{
mem_error_to_wasi, os::task::thread::WasiThread, syscalls, syscalls::types, Memory32, mem_error_to_wasi,
MemorySize, WasiEnv, WasiError, os::task::thread::WasiThread,
state::{PollEventBuilder, PollEventSet},
syscalls,
syscalls::types,
Memory32, MemorySize, WasiEnv, WasiError,
}; };
/// Wrapper around `syscalls::fd_filestat_get` with extra logic to handle the size /// Wrapper around `syscalls::fd_filestat_get` with extra logic to handle the size
@@ -141,7 +145,11 @@ pub fn poll_oneoff(
let in_origs = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions)); let in_origs = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions));
let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec());
for in_orig in in_origs { for in_orig in in_origs {
subscriptions.push(Into::<Subscription>::into(in_orig)); subscriptions.push((
None,
PollEventSet::default(),
Into::<Subscription>::into(in_orig),
));
} }
// make the call // make the call

View File

@@ -19,12 +19,14 @@ pub mod windows;
pub mod wasi; pub mod wasi;
pub mod wasix; pub mod wasix;
use bytes::{Buf, BufMut};
use futures::Future; use futures::Future;
pub use wasi::*; pub use wasi::*;
pub use wasix::*; pub use wasix::*;
pub mod legacy; pub mod legacy;
use std::mem::MaybeUninit;
pub(crate) use std::{ pub(crate) use std::{
borrow::{Borrow, Cow}, borrow::{Borrow, Cow},
cell::RefCell, cell::RefCell,
@@ -158,6 +160,60 @@ pub(crate) fn write_bytes<T: Write, M: MemorySize>(
result result
} }
pub(crate) fn copy_to_slice<M: MemorySize>(
memory: &MemoryView,
iovs_arr_cell: WasmSlice<__wasi_ciovec_t<M>>,
mut write_loc: &mut [MaybeUninit<u8>],
) -> Result<usize, Errno> {
let mut bytes_written = 0usize;
for iov in iovs_arr_cell.iter() {
let iov_inner = iov.read().map_err(mem_error_to_wasi)?;
let amt = from_offset::<M>(iov_inner.buf_len)?;
let (left, right) = write_loc.split_at_mut(amt);
let bytes = WasmPtr::<u8, M>::new(iov_inner.buf)
.slice(memory, iov_inner.buf_len)
.map_err(mem_error_to_wasi)?;
if amt != bytes.copy_to_slice(left).map_err(mem_error_to_wasi)? {
return Err(Errno::Fault);
}
write_loc = right;
bytes_written += amt;
}
Ok(bytes_written)
}
pub(crate) fn copy_from_slice<M: MemorySize>(
mut read_loc: &[u8],
memory: &MemoryView,
iovs_arr: WasmSlice<__wasi_iovec_t<M>>,
) -> Result<usize, Errno> {
let mut bytes_read = 0usize;
for iov in iovs_arr.iter() {
let iov_inner = iov.read().map_err(mem_error_to_wasi)?;
let to_read = from_offset::<M>(iov_inner.buf_len)?;
let to_read = to_read.min(read_loc.len());
if to_read == 0 {
break;
}
let (left, right) = read_loc.split_at(to_read);
let buf = WasmPtr::<u8, M>::new(iov_inner.buf)
.slice(memory, to_read.try_into().map_err(|_| Errno::Overflow)?)
.map_err(mem_error_to_wasi)?;
buf.write_slice(left).map_err(mem_error_to_wasi)?;
read_loc = right;
bytes_read += to_read;
}
Ok(bytes_read)
}
pub(crate) fn read_bytes<T: Read, M: MemorySize>( pub(crate) fn read_bytes<T: Read, M: MemorySize>(
mut reader: T, mut reader: T,
memory: &MemoryView, memory: &MemoryView,
@@ -167,7 +223,7 @@ pub(crate) fn read_bytes<T: Read, M: MemorySize>(
// We allocate the raw_bytes first once instead of // We allocate the raw_bytes first once instead of
// N times in the loop. // N times in the loop.
let mut raw_bytes: Vec<u8> = vec![0; 1024]; let mut raw_bytes: Vec<u8> = vec![0; 10240];
for iov in iovs_arr.iter() { for iov in iovs_arr.iter() {
let iov_inner = iov.read().map_err(mem_error_to_wasi)?; let iov_inner = iov.read().map_err(mem_error_to_wasi)?;
@@ -221,35 +277,17 @@ where
return Err(WasiError::Exit(exit_code)); return Err(WasiError::Exit(exit_code));
} }
// Fast path (inline synchronous)
let pinned_work = {
let _guard = env.tasks.runtime_enter();
let waker = WasiDummyWaker.into_waker();
let mut cx = Context::from_waker(&waker);
let mut pinned_work = Box::pin(work);
if let Poll::Ready(i) = pinned_work.as_mut().poll(&mut cx) {
return Ok(i);
}
pinned_work
};
// Slow path (will may put the thread to sleep)
//let mut env = ctx.data();
let tasks = env.tasks.clone();
// Create the timeout // Create the timeout
let mut nonblocking = false; let mut nonblocking = false;
if timeout == Some(Duration::ZERO) { if timeout == Some(Duration::ZERO) {
nonblocking = true; nonblocking = true;
} }
let timeout = { let timeout = {
let tasks_inner = tasks.clone(); let tasks_inner = env.tasks.clone();
async move { async move {
if let Some(timeout) = timeout { if let Some(timeout) = timeout {
if !nonblocking { if !nonblocking {
tasks_inner tasks_inner.sleep_now(timeout).await
.sleep_now(current_caller_id(), timeout.as_millis())
.await
} else { } else {
InfiniteSleep::default().await InfiniteSleep::default().await
} }
@@ -259,51 +297,148 @@ where
} }
}; };
let mut signaler = { // This poller will process any signals when the main working function is idle
let signals = env.thread.signals().lock().unwrap(); struct WorkWithSignalPoller<'a, 'b, Fut, T>
let signaler = signals.1.subscribe(); where
if !signals.0.is_empty() { Fut: Future<Output = Result<T, Errno>>,
drop(signals); {
match WasiEnv::process_signals(ctx)? { ctx: &'a mut FunctionEnvMut<'b, WasiEnv>,
Err(err) => return Ok(Err(err)), pinned_work: Pin<Box<Fut>>,
Ok(processed) if processed => return Ok(Err(Errno::Intr)), }
Ok(_) => {} impl<'a, 'b, Fut, T> Future for WorkWithSignalPoller<'a, 'b, Fut, T>
where
Fut: Future<Output = Result<T, Errno>>,
{
type Output = Result<Fut::Output, WasiError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Poll::Ready(res) = Pin::new(&mut self.pinned_work).poll(cx) {
return Poll::Ready(Ok(res));
}
if let Some(exit_code) = self.ctx.data().should_exit() {
return Poll::Ready(Err(WasiError::Exit(exit_code)));
}
if let Some(signals) = self.ctx.data().thread.pop_signals_or_subscribe(cx.waker()) {
if let Err(err) = WasiEnv::process_signals_internal(self.ctx, signals) {
return Poll::Ready(Err(err));
}
return Poll::Ready(Ok(Err(Errno::Intr)));
}
Poll::Pending
} }
env = ctx.data();
} }
signaler
};
// Define the work function // Define the work function
let work = async move { let tasks = env.tasks.clone();
let mut pinned_work = Box::pin(work);
let work = async {
Ok(tokio::select! { Ok(tokio::select! {
// The main work we are doing // The main work we are doing
ret = pinned_work => ret, res = WorkWithSignalPoller { ctx, pinned_work } => res?,
// If a signaler is triggered then we interrupt the main process
_ = signaler.recv() => {
WasiEnv::process_signals(ctx)?;
Err(Errno::Intr)
},
// Optional timeout // Optional timeout
_ = timeout => Err(Errno::Timedout), _ = timeout => Err(Errno::Timedout),
}) })
}; };
// If we are in nonblocking mode then we register a fake waker // Fast path
// and poll then return immediately with a timeout if nothing happened
if nonblocking { if nonblocking {
let waker = WasiDummyWaker.into_waker(); let waker = WasiDummyWaker.into_waker();
let mut cx = Context::from_waker(&waker); let mut cx = Context::from_waker(&waker);
let _guard = tasks.runtime_enter();
let mut pinned_work = Box::pin(work); let mut pinned_work = Box::pin(work);
if let Poll::Ready(res) = pinned_work.as_mut().poll(&mut cx) { if let Poll::Ready(res) = pinned_work.as_mut().poll(&mut cx) {
res return res;
} else {
Ok(Err(Errno::Again))
} }
} else { return Ok(Err(Errno::Again));
// Block on the work and process process }
// Slow path, block on the work and process process
tasks.block_on(work) tasks.block_on(work)
} }
/// Asyncify takes the current thread and blocks on the async runtime associated with it
/// thus allowed for asynchronous operations to execute. It has built in functionality
/// to (optionally) timeout the IO, force exit the process, callback signals and pump
/// synchronous IO engine
pub(crate) fn __asyncify_light<'a, T, Fut>(
env: &'a WasiEnv,
timeout: Option<Duration>,
work: Fut,
) -> Result<Result<T, Errno>, WasiError>
where
T: 'static,
Fut: std::future::Future<Output = Result<T, Errno>>,
{
// Create the timeout
let mut nonblocking = false;
if timeout == Some(Duration::ZERO) {
nonblocking = true;
}
let timeout = {
async {
if let Some(timeout) = timeout {
if !nonblocking {
env.tasks.sleep_now(timeout).await
} else {
InfiniteSleep::default().await
}
} else {
InfiniteSleep::default().await
}
}
};
// This poller will process any signals when the main working function is idle
struct WorkWithSignalPoller<'a, Fut, T>
where
Fut: Future<Output = Result<T, Errno>>,
{
env: &'a WasiEnv,
pinned_work: Pin<Box<Fut>>,
}
impl<'a, Fut, T> Future for WorkWithSignalPoller<'a, Fut, T>
where
Fut: Future<Output = Result<T, Errno>>,
{
type Output = Result<Fut::Output, WasiError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Poll::Ready(res) = Pin::new(&mut self.pinned_work).poll(cx) {
return Poll::Ready(Ok(res));
}
if let Some(exit_code) = self.env.should_exit() {
return Poll::Ready(Err(WasiError::Exit(exit_code)));
}
if let Some(signals) = self.env.thread.pop_signals_or_subscribe(cx.waker()) {
return Poll::Ready(Ok(Err(Errno::Intr)));
}
Poll::Pending
}
}
// Define the work function
let mut pinned_work = Box::pin(work);
let work = async move {
Ok(tokio::select! {
// The main work we are doing
res = WorkWithSignalPoller { env, pinned_work } => res?,
// Optional timeout
_ = timeout => Err(Errno::Timedout),
})
};
// Fast path
if nonblocking {
let waker = WasiDummyWaker.into_waker();
let mut cx = Context::from_waker(&waker);
let _guard = env.tasks.runtime_enter();
let mut pinned_work = Box::pin(work);
if let Poll::Ready(res) = pinned_work.as_mut().poll(&mut cx) {
return res;
}
return Ok(Err(Errno::Again));
}
// Slow path, block on the work and process process
env.tasks.block_on(work)
} }
// This should be compiled away, it will simply wait forever however its never // This should be compiled away, it will simply wait forever however its never
@@ -318,22 +453,18 @@ impl std::future::Future for InfiniteSleep {
} }
} }
/// Performs an immuatble operation on the socket while running in an asynchronous runtime /// Performs an immutable operation on the socket while running in an asynchronous runtime
/// This has built in signal support /// This has built in signal support
pub(crate) fn __sock_actor<T, F, Fut>( pub(crate) fn __sock_asyncify<'a, T, F, Fut>(
ctx: &mut FunctionEnvMut<'_, WasiEnv>, env: &'a WasiEnv,
sock: WasiFd, sock: WasiFd,
rights: Rights, rights: Rights,
actor: F, actor: F,
) -> Result<T, Errno> ) -> Result<T, Errno>
where where
T: 'static, F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Fut,
F: FnOnce(crate::net::socket::InodeSocket) -> Fut + 'static,
Fut: std::future::Future<Output = Result<T, Errno>>, Fut: std::future::Future<Output = Result<T, Errno>>,
{ {
let env = ctx.data();
let tasks = env.tasks.clone();
let state = env.state.clone(); let state = env.state.clone();
let inodes = state.inodes.clone(); let inodes = state.inodes.clone();
@@ -356,7 +487,7 @@ where
drop(guard); drop(guard);
// Start the work using the socket // Start the work using the socket
actor(socket) actor(socket, fd_entry)
} }
_ => { _ => {
return Err(Errno::Notsock); return Err(Errno::Notsock);
@@ -365,21 +496,20 @@ where
}; };
// Block on the work and process it // Block on the work and process it
tasks.block_on(work) env.tasks.block_on(work)
} }
/// Performs mutable work on a socket under an asynchronous runtime with /// Performs mutable work on a socket under an asynchronous runtime with
/// built in signal processing /// built in signal processing
pub(crate) fn __sock_actor_mut<'a, T, F, Fut>( pub(crate) fn __sock_asyncify_mut<T, F, Fut>(
ctx: &'a mut FunctionEnvMut<'_, WasiEnv>, ctx: &'_ mut FunctionEnvMut<'_, WasiEnv>,
sock: WasiFd, sock: WasiFd,
rights: Rights, rights: Rights,
actor: F, actor: F,
) -> Result<T, Errno> ) -> Result<T, Errno>
where where
T: 'static, F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Fut,
F: FnOnce(crate::net::socket::InodeSocket) -> Fut, Fut: std::future::Future<Output = Result<T, Errno>>,
Fut: std::future::Future<Output = Result<T, Errno>> + 'a,
{ {
let env = ctx.data(); let env = ctx.data();
let tasks = env.tasks.clone(); let tasks = env.tasks.clone();
@@ -392,8 +522,6 @@ where
return Err(Errno::Access); return Err(Errno::Access);
} }
let tasks = env.tasks.clone();
{
let inode_idx = fd_entry.inode; let inode_idx = fd_entry.inode;
let inodes_guard = inodes.read().unwrap(); let inodes_guard = inodes.read().unwrap();
let inode = &inodes_guard.arena[inode_idx]; let inode = &inodes_guard.arena[inode_idx];
@@ -406,7 +534,7 @@ where
drop(inodes_guard); drop(inodes_guard);
// Start the work using the socket // Start the work using the socket
let work = actor(socket); let work = actor(socket, fd_entry);
// Block on the work and process it // Block on the work and process it
tasks.block_on(work) tasks.block_on(work)
@@ -414,6 +542,90 @@ where
_ => Err(Errno::Notsock), _ => Err(Errno::Notsock),
} }
} }
/// Performs an immutable operation on the socket while running in an asynchronous runtime
/// This has built in signal support
pub(crate) fn __sock_actor<T, F>(
ctx: &mut FunctionEnvMut<'_, WasiEnv>,
sock: WasiFd,
rights: Rights,
actor: F,
) -> Result<T, Errno>
where
T: 'static,
F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Result<T, Errno>,
{
let env = ctx.data();
let tasks = env.tasks.clone();
let state = env.state.clone();
let inodes = state.inodes.clone();
let fd_entry = state.fs.get_fd(sock)?;
if !rights.is_empty() && !fd_entry.rights.contains(rights) {
return Err(Errno::Access);
}
let inodes_guard = inodes.read().unwrap();
let inode_idx = fd_entry.inode;
let inode = &inodes_guard.arena[inode_idx];
let tasks = env.tasks.clone();
let mut guard = inode.read();
match guard.deref() {
Kind::Socket { socket } => {
// Clone the socket and release the lock
let socket = socket.clone();
drop(guard);
// Start the work using the socket
actor(socket, fd_entry)
}
_ => {
return Err(Errno::Notsock);
}
}
}
/// Performs mutable work on a socket under an asynchronous runtime with
/// built in signal processing
pub(crate) fn __sock_actor_mut<'a, T, F>(
ctx: &'a mut FunctionEnvMut<'_, WasiEnv>,
sock: WasiFd,
rights: Rights,
actor: F,
) -> Result<T, Errno>
where
T: 'static,
F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Result<T, Errno>,
{
let env = ctx.data();
let tasks = env.tasks.clone();
let state = env.state.clone();
let inodes = state.inodes.clone();
let fd_entry = state.fs.get_fd(sock)?;
if !rights.is_empty() && !fd_entry.rights.contains(rights) {
return Err(Errno::Access);
}
let inode_idx = fd_entry.inode;
let inodes_guard = inodes.read().unwrap();
let inode = &inodes_guard.arena[inode_idx];
let mut guard = inode.write();
match guard.deref_mut() {
Kind::Socket { socket } => {
// Clone the socket and release the lock
let socket = socket.clone();
drop(guard);
drop(inodes_guard);
// Start the work using the socket
actor(socket, fd_entry)
}
_ => Err(Errno::Notsock),
}
} }
/// Replaces a socket with another socket in under an asynchronous runtime. /// Replaces a socket with another socket in under an asynchronous runtime.

View File

@@ -36,7 +36,7 @@ pub fn fd_close(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result<Errn
drop(inodes); drop(inodes);
__asyncify(&mut ctx, None, async move { __asyncify(&mut ctx, None, async move {
socket.close().await.map(|()| Errno::Success) socket.close().map(|()| Errno::Success)
})? })?
.unwrap_or_else(|a| a) .unwrap_or_else(|a| a)
} }

View File

@@ -38,26 +38,6 @@ pub fn fd_fdstat_set_flags(
); );
return Ok(Errno::Access); return Ok(Errno::Access);
} }
let mut guard = inodes.arena[inode].write();
if let Kind::Socket { socket } = guard.deref_mut() {
let nonblocking = flags.contains(Fdflags::NONBLOCK);
debug!(
"wasi[{}:{}]::socket(fd={}) nonblocking={}",
ctx.data().pid(),
ctx.data().tid(),
fd,
nonblocking
);
let socket = socket.clone();
drop(guard);
drop(fd_map);
drop(inodes);
wasi_try_ok!(__asyncify(&mut ctx, None, async move {
socket.set_nonblocking(nonblocking).await
})?)
}
} }
let env = ctx.data(); let env = ctx.data();

View File

@@ -123,8 +123,8 @@ fn fd_read_internal<M: MemorySize>(
return Ok(Errno::Access); return Ok(Errno::Access);
} }
let is_non_blocking = fd_entry.flags.contains(Fdflags::NONBLOCK);
let inode_idx = fd_entry.inode; let inode_idx = fd_entry.inode;
let fd_flags = fd_entry.flags;
let max_size = { let max_size = {
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
@@ -152,7 +152,7 @@ fn fd_read_internal<M: MemorySize>(
let data = wasi_try_ok!(__asyncify( let data = wasi_try_ok!(__asyncify(
&mut ctx, &mut ctx,
if is_non_blocking { if fd_flags.contains(Fdflags::NONBLOCK) {
Some(Duration::ZERO) Some(Duration::ZERO)
} else { } else {
None None
@@ -206,14 +206,30 @@ fn fd_read_internal<M: MemorySize>(
drop(guard); drop(guard);
drop(inodes); drop(inodes);
let tasks = env.tasks.clone();
let res = __asyncify( let res = __asyncify(
&mut ctx, &mut ctx,
if is_non_blocking { if fd_flags.contains(Fdflags::NONBLOCK) {
Some(Duration::ZERO) Some(Duration::ZERO)
} else { } else {
None None
}, },
async move { socket.recv(max_size).await }, async {
let mut buf = Vec::with_capacity(max_size);
unsafe {
buf.set_len(max_size);
}
socket
.recv(tasks.deref(), &mut buf, fd_flags)
.await
.map(|amt| {
unsafe {
buf.set_len(amt);
}
let buf: Vec<u8> = unsafe { std::mem::transmute(buf) };
buf
})
},
)? )?
.map_err(|err| match err { .map_err(|err| match err {
Errno::Timedout => Errno::Again, Errno::Timedout => Errno::Again,
@@ -244,7 +260,7 @@ fn fd_read_internal<M: MemorySize>(
let data = wasi_try_ok!(__asyncify( let data = wasi_try_ok!(__asyncify(
&mut ctx, &mut ctx,
if is_non_blocking { if fd_flags.contains(Fdflags::NONBLOCK) {
Some(Duration::ZERO) Some(Duration::ZERO)
} else { } else {
None None
@@ -317,7 +333,7 @@ fn fd_read_internal<M: MemorySize>(
} }
// If its none blocking then exit // If its none blocking then exit
if is_non_blocking { if fd_flags.contains(Fdflags::NONBLOCK) {
return Ok(Errno::Again); return Ok(Errno::Again);
} }

View File

@@ -112,7 +112,7 @@ fn fd_write_internal<M: MemorySize>(
return Ok(Errno::Access); return Ok(Errno::Access);
} }
let is_non_blocking = fd_entry.flags.contains(Fdflags::NONBLOCK); let fd_flags = fd_entry.flags;
let inode_idx = fd_entry.inode; let inode_idx = fd_entry.inode;
let (bytes_written, can_update_cursor) = { let (bytes_written, can_update_cursor) = {
@@ -138,12 +138,12 @@ fn fd_write_internal<M: MemorySize>(
let written = wasi_try_ok!(__asyncify( let written = wasi_try_ok!(__asyncify(
&mut ctx, &mut ctx,
if is_non_blocking { if fd_entry.flags.contains(Fdflags::NONBLOCK) {
Some(Duration::ZERO) Some(Duration::ZERO)
} else { } else {
None None
}, },
async move { async {
let mut handle = handle.write().unwrap(); let mut handle = handle.write().unwrap();
if !is_stdio { if !is_stdio {
handle handle
@@ -179,8 +179,9 @@ fn fd_write_internal<M: MemorySize>(
let mut buf = Vec::with_capacity(buf_len); let mut buf = Vec::with_capacity(buf_len);
wasi_try_ok!(write_bytes(&mut buf, &memory, iovs_arr)); wasi_try_ok!(write_bytes(&mut buf, &memory, iovs_arr));
let tasks = env.tasks.clone();
let written = wasi_try_ok!(__asyncify(&mut ctx, None, async move { let written = wasi_try_ok!(__asyncify(&mut ctx, None, async move {
socket.send(buf).await socket.send(tasks.deref(), &buf, fd_flags).await
})?); })?);
(written, false) (written, false)
} }
@@ -208,12 +209,13 @@ fn fd_write_internal<M: MemorySize>(
immediate, immediate,
.. ..
} => { } => {
let mut val = 0u64.to_ne_bytes(); let mut val: [MaybeUninit<u8>; 8] =
let written = wasi_try_ok!(write_bytes(&mut val[..], &memory, iovs_arr)); unsafe { MaybeUninit::uninit().assume_init() };
let written = wasi_try_ok!(copy_to_slice(&memory, iovs_arr, &mut val[..]));
if written != val.len() { if written != val.len() {
return Ok(Errno::Inval); return Ok(Errno::Inval);
} }
let val = u64::from_ne_bytes(val); let val = u64::from_ne_bytes(unsafe { std::mem::transmute(val) });
counter.fetch_add(val, Ordering::AcqRel); counter.fetch_add(val, Ordering::AcqRel);
{ {

View File

@@ -3,6 +3,7 @@ use wasmer_wasi_types::wasi::SubscriptionClock;
use super::*; use super::*;
use crate::{ use crate::{
fs::{InodeValFilePollGuard, InodeValFilePollGuardJoin}, fs::{InodeValFilePollGuard, InodeValFilePollGuardJoin},
state::PollEventSet,
syscalls::*, syscalls::*,
}; };
@@ -30,11 +31,11 @@ pub fn poll_oneoff<M: MemorySize>(
let mut env = ctx.data(); let mut env = ctx.data();
let mut memory = env.memory_view(&ctx); let mut memory = env.memory_view(&ctx);
let mut subscriptions = Vec::new();
let subscription_array = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions)); let subscription_array = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions));
let mut subscriptions = Vec::with_capacity(subscription_array.len() as usize);
for sub in subscription_array.iter() { for sub in subscription_array.iter() {
let s = wasi_try_mem_ok!(sub.read()); let s = wasi_try_mem_ok!(sub.read());
subscriptions.push(s); subscriptions.push((None, PollEventSet::default(), s));
} }
// Poll and receive all the events that triggered // Poll and receive all the events that triggered
@@ -70,6 +71,7 @@ pub fn poll_oneoff<M: MemorySize>(
struct PollBatch<'a> { struct PollBatch<'a> {
pid: WasiProcessId, pid: WasiProcessId,
tid: WasiThreadId, tid: WasiThreadId,
evts: Vec<Event>,
joins: Vec<InodeValFilePollGuardJoin<'a>>, joins: Vec<InodeValFilePollGuardJoin<'a>>,
} }
impl<'a> PollBatch<'a> { impl<'a> PollBatch<'a> {
@@ -77,6 +79,7 @@ impl<'a> PollBatch<'a> {
Self { Self {
pid, pid,
tid, tid,
evts: Vec::new(),
joins: fds.iter_mut().map(InodeValFilePollGuardJoin::new).collect(), joins: fds.iter_mut().map(InodeValFilePollGuardJoin::new).collect(),
} }
} }
@@ -94,8 +97,7 @@ impl<'a> Future for PollBatch<'a> {
let mut guard = Pin::new(join); let mut guard = Pin::new(join);
match guard.poll(cx) { match guard.poll(cx) {
Poll::Pending => {} Poll::Pending => {}
Poll::Ready(mut res) => { Poll::Ready(evt) => {
for evt in res.iter() {
tracing::trace!( tracing::trace!(
"wasi[{}:{}]::poll_oneoff triggered_fd (fd={}, userdata={}, type={:?})", "wasi[{}:{}]::poll_oneoff triggered_fd (fd={}, userdata={}, type={:?})",
pid, pid,
@@ -104,14 +106,13 @@ impl<'a> Future for PollBatch<'a> {
evt.userdata, evt.userdata,
evt.type_, evt.type_,
); );
} evts.push(evt);
evts.append(&mut res);
done = true; done = true;
} }
} }
} }
if done { if !evts.is_empty() {
return Poll::Ready(Ok(evts)); return Poll::Ready(Ok(evts));
} }
@@ -133,7 +134,7 @@ impl<'a> Future for PollBatch<'a> {
/// The number of events seen /// The number of events seen
pub(crate) fn poll_oneoff_internal( pub(crate) fn poll_oneoff_internal(
ctx: &mut FunctionEnvMut<'_, WasiEnv>, ctx: &mut FunctionEnvMut<'_, WasiEnv>,
subs: Vec<Subscription>, mut subs: Vec<(Option<WasiFd>, PollEventSet, Subscription)>,
) -> Result<Result<Vec<Event>, Errno>, WasiError> { ) -> Result<Result<Vec<Event>, Errno>, WasiError> {
let pid = ctx.data().pid(); let pid = ctx.data().pid();
let tid = ctx.data().tid(); let tid = ctx.data().tid();
@@ -150,16 +151,17 @@ pub(crate) fn poll_oneoff_internal(
// These are used when we capture what clocks (timeouts) are being // These are used when we capture what clocks (timeouts) are being
// subscribed too // subscribed too
let mut clock_subs: Vec<(SubscriptionClock, u64)> = vec![]; let clock_cnt = subs
.iter()
.filter(|a| a.2.type_ == Eventtype::Clock)
.count();
let mut clock_subs: Vec<(SubscriptionClock, u64)> = Vec::with_capacity(subs.len());
let mut time_to_sleep = None; let mut time_to_sleep = None;
// First we extract all the subscriptions into an array so that they // First we extract all the subscriptions into an array so that they
// can be processed // can be processed
let mut memory = env.memory_view(&ctx); let mut memory = env.memory_view(&ctx);
let mut subscriptions = HashMap::new(); for (fd, peb, s) in subs.iter_mut() {
for s in subs {
let mut peb = PollEventBuilder::new();
let mut in_events = HashMap::new();
let fd = match s.type_ { let fd = match s.type_ {
Eventtype::FdRead => { Eventtype::FdRead => {
let file_descriptor = unsafe { s.data.fd_readwrite.file_descriptor }; let file_descriptor = unsafe { s.data.fd_readwrite.file_descriptor };
@@ -175,7 +177,8 @@ pub(crate) fn poll_oneoff_internal(
} }
} }
} }
in_events.insert(peb.add(PollEvent::PollIn).build(), s); *fd = Some(file_descriptor);
*peb = *peb | (PollEvent::PollIn as PollEventSet);
file_descriptor file_descriptor
} }
Eventtype::FdWrite => { Eventtype::FdWrite => {
@@ -192,7 +195,8 @@ pub(crate) fn poll_oneoff_internal(
} }
} }
} }
in_events.insert(peb.add(PollEvent::PollOut).build(), s); *fd = Some(file_descriptor);
*peb = *peb | (PollEvent::PollOut as PollEventSet);
file_descriptor file_descriptor
} }
Eventtype::Clock => { Eventtype::Clock => {
@@ -232,11 +236,6 @@ pub(crate) fn poll_oneoff_internal(
} }
} }
}; };
let entry = subscriptions
.entry(fd)
.or_insert_with(HashMap::<state::PollEventSet, Subscription>::default);
entry.extend(in_events.into_iter());
} }
let mut events_seen: u32 = 0; let mut events_seen: u32 = 0;
@@ -250,27 +249,28 @@ pub(crate) fn poll_oneoff_internal(
// and open a read lock on them all // and open a read lock on them all
let inodes = state.inodes.clone(); let inodes = state.inodes.clone();
let inodes = inodes.read().unwrap(); let inodes = inodes.read().unwrap();
let mut fd_guards = vec![]; let mut fd_guards = Vec::with_capacity(subs.len());
#[allow(clippy::significant_drop_in_scrutinee)] #[allow(clippy::significant_drop_in_scrutinee)]
for (fd, in_events) in subscriptions { for (fd, peb, s) in subs {
if let Some(fd) = fd {
let wasi_file_ref = match fd { let wasi_file_ref = match fd {
__WASI_STDERR_FILENO => { __WASI_STDERR_FILENO => {
wasi_try_ok_ok!(inodes wasi_try_ok_ok!(inodes
.stderr(&state.fs.fd_map) .stderr(&state.fs.fd_map)
.map(|g| g.into_poll_guard(fd, in_events)) .map(|g| g.into_poll_guard(fd, peb, s))
.map_err(fs_error_into_wasi_err)) .map_err(fs_error_into_wasi_err))
} }
__WASI_STDIN_FILENO => { __WASI_STDIN_FILENO => {
wasi_try_ok_ok!(inodes wasi_try_ok_ok!(inodes
.stdin(&state.fs.fd_map) .stdin(&state.fs.fd_map)
.map(|g| g.into_poll_guard(fd, in_events)) .map(|g| g.into_poll_guard(fd, peb, s))
.map_err(fs_error_into_wasi_err)) .map_err(fs_error_into_wasi_err))
} }
__WASI_STDOUT_FILENO => { __WASI_STDOUT_FILENO => {
wasi_try_ok_ok!(inodes wasi_try_ok_ok!(inodes
.stdout(&state.fs.fd_map) .stdout(&state.fs.fd_map)
.map(|g| g.into_poll_guard(fd, in_events)) .map(|g| g.into_poll_guard(fd, peb, s))
.map_err(fs_error_into_wasi_err)) .map_err(fs_error_into_wasi_err))
} }
_ => { _ => {
@@ -283,7 +283,7 @@ pub(crate) fn poll_oneoff_internal(
{ {
let guard = inodes.arena[inode].read(); let guard = inodes.arena[inode].read();
if let Some(guard) = if let Some(guard) =
crate::fs::InodeValFilePollGuard::new(fd, guard.deref(), in_events) crate::fs::InodeValFilePollGuard::new(fd, peb, s, guard.deref())
{ {
guard guard
} else { } else {
@@ -301,6 +301,7 @@ pub(crate) fn poll_oneoff_internal(
); );
fd_guards.push(wasi_file_ref); fd_guards.push(wasi_file_ref);
} }
}
fd_guards fd_guards
}; };

View File

@@ -1,6 +1,62 @@
use std::task::Waker;
use super::*; use super::*;
use crate::syscalls::*; use crate::syscalls::*;
struct FutexPoller<'a, M>
where
M: MemorySize,
{
env: &'a WasiEnv,
view: MemoryView<'a>,
futex_idx: u64,
futex_ptr: WasmPtr<u32, M>,
expected: u32,
}
impl<'a, M> Future for FutexPoller<'a, M>
where
M: MemorySize,
{
type Output = Result<(), Errno>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let waker = cx.waker();
let mut guard = self.env.state.futexs.lock().unwrap();
{
let val = match self.futex_ptr.read(&self.view) {
Ok(a) => a,
Err(err) => return Poll::Ready(Err(mem_error_to_wasi(err))),
};
if val != self.expected {
return Poll::Ready(Ok(()));
}
}
let futex = guard
.entry(self.futex_idx)
.or_insert_with(|| WasiFutex { wakers: vec![] });
if futex.wakers.iter().any(|w| w.will_wake(waker)) == false {
futex.wakers.push(waker.clone());
}
Poll::Pending
}
}
impl<'a, M> Drop for FutexPoller<'a, M>
where
M: MemorySize,
{
fn drop(&mut self) {
let futex = {
let mut guard = self.env.state.futexs.lock().unwrap();
guard.remove(&self.futex_idx)
};
if let Some(futex) = futex {
futex.wakers.into_iter().for_each(|w| w.wake());
}
}
}
/// Wait for a futex_wake operation to wake us. /// Wait for a futex_wake operation to wake us.
/// Returns with EINVAL if the futex doesn't hold the expected value. /// Returns with EINVAL if the futex doesn't hold the expected value.
/// Returns false on timeout, and true in all other cases. /// Returns false on timeout, and true in all other cases.
@@ -29,7 +85,7 @@ pub fn futex_wait<M: MemorySize>(
let mut env = ctx.data(); let mut env = ctx.data();
let state = env.state.clone(); let state = env.state.clone();
let pointer: u64 = wasi_try_ok!(futex_ptr.offset().try_into().map_err(|_| Errno::Overflow)); let futex_idx: u64 = wasi_try_ok!(futex_ptr.offset().try_into().map_err(|_| Errno::Overflow));
// Determine the timeout // Determine the timeout
let timeout = { let timeout = {
@@ -37,74 +93,36 @@ pub fn futex_wait<M: MemorySize>(
wasi_try_mem_ok!(timeout.read(&memory)) wasi_try_mem_ok!(timeout.read(&memory))
}; };
let timeout = match timeout.tag { let timeout = match timeout.tag {
OptionTag::Some => Some(timeout.u as u128), OptionTag::Some => Some(Duration::from_nanos(timeout.u as u64)),
_ => None, _ => None,
}; };
// Loop until we either hit a yield error or the futex is woken // Create a poller which will register ourselves against
let mut woken = Bool::False; // this futex event and check when it has changed
let start = platform_clock_time_get(Snapshot0Clockid::Monotonic, 1).unwrap() as u128;
loop {
// Register the waiting futex (if its not already registered)
let mut rx = {
use std::collections::hash_map::Entry;
let mut guard = state.futexs.write().unwrap();
guard.entry(pointer).or_insert_with(|| WasiFutex {
refcnt: AtomicU32::new(1),
waker: tokio::sync::broadcast::channel(1).0,
});
let futex = guard.get_mut(&pointer).unwrap();
// If the value of the memory is no longer the expected value
// then terminate from the loop (we do this under a futex lock
// so that its protected)
let rx = futex.waker.subscribe();
{
let view = env.memory_view(&ctx); let view = env.memory_view(&ctx);
let val = wasi_try_mem_ok!(futex_ptr.read(&view)); let poller = FutexPoller {
if val != expected { env,
woken = Bool::True; view,
break; futex_idx,
} futex_ptr,
} expected,
rx
}; };
// Check if we have timed out // Wait for the futex to trigger or a timeout to occur
let mut sub_timeout = None; let res = __asyncify_light(env, timeout, poller)?;
if let Some(timeout) = timeout.as_ref() {
let now = platform_clock_time_get(Snapshot0Clockid::Monotonic, 1).unwrap() as u128;
let delta = now.saturating_sub(start);
if delta >= *timeout {
break;
}
let remaining = *timeout - delta;
sub_timeout = Some(Duration::from_nanos(remaining as u64));
}
//sub_timeout.replace(sub_timeout.map(|a| a.min(Duration::from_millis(10))).unwrap_or(Duration::from_millis(10)));
// Now wait for it to be triggered // Process it and return the result
__asyncify(&mut ctx, sub_timeout, async move { let mut ret = Errno::Success;
rx.recv().await.ok(); let woken = match res {
Ok(()) Err(Errno::Timedout) => Bool::False,
})?; Err(err) => {
env = ctx.data(); ret = err;
Bool::True
} }
Ok(_) => Bool::True,
// Drop the reference count to the futex (and remove it if the refcnt hits zero) };
{
let mut guard = state.futexs.write().unwrap();
if guard
.get(&pointer)
.map(|futex| futex.refcnt.fetch_sub(1, Ordering::AcqRel) == 1)
.unwrap_or(false)
{
guard.remove(&pointer);
}
}
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
wasi_try_mem_ok!(ret_woken.write(&memory, woken)); let mut env = ctx.data();
wasi_try_mem_ok!(ret_woken.write(&memory, Bool::False));
Ok(Errno::Success) Ok(ret)
} }

View File

@@ -20,10 +20,19 @@ pub fn futex_wake<M: MemorySize>(
let pointer: u64 = wasi_try!(futex_ptr.offset().try_into().map_err(|_| Errno::Overflow)); let pointer: u64 = wasi_try!(futex_ptr.offset().try_into().map_err(|_| Errno::Overflow));
let mut woken = false; let mut woken = false;
let mut guard = state.futexs.read().unwrap(); let woken = {
if let Some(futex) = guard.get(&pointer) { let mut guard = state.futexs.lock().unwrap();
woken = futex.waker.receiver_count() > 0; if let Some(futex) = guard.get_mut(&pointer) {
let _ = futex.waker.send(()); futex.wakers.pop().map(|w| w.wake());
if futex.wakers.is_empty() {
guard.remove(&pointer);
}
true
} else {
false
}
};
if woken {
trace!( trace!(
%woken, %woken,
"wasi[{}:{}]::futex_wake(offset={})", "wasi[{}:{}]::futex_wake(offset={})",

View File

@@ -18,20 +18,26 @@ pub fn futex_wake_all<M: MemorySize>(
let pointer: u64 = wasi_try!(futex_ptr.offset().try_into().map_err(|_| Errno::Overflow)); let pointer: u64 = wasi_try!(futex_ptr.offset().try_into().map_err(|_| Errno::Overflow));
let mut woken = false; let mut woken = false;
let mut guard = state.futexs.read().unwrap(); let woken = {
if let Some(futex) = guard.get(&pointer) { let mut guard = state.futexs.lock().unwrap();
woken = futex.waker.receiver_count() > 0; if let Some(futex) = guard.remove(&pointer) {
let _ = futex.waker.send(()); futex.wakers.into_iter().for_each(|w| w.wake());
true
} else {
false
}
};
if woken {
trace!( trace!(
%woken, %woken,
"wasi[{}:{}]::futex_wake_all(offset={})", "wasi[{}:{}]::futex_wake(offset={})",
ctx.data().pid(), ctx.data().pid(),
ctx.data().tid(), ctx.data().tid(),
futex_ptr.offset() futex_ptr.offset()
); );
} else { } else {
trace!( trace!(
"wasi[{}:{}]::futex_wake_all(offset={}) - nothing waiting", "wasi[{}:{}]::futex_wake(offset={}) - nothing waiting",
ctx.data().pid(), ctx.data().pid(),
ctx.data().tid(), ctx.data().tid(),
futex_ptr.offset() futex_ptr.offset()

View File

@@ -20,9 +20,8 @@ pub fn port_addr_add<M: MemorySize>(
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
let cidr = wasi_try_ok!(crate::net::read_cidr(&memory, ip)); let cidr = wasi_try_ok!(crate::net::read_cidr(&memory, ip));
let net = env.net(); let net = env.net();
wasi_try_ok!(__asyncify(&mut ctx, None, async move { wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.ip_add(cidr.ip, cidr.prefix) net.ip_add(cidr.ip, cidr.prefix)
.await
.map_err(net_error_into_wasi_err) .map_err(net_error_into_wasi_err)
})?); })?);
Ok(Errno::Success) Ok(Errno::Success)

View File

@@ -11,8 +11,8 @@ pub fn port_addr_clear(mut ctx: FunctionEnvMut<'_, WasiEnv>) -> Result<Errno, Wa
); );
let env = ctx.data(); let env = ctx.data();
let net = env.net(); let net = env.net();
wasi_try_ok!(__asyncify(&mut ctx, None, async move { wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.ip_clear().await.map_err(net_error_into_wasi_err) net.ip_clear().map_err(net_error_into_wasi_err)
})?); })?);
Ok(Errno::Success) Ok(Errno::Success)
} }

View File

@@ -30,8 +30,8 @@ pub fn port_addr_list<M: MemorySize>(
let max_addrs: u64 = wasi_try_ok!(max_addrs.try_into().map_err(|_| Errno::Overflow)); let max_addrs: u64 = wasi_try_ok!(max_addrs.try_into().map_err(|_| Errno::Overflow));
let net = env.net(); let net = env.net();
let addrs = wasi_try_ok!(__asyncify(&mut ctx, None, async move { let addrs = wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.ip_list().await.map_err(net_error_into_wasi_err) net.ip_list().map_err(net_error_into_wasi_err)
})?); })?);
let env = ctx.data(); let env = ctx.data();
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);

View File

@@ -20,8 +20,8 @@ pub fn port_addr_remove<M: MemorySize>(
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
let ip = wasi_try_ok!(crate::net::read_ip(&memory, ip)); let ip = wasi_try_ok!(crate::net::read_ip(&memory, ip));
let net = env.net(); let net = env.net();
wasi_try_ok!(__asyncify(&mut ctx, None, async move { wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.ip_remove(ip).await.map_err(net_error_into_wasi_err) net.ip_remove(ip).map_err(net_error_into_wasi_err)
})?); })?);
Ok(Errno::Success) Ok(Errno::Success)
} }

View File

@@ -21,8 +21,8 @@ pub fn port_gateway_set<M: MemorySize>(
let ip = wasi_try_ok!(crate::net::read_ip(&memory, ip)); let ip = wasi_try_ok!(crate::net::read_ip(&memory, ip));
let net = env.net(); let net = env.net();
wasi_try_ok!(__asyncify(&mut ctx, None, async move { wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.gateway_set(ip).await.map_err(net_error_into_wasi_err) net.gateway_set(ip).map_err(net_error_into_wasi_err)
})?); })?);
Ok(Errno::Success) Ok(Errno::Success)
} }

View File

@@ -12,8 +12,8 @@ pub fn port_mac<M: MemorySize>(
let mut memory = env.memory_view(&ctx); let mut memory = env.memory_view(&ctx);
let net = env.net(); let net = env.net();
let mac = wasi_try_ok!(__asyncify(&mut ctx, None, async move { let mac = wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.mac().await.map_err(net_error_into_wasi_err) net.mac().map_err(net_error_into_wasi_err)
})?); })?);
let env = ctx.data(); let env = ctx.data();
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);

View File

@@ -33,9 +33,8 @@ pub fn port_route_add<M: MemorySize>(
}; };
let net = env.net(); let net = env.net();
wasi_try_ok!(__asyncify(&mut ctx, None, async move { wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.route_add(cidr, via_router, preferred_until, expires_at) net.route_add(cidr, via_router, preferred_until, expires_at)
.await
.map_err(net_error_into_wasi_err) .map_err(net_error_into_wasi_err)
})?); })?);
Ok(Errno::Success) Ok(Errno::Success)

View File

@@ -11,8 +11,8 @@ pub fn port_route_clear(mut ctx: FunctionEnvMut<'_, WasiEnv>) -> Result<Errno, W
); );
let env = ctx.data(); let env = ctx.data();
let net = env.net(); let net = env.net();
wasi_try_ok!(__asyncify(&mut ctx, None, async move { wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.route_clear().await.map_err(net_error_into_wasi_err) net.route_clear().map_err(net_error_into_wasi_err)
})?); })?);
Ok(Errno::Success) Ok(Errno::Success)
} }

View File

@@ -30,8 +30,8 @@ pub fn port_route_list<M: MemorySize>(
wasi_try_mem_ok!(routes_ptr.slice(&memory, wasi_try_ok!(to_offset::<M>(max_routes)))); wasi_try_mem_ok!(routes_ptr.slice(&memory, wasi_try_ok!(to_offset::<M>(max_routes))));
let net = env.net(); let net = env.net();
let routes = wasi_try_ok!(__asyncify(&mut ctx, None, async move { let routes = wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.route_list().await.map_err(net_error_into_wasi_err) net.route_list().map_err(net_error_into_wasi_err)
})?); })?);
let env = ctx.data(); let env = ctx.data();
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);

View File

@@ -17,8 +17,8 @@ pub fn port_route_remove<M: MemorySize>(
let ip = wasi_try_ok!(crate::net::read_ip(&memory, ip)); let ip = wasi_try_ok!(crate::net::read_ip(&memory, ip));
let net = env.net(); let net = env.net();
wasi_try_ok!(__asyncify(&mut ctx, None, async move { wasi_try_ok!(__asyncify(&mut ctx, None, async {
net.route_remove(ip).await.map_err(net_error_into_wasi_err) net.route_remove(ip).map_err(net_error_into_wasi_err)
})?); })?);
Ok(Errno::Success) Ok(Errno::Success)

View File

@@ -280,7 +280,7 @@ pub fn proc_exec<M: MemorySize>(
let tasks_inner = tasks.clone(); let tasks_inner = tasks.clone();
tasks.block_on(Box::pin(async move { tasks.block_on(Box::pin(async move {
loop { loop {
tasks_inner.sleep_now(current_caller_id(), 5).await; tasks_inner.sleep_now(Duration::from_millis(5)).await;
if let Some(exit_code) = process.inst.exit_code() { if let Some(exit_code) = process.inst.exit_code() {
tx.send(exit_code).unwrap(); tx.send(exit_code).unwrap();
break; break;

View File

@@ -5,12 +5,5 @@ use crate::syscalls::*;
/// Yields execution of the thread /// Yields execution of the thread
pub fn sched_yield(mut ctx: FunctionEnvMut<'_, WasiEnv>) -> Result<Errno, WasiError> { pub fn sched_yield(mut ctx: FunctionEnvMut<'_, WasiEnv>) -> Result<Errno, WasiError> {
//trace!("wasi[{}:{}]::sched_yield", ctx.data().pid(), ctx.data().tid()); //trace!("wasi[{}:{}]::sched_yield", ctx.data().pid(), ctx.data().tid());
let env = ctx.data(); thread_sleep_internal(ctx, 0)
let tasks = env.tasks.clone();
wasi_try_ok!(__asyncify(&mut ctx, None, async move {
tasks.sleep_now(current_caller_id(), 0).await;
Ok(())
})?);
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?);
Ok(Errno::Success)
} }

View File

@@ -16,7 +16,7 @@ use crate::syscalls::*;
pub fn sock_accept<M: MemorySize>( pub fn sock_accept<M: MemorySize>(
mut ctx: FunctionEnvMut<'_, WasiEnv>, mut ctx: FunctionEnvMut<'_, WasiEnv>,
sock: WasiFd, sock: WasiFd,
fd_flags: Fdflags, mut fd_flags: Fdflags,
ro_fd: WasmPtr<WasiFd, M>, ro_fd: WasmPtr<WasiFd, M>,
ro_addr: WasmPtr<__wasi_addr_port_t, M>, ro_addr: WasmPtr<__wasi_addr_port_t, M>,
) -> Result<Errno, WasiError> { ) -> Result<Errno, WasiError> {
@@ -30,28 +30,44 @@ pub fn sock_accept<M: MemorySize>(
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?);
let (child, addr) = wasi_try_ok!(__sock_actor( let tasks = ctx.data().tasks.clone();
&mut ctx, let (child, addr, fd_flags) = wasi_try_ok!(__sock_asyncify(
ctx.data(),
sock, sock,
Rights::SOCK_ACCEPT, Rights::SOCK_ACCEPT,
move |socket| async move { socket.accept(fd_flags).await } move |socket, fd| async move {
if fd.flags.contains(Fdflags::NONBLOCK) {
fd_flags.set(Fdflags::NONBLOCK, true);
}
socket
.accept(tasks.deref(), fd_flags)
.await
.map(|a| (a.0, a.1, fd_flags))
}
)); ));
let env = ctx.data(); let env = ctx.data();
let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0);
let kind = Kind::Socket { let kind = Kind::Socket {
socket: InodeSocket::new(InodeSocketKind::TcpStream(child)), socket: InodeSocket::new(InodeSocketKind::TcpStream {
socket: child,
write_timeout: None,
read_timeout: None,
}),
}; };
let inode = let inode =
state state
.fs .fs
.create_inode_with_default_stat(inodes.deref_mut(), kind, false, "socket".into()); .create_inode_with_default_stat(inodes.deref_mut(), kind, false, "socket".into());
let mut new_flags = Fdflags::empty();
if fd_flags.contains(Fdflags::NONBLOCK) {
new_flags.set(Fdflags::NONBLOCK, true);
}
let rights = Rights::all_socket(); let rights = Rights::all_socket();
let fd = wasi_try_ok!(state let fd = wasi_try_ok!(state.fs.create_fd(rights, rights, new_flags, 0, inode));
.fs
.create_fd(rights, rights, Fdflags::empty(), 0, inode));
debug!( debug!(
"wasi[{}:{}]::sock_accept (ret=ESUCCESS, peer={})", "wasi[{}:{}]::sock_accept (ret=ESUCCESS, peer={})",

View File

@@ -28,7 +28,7 @@ pub fn sock_addr_local<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { socket.addr_local().await } |socket, _| socket.addr_local()
)); ));
let memory = ctx.data().memory_view(&ctx); let memory = ctx.data().memory_view(&ctx);
wasi_try!(crate::net::write_ip_port( wasi_try!(crate::net::write_ip_port(

View File

@@ -28,7 +28,7 @@ pub fn sock_addr_peer<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { socket.addr_peer().await } |socket, _| socket.addr_peer()
)); ));
let env = ctx.data(); let env = ctx.data();

View File

@@ -26,11 +26,14 @@ pub fn sock_bind<M: MemorySize>(
let addr = wasi_try!(crate::net::read_ip_port(&memory, addr)); let addr = wasi_try!(crate::net::read_ip_port(&memory, addr));
let addr = SocketAddr::new(addr.0, addr.1); let addr = SocketAddr::new(addr.0, addr.1);
let net = env.net(); let net = env.net();
let tasks = ctx.data().tasks.clone();
wasi_try!(__sock_upgrade( wasi_try!(__sock_upgrade(
&mut ctx, &mut ctx,
sock, sock,
Rights::SOCK_BIND, Rights::SOCK_BIND,
move |socket| async move { socket.bind(net, addr).await } move |socket| async move { socket.bind(tasks.deref(), net.deref(), addr).await }
)); ));
Errno::Success Errno::Success
} }

View File

@@ -31,11 +31,13 @@ pub fn sock_connect<M: MemorySize>(
let addr = wasi_try!(crate::net::read_ip_port(&memory, addr)); let addr = wasi_try!(crate::net::read_ip_port(&memory, addr));
let addr = SocketAddr::new(addr.0, addr.1); let addr = SocketAddr::new(addr.0, addr.1);
let tasks = ctx.data().tasks.clone();
wasi_try!(__sock_upgrade( wasi_try!(__sock_upgrade(
&mut ctx, &mut ctx,
sock, sock,
Rights::SOCK_CONNECT, Rights::SOCK_CONNECT,
move |mut socket| async move { socket.connect(net, addr).await } move |mut socket| async move { socket.connect(tasks.deref(), net.deref(), addr, None).await }
)); ));
Errno::Success Errno::Success
} }

View File

@@ -28,7 +28,7 @@ pub fn sock_get_opt_flag<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { socket.get_opt_flag(option).await } |socket, _| socket.get_opt_flag(option)
)); ));
let env = ctx.data(); let env = ctx.data();

View File

@@ -26,17 +26,15 @@ pub fn sock_get_opt_size<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { |socket, _| match opt {
match opt { Sockoption::RecvBufSize => socket.recv_buf_size().map(|a| a as Filesize),
Sockoption::RecvBufSize => socket.recv_buf_size().await.map(|a| a as Filesize), Sockoption::SendBufSize => socket.send_buf_size().map(|a| a as Filesize),
Sockoption::SendBufSize => socket.send_buf_size().await.map(|a| a as Filesize), Sockoption::Ttl => socket.ttl().map(|a| a as Filesize),
Sockoption::Ttl => socket.ttl().await.map(|a| a as Filesize),
Sockoption::MulticastTtlV4 => { Sockoption::MulticastTtlV4 => {
socket.multicast_ttl_v4().await.map(|a| a as Filesize) socket.multicast_ttl_v4().map(|a| a as Filesize)
} }
_ => Err(Errno::Inval), _ => Err(Errno::Inval),
} }
}
)); ));
let env = ctx.data(); let env = ctx.data();

View File

@@ -1,5 +1,5 @@
use super::*; use super::*;
use crate::syscalls::*; use crate::{net::socket::TimeType, syscalls::*};
/// ### `sock_get_opt_time()` /// ### `sock_get_opt_time()`
/// Retrieve one of the times on the socket /// Retrieve one of the times on the socket
@@ -23,11 +23,11 @@ pub fn sock_get_opt_time<M: MemorySize>(
); );
let ty = match opt { let ty = match opt {
Sockoption::RecvTimeout => wasmer_vnet::TimeType::ReadTimeout, Sockoption::RecvTimeout => TimeType::ReadTimeout,
Sockoption::SendTimeout => wasmer_vnet::TimeType::WriteTimeout, Sockoption::SendTimeout => TimeType::WriteTimeout,
Sockoption::ConnectTimeout => wasmer_vnet::TimeType::ConnectTimeout, Sockoption::ConnectTimeout => TimeType::ConnectTimeout,
Sockoption::AcceptTimeout => wasmer_vnet::TimeType::AcceptTimeout, Sockoption::AcceptTimeout => TimeType::AcceptTimeout,
Sockoption::Linger => wasmer_vnet::TimeType::Linger, Sockoption::Linger => TimeType::Linger,
_ => return Errno::Inval, _ => return Errno::Inval,
}; };
@@ -35,7 +35,7 @@ pub fn sock_get_opt_time<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { socket.opt_time(ty).await } |socket, _| socket.opt_time(ty)
)); ));
let env = ctx.data(); let env = ctx.data();

View File

@@ -30,7 +30,7 @@ pub fn sock_join_multicast_v4<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { socket.join_multicast_v4(multiaddr, iface).await } |socket, _| socket.join_multicast_v4(multiaddr, iface)
)); ));
Errno::Success Errno::Success
} }

View File

@@ -29,7 +29,7 @@ pub fn sock_join_multicast_v6<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { socket.join_multicast_v6(multiaddr, iface).await } |socket, _| socket.join_multicast_v6(multiaddr, iface)
)); ));
Errno::Success Errno::Success
} }

View File

@@ -30,7 +30,7 @@ pub fn sock_leave_multicast_v4<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { socket.leave_multicast_v4(multiaddr, iface).await } |socket, _| socket.leave_multicast_v4(multiaddr, iface)
)); ));
Errno::Success Errno::Success
} }

View File

@@ -29,7 +29,7 @@ pub fn sock_leave_multicast_v6<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |mut socket| async move { socket.leave_multicast_v6(multiaddr, iface).await } |mut socket, _| socket.leave_multicast_v6(multiaddr, iface)
)); ));
Errno::Success Errno::Success
} }

View File

@@ -28,11 +28,14 @@ pub fn sock_listen<M: MemorySize>(
let env = ctx.data(); let env = ctx.data();
let net = env.net(); let net = env.net();
let backlog: usize = wasi_try!(backlog.try_into().map_err(|_| Errno::Inval)); let backlog: usize = wasi_try!(backlog.try_into().map_err(|_| Errno::Inval));
let tasks = ctx.data().tasks.clone();
wasi_try!(__sock_upgrade( wasi_try!(__sock_upgrade(
&mut ctx, &mut ctx,
sock, sock,
Rights::SOCK_LISTEN, Rights::SOCK_LISTEN,
move |socket| async move { socket.listen(net, backlog).await } |socket| async move { socket.listen(tasks.deref(), net.deref(), backlog).await }
)); ));
Errno::Success Errno::Success
} }

View File

@@ -42,13 +42,12 @@ pub fn sock_open<M: MemorySize>(
only_v6: false, only_v6: false,
reuse_port: false, reuse_port: false,
reuse_addr: false, reuse_addr: false,
nonblocking: false,
send_buf_size: None, send_buf_size: None,
recv_buf_size: None, recv_buf_size: None,
send_timeout: None, write_timeout: None,
recv_timeout: None, read_timeout: None,
connect_timeout: None,
accept_timeout: None, accept_timeout: None,
connect_timeout: None,
}), }),
}, },
_ => return Errno::Notsup, _ => return Errno::Notsup,

View File

@@ -1,3 +1,5 @@
use std::mem::MaybeUninit;
use super::*; use super::*;
use crate::syscalls::*; use crate::syscalls::*;
@@ -26,10 +28,10 @@ pub fn sock_recv<M: MemorySize>(
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?);
let mut env = ctx.data(); let mut env = ctx.data();
let max_size = {
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
let iovs_arr = wasi_try_mem_ok!(ri_data.slice(&memory, ri_data_len)); let iovs_arr = wasi_try_mem_ok!(ri_data.slice(&memory, ri_data_len));
let max_size = {
let mut max_size = 0usize; let mut max_size = 0usize;
for iovs in iovs_arr.iter() { for iovs in iovs_arr.iter() {
let iovs = wasi_try_mem_ok!(iovs.read()); let iovs = wasi_try_mem_ok!(iovs.read());
@@ -39,23 +41,55 @@ pub fn sock_recv<M: MemorySize>(
max_size max_size
}; };
let data = wasi_try_ok!(__sock_actor_mut( let bytes_read = {
&mut ctx, if max_size <= 10240 {
let mut buf: [MaybeUninit<u8>; 10240] = unsafe { MaybeUninit::uninit().assume_init() };
let writer = &mut buf[..max_size];
let amt = wasi_try_ok!(__sock_asyncify(
env,
sock, sock,
Rights::SOCK_RECV, Rights::SOCK_RECV,
move |socket| async move { socket.recv(max_size).await }, |socket, fd| async move { socket.recv(env.tasks.deref(), writer, fd.flags).await },
)); ));
env = ctx.data();
let memory = env.memory_view(&ctx); if amt > 0 {
let buf: &[MaybeUninit<u8>] = &buf[..amt];
let buf: &[u8] = unsafe { std::mem::transmute(buf) };
wasi_try_ok!(copy_from_slice(buf, &memory, iovs_arr).map(|_| amt))
} else {
0
}
} else {
let data = wasi_try_ok!(__sock_asyncify(
env,
sock,
Rights::SOCK_RECV,
|socket, fd| async move {
let mut buf = Vec::with_capacity(max_size);
unsafe {
buf.set_len(max_size);
}
socket
.recv(env.tasks.deref(), &mut buf, fd.flags)
.await
.map(|amt| {
unsafe {
buf.set_len(amt);
}
let buf: Vec<u8> = unsafe { std::mem::transmute(buf) };
buf
})
},
));
let data_len = data.len(); let data_len = data.len();
let bytes_read = if data_len > 0 { if data_len > 0 {
let mut reader = &data[..]; let mut reader = &data[..];
let iovs_arr = wasi_try_mem_ok!(ri_data.slice(&memory, ri_data_len));
wasi_try_ok!(read_bytes(reader, &memory, iovs_arr).map(|_| data_len)) wasi_try_ok!(read_bytes(reader, &memory, iovs_arr).map(|_| data_len))
} else { } else {
0 0
}
}
}; };
debug!( debug!(

View File

@@ -1,3 +1,5 @@
use std::mem::MaybeUninit;
use super::*; use super::*;
use crate::syscalls::*; use crate::syscalls::*;
@@ -34,10 +36,10 @@ pub fn sock_recv_from<M: MemorySize>(
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?);
let mut env = ctx.data(); let mut env = ctx.data();
let max_size = {
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
let iovs_arr = wasi_try_mem_ok!(ri_data.slice(&memory, ri_data_len)); let iovs_arr = wasi_try_mem_ok!(ri_data.slice(&memory, ri_data_len));
let max_size = {
let mut max_size = 0usize; let mut max_size = 0usize;
for iovs in iovs_arr.iter() { for iovs in iovs_arr.iter() {
let iovs = wasi_try_mem_ok!(iovs.read()); let iovs = wasi_try_mem_ok!(iovs.read());
@@ -47,23 +49,60 @@ pub fn sock_recv_from<M: MemorySize>(
max_size max_size
}; };
let (data, peer) = wasi_try_ok!(__sock_actor_mut( let (bytes_read, peer) = {
&mut ctx, if max_size <= 10240 {
let mut buf: [MaybeUninit<u8>; 10240] = unsafe { MaybeUninit::uninit().assume_init() };
let writer = &mut buf[..max_size];
let (amt, peer) = wasi_try_ok!(__sock_asyncify(
env,
sock,
Rights::SOCK_RECV,
|socket, fd| async move { socket.recv_from(env.tasks.deref(), writer, fd.flags).await },
));
if amt > 0 {
let buf: &[MaybeUninit<u8>] = &buf[..amt];
let buf: &[u8] = unsafe { std::mem::transmute(buf) };
wasi_try_ok!(copy_from_slice(buf, &memory, iovs_arr).map(|_| (amt, peer)))
} else {
(amt, peer)
}
} else {
let (data, peer) = wasi_try_ok!(__sock_asyncify(
env,
sock, sock,
Rights::SOCK_RECV_FROM, Rights::SOCK_RECV_FROM,
move |socket| async move { socket.recv_from(max_size).await } |socket, fd| async move {
let mut buf = Vec::with_capacity(max_size);
unsafe {
buf.set_len(max_size);
}
socket
.recv_from(env.tasks.deref(), &mut buf, fd.flags)
.await
.map(|(amt, addr)| {
unsafe {
buf.set_len(amt);
}
let buf: Vec<u8> = unsafe { std::mem::transmute(buf) };
(buf, addr)
})
}
)); ));
env = ctx.data();
let memory = env.memory_view(&ctx);
let iovs_arr = wasi_try_mem_ok!(ri_data.slice(&memory, ri_data_len));
wasi_try_ok!(write_ip_port(&memory, ro_addr, peer.ip(), peer.port()));
let data_len = data.len(); let data_len = data.len();
if data_len > 0 {
let mut reader = &data[..]; let mut reader = &data[..];
let bytes_read = wasi_try_ok!(read_bytes(reader, &memory, iovs_arr).map(|_| data_len)); wasi_try_ok!(read_bytes(reader, &memory, iovs_arr).map(|_| (data_len, peer)))
let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow)); } else {
(0, peer)
}
}
};
wasi_try_ok!(write_ip_port(&memory, ro_addr, peer.ip(), peer.port()));
let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow));
wasi_try_mem_ok!(ro_flags.write(&memory, 0)); wasi_try_mem_ok!(ro_flags.write(&memory, 0));
wasi_try_mem_ok!(ro_data_len.write(&memory, bytes_read)); wasi_try_mem_ok!(ro_data_len.write(&memory, bytes_read));

View File

@@ -1,3 +1,5 @@
use std::mem::MaybeUninit;
use super::*; use super::*;
use crate::syscalls::*; use crate::syscalls::*;
@@ -22,14 +24,12 @@ pub fn sock_send<M: MemorySize>(
si_flags: SiFlags, si_flags: SiFlags,
ret_data_len: WasmPtr<M::Offset, M>, ret_data_len: WasmPtr<M::Offset, M>,
) -> Result<Errno, WasiError> { ) -> Result<Errno, WasiError> {
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); let env = ctx.data();
let memory = env.memory_view(&ctx);
let mut env = ctx.data(); let iovs_arr = wasi_try_mem_ok!(si_data.slice(&memory, si_data_len));
let runtime = env.runtime.clone(); let runtime = env.runtime.clone();
let buf_len: M::Offset = { let buf_len: M::Offset = {
let memory = env.memory_view(&ctx);
let iovs_arr = wasi_try_mem_ok!(si_data.slice(&memory, si_data_len));
iovs_arr iovs_arr
.iter() .iter()
.filter_map(|a| a.read().ok()) .filter_map(|a| a.read().ok())
@@ -45,24 +45,38 @@ pub fn sock_send<M: MemorySize>(
si_flags si_flags
); );
let buf_len: usize = wasi_try_ok!(buf_len.try_into().map_err(|_| Errno::Inval)); let buf_len: usize = wasi_try_ok!(buf_len.try_into().map_err(|_| Errno::Inval));
let mut buf = Vec::with_capacity(buf_len);
{
let memory = env.memory_view(&ctx);
let iovs_arr = wasi_try_mem_ok!(si_data.slice(&memory, si_data_len));
wasi_try_ok!(write_bytes(&mut buf, &memory, iovs_arr));
}
let bytes_written = wasi_try_ok!(__sock_actor_mut( let bytes_written = {
&mut ctx, if buf_len <= 10240 {
let mut buf: [MaybeUninit<u8>; 10240] = unsafe { MaybeUninit::uninit().assume_init() };
let writer = &mut buf[..buf_len];
let written = wasi_try_ok!(copy_to_slice(&memory, iovs_arr, writer));
let reader = &buf[..written];
let reader: &[u8] = unsafe { std::mem::transmute(reader) };
wasi_try_ok!(__sock_asyncify(
env,
sock, sock,
Rights::SOCK_SEND, Rights::SOCK_SEND,
move |socket| async move { socket.send(buf).await }, |socket, fd| async move { socket.send(env.tasks.deref(), reader, fd.flags).await },
)); ))
env = ctx.data(); } else {
let mut buf = Vec::with_capacity(buf_len);
wasi_try_ok!(write_bytes(&mut buf, &memory, iovs_arr));
let reader = &buf;
wasi_try_ok!(__sock_asyncify(
env,
sock,
Rights::SOCK_SEND,
|socket, fd| async move { socket.send(env.tasks.deref(), reader, fd.flags).await },
))
}
};
let bytes_written: M::Offset = let bytes_written: M::Offset =
wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow)); wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow));
let memory = env.memory_view(&ctx);
wasi_try_mem_ok!(ret_data_len.write(&memory, bytes_written)); wasi_try_mem_ok!(ret_data_len.write(&memory, bytes_written));
Ok(Errno::Success) Ok(Errno::Success)

View File

@@ -53,6 +53,8 @@ pub fn sock_send_file<M: MemorySize>(
count -= sub_count; count -= sub_count;
let fd_entry = wasi_try_ok!(state.fs.get_fd(in_fd)); let fd_entry = wasi_try_ok!(state.fs.get_fd(in_fd));
let fd_flags = fd_entry.flags;
let data = { let data = {
let inodes = env.state.inodes.clone(); let inodes = env.state.inodes.clone();
match in_fd { match in_fd {
@@ -116,12 +118,21 @@ pub fn sock_send_file<M: MemorySize>(
drop(guard); drop(guard);
drop(inodes); drop(inodes);
let data = let data = wasi_try_ok!(__asyncify(&mut ctx, None, async {
wasi_try_ok!(__asyncify(&mut ctx, None, async move { let mut buf = Vec::with_capacity(sub_count as usize);
socket unsafe {
.recv(sub_count as usize) buf.set_len(sub_count as usize);
.await }
.map(|a| a.to_vec()) socket.recv(tasks.deref(), &mut buf, fd_flags).await.map(
|amt| {
unsafe {
buf.set_len(amt);
}
let buf: Vec<u8> =
unsafe { std::mem::transmute(buf) };
buf
},
)
})?); })?);
env = ctx.data(); env = ctx.data();
data data
@@ -177,11 +188,12 @@ pub fn sock_send_file<M: MemorySize>(
}; };
// Write it down to the socket // Write it down to the socket
let bytes_written = wasi_try_ok!(__sock_actor_mut( let tasks = ctx.data().tasks.clone();
let bytes_written = wasi_try_ok!(__sock_asyncify_mut(
&mut ctx, &mut ctx,
sock, sock,
Rights::SOCK_SEND, Rights::SOCK_SEND,
move |socket| async move { socket.send(data).await }, |socket, fd| async move { socket.send(tasks.deref(), &data, fd.flags).await },
)); ));
env = ctx.data(); env = ctx.data();

View File

@@ -30,14 +30,11 @@ pub fn sock_send_to<M: MemorySize>(
ctx.data().tid(), ctx.data().tid(),
sock sock
); );
let env = ctx.data();
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?);
let mut env = ctx.data();
let buf_len: M::Offset = {
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
let iovs_arr = wasi_try_mem_ok!(si_data.slice(&memory, si_data_len)); let iovs_arr = wasi_try_mem_ok!(si_data.slice(&memory, si_data_len));
let buf_len: M::Offset = {
iovs_arr iovs_arr
.iter() .iter()
.filter_map(|a| a.read().ok()) .filter_map(|a| a.read().ok())
@@ -45,30 +42,51 @@ pub fn sock_send_to<M: MemorySize>(
.sum() .sum()
}; };
let buf_len: usize = wasi_try_ok!(buf_len.try_into().map_err(|_| Errno::Inval)); let buf_len: usize = wasi_try_ok!(buf_len.try_into().map_err(|_| Errno::Inval));
let mut buf = Vec::with_capacity(buf_len);
{
let memory = env.memory_view(&ctx);
let iovs_arr = wasi_try_mem_ok!(si_data.slice(&memory, si_data_len));
wasi_try_ok!(write_bytes(&mut buf, &memory, iovs_arr));
}
let (addr_ip, addr_port) = { let (addr_ip, addr_port) = {
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
wasi_try_ok!(read_ip_port(&memory, addr)) wasi_try_ok!(read_ip_port(&memory, addr))
}; };
let addr = SocketAddr::new(addr_ip, addr_port); let addr = SocketAddr::new(addr_ip, addr_port);
let bytes_written = wasi_try_ok!(__sock_actor_mut( let bytes_written = {
&mut ctx, if buf_len <= 10240 {
let mut buf: [MaybeUninit<u8>; 10240] = unsafe { MaybeUninit::uninit().assume_init() };
let writer = &mut buf[..buf_len];
let written = wasi_try_ok!(copy_to_slice(&memory, iovs_arr, writer));
let reader = &buf[..written];
let reader: &[u8] = unsafe { std::mem::transmute(reader) };
wasi_try_ok!(__sock_asyncify(
env,
sock,
Rights::SOCK_SEND,
|socket, fd| async move {
socket
.send_to::<M>(env.tasks.deref(), reader, addr, fd.flags)
.await
},
))
} else {
let mut buf = Vec::with_capacity(buf_len);
wasi_try_ok!(write_bytes(&mut buf, &memory, iovs_arr));
let reader = &buf;
wasi_try_ok!(__sock_asyncify(
env,
sock, sock,
Rights::SOCK_SEND_TO, Rights::SOCK_SEND_TO,
move |socket| async move { socket.send_to::<M>(buf, addr).await }, |socket, fd| async move {
)); socket
env = ctx.data(); .send_to::<M>(env.tasks.deref(), reader, addr, fd.flags)
.await
},
))
}
};
let bytes_written: M::Offset = let bytes_written: M::Offset =
wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow)); wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow));
let memory = env.memory_view(&ctx);
wasi_try_mem_ok!(ret_data_len.write(&memory, bytes_written as M::Offset)); wasi_try_mem_ok!(ret_data_len.write(&memory, bytes_written as M::Offset));
Ok(Errno::Success) Ok(Errno::Success)

View File

@@ -36,7 +36,7 @@ pub fn sock_set_opt_flag(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |mut socket| async move { socket.set_opt_flag(option, flag).await } |mut socket, _| socket.set_opt_flag(option, flag)
)); ));
Errno::Success Errno::Success
} }

View File

@@ -1,5 +1,5 @@
use super::*; use super::*;
use crate::syscalls::*; use crate::{net::socket::TimeType, syscalls::*};
/// ### `sock_set_opt_size() /// ### `sock_set_opt_size()
/// Set size of particular option for this socket /// Set size of particular option for this socket
@@ -25,11 +25,11 @@ pub fn sock_set_opt_size(
); );
let ty = match opt { let ty = match opt {
Sockoption::RecvTimeout => wasmer_vnet::TimeType::ReadTimeout, Sockoption::RecvTimeout => TimeType::ReadTimeout,
Sockoption::SendTimeout => wasmer_vnet::TimeType::WriteTimeout, Sockoption::SendTimeout => TimeType::WriteTimeout,
Sockoption::ConnectTimeout => wasmer_vnet::TimeType::ConnectTimeout, Sockoption::ConnectTimeout => TimeType::ConnectTimeout,
Sockoption::AcceptTimeout => wasmer_vnet::TimeType::AcceptTimeout, Sockoption::AcceptTimeout => TimeType::AcceptTimeout,
Sockoption::Linger => wasmer_vnet::TimeType::Linger, Sockoption::Linger => TimeType::Linger,
_ => return Errno::Inval, _ => return Errno::Inval,
}; };
@@ -38,15 +38,13 @@ pub fn sock_set_opt_size(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |mut socket| async move { |mut socket, _| match opt {
match opt { Sockoption::RecvBufSize => socket.set_recv_buf_size(size as usize),
Sockoption::RecvBufSize => socket.set_recv_buf_size(size as usize).await, Sockoption::SendBufSize => socket.set_send_buf_size(size as usize),
Sockoption::SendBufSize => socket.set_send_buf_size(size as usize).await, Sockoption::Ttl => socket.set_ttl(size as u32),
Sockoption::Ttl => socket.set_ttl(size as u32).await, Sockoption::MulticastTtlV4 => socket.set_multicast_ttl_v4(size as u32),
Sockoption::MulticastTtlV4 => socket.set_multicast_ttl_v4(size as u32).await,
_ => Err(Errno::Inval), _ => Err(Errno::Inval),
} }
}
)); ));
Errno::Success Errno::Success
} }

View File

@@ -1,5 +1,5 @@
use super::*; use super::*;
use crate::syscalls::*; use crate::{net::socket::TimeType, syscalls::*};
/// ### `sock_set_opt_time()` /// ### `sock_set_opt_time()`
/// Sets one of the times the socket /// Sets one of the times the socket
@@ -33,11 +33,11 @@ pub fn sock_set_opt_time<M: MemorySize>(
}; };
let ty = match opt { let ty = match opt {
Sockoption::RecvTimeout => wasmer_vnet::TimeType::ReadTimeout, Sockoption::RecvTimeout => TimeType::ReadTimeout,
Sockoption::SendTimeout => wasmer_vnet::TimeType::WriteTimeout, Sockoption::SendTimeout => TimeType::WriteTimeout,
Sockoption::ConnectTimeout => wasmer_vnet::TimeType::ConnectTimeout, Sockoption::ConnectTimeout => TimeType::ConnectTimeout,
Sockoption::AcceptTimeout => wasmer_vnet::TimeType::AcceptTimeout, Sockoption::AcceptTimeout => TimeType::AcceptTimeout,
Sockoption::Linger => wasmer_vnet::TimeType::Linger, Sockoption::Linger => TimeType::Linger,
_ => return Errno::Inval, _ => return Errno::Inval,
}; };
@@ -46,7 +46,7 @@ pub fn sock_set_opt_time<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { socket.set_opt_time(ty, time).await } |socket, _| socket.set_opt_time(ty, time)
)); ));
Errno::Success Errno::Success
} }

View File

@@ -28,7 +28,7 @@ pub fn sock_shutdown(mut ctx: FunctionEnvMut<'_, WasiEnv>, sock: WasiFd, how: Sd
&mut ctx, &mut ctx,
sock, sock,
Rights::SOCK_SHUTDOWN, Rights::SOCK_SHUTDOWN,
move |mut socket| async move { socket.shutdown(how).await } |mut socket, _| socket.shutdown(how)
)); ));
Errno::Success Errno::Success

View File

@@ -19,7 +19,7 @@ pub fn sock_status<M: MemorySize>(
&mut ctx, &mut ctx,
sock, sock,
Rights::empty(), Rights::empty(),
move |socket| async move { socket.status().await } |socket, _| socket.status()
)); ));
use crate::net::socket::WasiSocketStatus; use crate::net::socket::WasiSocketStatus;

View File

@@ -10,6 +10,13 @@ use crate::syscalls::*;
pub fn thread_sleep( pub fn thread_sleep(
mut ctx: FunctionEnvMut<'_, WasiEnv>, mut ctx: FunctionEnvMut<'_, WasiEnv>,
duration: Timestamp, duration: Timestamp,
) -> Result<Errno, WasiError> {
thread_sleep_internal(ctx, duration)
}
pub(crate) fn thread_sleep_internal(
mut ctx: FunctionEnvMut<'_, WasiEnv>,
duration: Timestamp,
) -> Result<Errno, WasiError> { ) -> Result<Errno, WasiError> {
/* /*
trace!( trace!(