Many bug fixes and performance optimizations

- Removed generation_arena which was causing some serious leakages of files and sockets
- Added OsError for NetworkErrors so that "Too Many Open Files" is properly passed
- Local networking will now cap at 10 sockets in the backlog
- Added the missing shutdown error code
- Removed the inodes lock around most of the WASI syscalls
- Fixed some race conditions in the event notifications for WASI
- The polling loop will now only notify a closed socket once
- Event notifications now uses Wakers rather than MPSC
- Some socket errors now return the right codes which prevents panics in WASM
- Fixed a bug where the file read and write guards might release the file before the lock
- The inode seed is now much safer preventing overlaps
- The fd seed is now much safer preventing overlaps
- Closing files is now implicit rather than explicit reducing possibliities for error
- Forking of file descriptors is now much simplier
- Polling events will now be returned in random order to prevent some race conditions
- Removed a number of memory allocations which were wasting memory and performance
- Sockets now only copy the send and recv data once rather than multiple times
This commit is contained in:
Johnathan Sharratt
2023-02-15 16:13:48 +11:00
parent 21237eb3d3
commit c12a60f9a7
60 changed files with 1351 additions and 1335 deletions

61
Cargo.lock generated
View File

@@ -125,6 +125,15 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "atomic-polyfill"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28"
dependencies = [
"critical-section",
]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@@ -732,6 +741,12 @@ dependencies = [
"itertools", "itertools",
] ]
[[package]]
name = "critical-section"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52"
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.6" version = "0.5.6"
@@ -1332,16 +1347,6 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "generational-arena"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e1d3b771574f62d0548cee0ad9057857e9fc25d7a3335f140c84f6acd0bf601"
dependencies = [
"cfg-if 0.1.10",
"serde",
]
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.6" version = "0.14.6"
@@ -1511,6 +1516,15 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hash32"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
dependencies = [
"byteorder",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.11.2" version = "0.11.2"
@@ -1538,6 +1552,19 @@ dependencies = [
"hashbrown 0.12.3", "hashbrown 0.12.3",
] ]
[[package]]
name = "heapless"
version = "0.7.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743"
dependencies = [
"atomic-polyfill",
"hash32",
"rustc_version 0.4.0",
"spin 0.9.5",
"stable_deref_trait",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.3.3" version = "0.3.3"
@@ -2985,7 +3012,7 @@ dependencies = [
"cc", "cc",
"libc", "libc",
"once_cell", "once_cell",
"spin", "spin 0.5.2",
"untrusted", "untrusted",
"web-sys", "web-sys",
"winapi", "winapi",
@@ -3506,6 +3533,15 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spin"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc"
dependencies = [
"lock_api",
]
[[package]] [[package]]
name = "spinoff" name = "spinoff"
version = "0.5.4" version = "0.5.4"
@@ -5135,6 +5171,7 @@ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
"thiserror", "thiserror",
"tracing",
"wasmer-vfs", "wasmer-vfs",
] ]
@@ -5151,8 +5188,8 @@ dependencies = [
"cooked-waker", "cooked-waker",
"derivative", "derivative",
"futures", "futures",
"generational-arena",
"getrandom", "getrandom",
"heapless",
"hex", "hex",
"http", "http",
"lazy_static", "lazy_static",

View File

@@ -11,6 +11,7 @@ thiserror = "1"
wasmer-vfs = { path = "../vfs", version = "=3.2.0-alpha.1", default-features = false } wasmer-vfs = { path = "../vfs", version = "=3.2.0-alpha.1", default-features = false }
bytes = "1" bytes = "1"
async-trait = { version = "^0.1" } async-trait = { version = "^0.1" }
tracing = "0.1"
[features] [features]
default = [] default = []

View File

@@ -554,6 +554,9 @@ pub enum NetworkError {
/// A call to write returned 0 /// A call to write returned 0
#[error("write returned 0")] #[error("write returned 0")]
WriteZero, WriteZero,
/// OS error
#[error("operating system error({0})")]
OsError(i32),
/// The operation is not supported. /// The operation is not supported.
#[error("unsupported")] #[error("unsupported")]
Unsupported, Unsupported,
@@ -563,6 +566,7 @@ pub enum NetworkError {
} }
pub fn net_error_into_io_err(net_error: NetworkError) -> std::io::Error { pub fn net_error_into_io_err(net_error: NetworkError) -> std::io::Error {
use std::io::Error;
use std::io::ErrorKind; use std::io::ErrorKind;
match net_error { match net_error {
NetworkError::InvalidFd => ErrorKind::BrokenPipe.into(), NetworkError::InvalidFd => ErrorKind::BrokenPipe.into(),
@@ -585,6 +589,7 @@ pub fn net_error_into_io_err(net_error: NetworkError) -> std::io::Error {
NetworkError::UnexpectedEof => ErrorKind::UnexpectedEof.into(), NetworkError::UnexpectedEof => ErrorKind::UnexpectedEof.into(),
NetworkError::WouldBlock => ErrorKind::WouldBlock.into(), NetworkError::WouldBlock => ErrorKind::WouldBlock.into(),
NetworkError::WriteZero => ErrorKind::WriteZero.into(), NetworkError::WriteZero => ErrorKind::WriteZero.into(),
NetworkError::OsError(code) => Error::from_raw_os_error(code),
NetworkError::Unsupported => ErrorKind::Unsupported.into(), NetworkError::Unsupported => ErrorKind::Unsupported.into(),
NetworkError::UnknownError => ErrorKind::BrokenPipe.into(), NetworkError::UnknownError => ErrorKind::BrokenPipe.into(),
} }
@@ -610,6 +615,12 @@ pub fn io_err_into_net_error(net_error: std::io::Error) -> NetworkError {
ErrorKind::WouldBlock => NetworkError::WouldBlock, ErrorKind::WouldBlock => NetworkError::WouldBlock,
ErrorKind::WriteZero => NetworkError::WriteZero, ErrorKind::WriteZero => NetworkError::WriteZero,
ErrorKind::Unsupported => NetworkError::Unsupported, ErrorKind::Unsupported => NetworkError::Unsupported,
_ => NetworkError::UnknownError, _ => {
if let Some(code) = net_error.raw_os_error() {
NetworkError::OsError(code)
} else {
NetworkError::UnknownError
}
}
} }
} }

View File

@@ -11,6 +11,6 @@ use wasmer_wasi::os::fs::WasiFs;
use wasmer_wasi::os::fs::WasiInodes; use wasmer_wasi::os::fs::WasiInodes;
#[cfg(not(feature = "link_external_libs"))] #[cfg(not(feature = "link_external_libs"))]
pub fn initialize(_: &mut WasiInodes, _: &mut WasiFs) -> Result<(), String> { pub fn initialize(_: &WasiInodes, _: &mut WasiFs) -> Result<(), String> {
Err("wasi-experimental-io-devices has to be compiled with --features=\"link_external_libs\" (not enabled by default) for graphics I/O to work".to_string()) Err("wasi-experimental-io-devices has to be compiled with --features=\"link_external_libs\" (not enabled by default) for graphics I/O to work".to_string())
} }

View File

@@ -430,7 +430,7 @@ impl VirtualFile for FrameBuffer {
} }
} }
pub fn initialize(inodes: &mut WasiInodes, fs: &mut WasiFs) -> Result<(), String> { pub fn initialize(inodes: &WasiInodes, fs: &mut WasiFs) -> Result<(), String> {
let frame_buffer_file = Box::new(FrameBuffer { let frame_buffer_file = Box::new(FrameBuffer {
fb_type: FrameBufferFileType::Buffer, fb_type: FrameBufferFileType::Buffer,
cursor: 0, cursor: 0,

View File

@@ -140,6 +140,12 @@ impl VirtualTcpListener for LocalTcpListener {
&mut self, &mut self,
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<usize>> { ) -> std::task::Poll<Result<usize>> {
{
let backlog = self.backlog.lock().unwrap();
if backlog.len() > 10 {
return Poll::Ready(Ok(backlog.len()));
}
}
self.stream self.stream
.poll_accept(cx) .poll_accept(cx)
.map_err(io_err_into_net_error) .map_err(io_err_into_net_error)

View File

@@ -245,6 +245,8 @@ enum errno {
xdev, xdev,
/// Extension: Capabilities insufficient. /// Extension: Capabilities insufficient.
notcapable, notcapable,
/// Cannot send after socket shutdown.
shutdown,
} }
enum bus-errno { enum bus-errno {

View File

@@ -246,6 +246,8 @@ pub enum Errno {
Xdev, Xdev,
#[doc = " Extension: Capabilities insufficient."] #[doc = " Extension: Capabilities insufficient."]
Notcapable, Notcapable,
#[doc = " Cannot send after socket shutdown."]
Shutdown,
} }
impl Errno { impl Errno {
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
@@ -327,6 +329,7 @@ impl Errno {
Errno::Txtbsy => "txtbsy", Errno::Txtbsy => "txtbsy",
Errno::Xdev => "xdev", Errno::Xdev => "xdev",
Errno::Notcapable => "notcapable", Errno::Notcapable => "notcapable",
Errno::Shutdown => "shutdown",
} }
} }
pub fn message(&self) -> &'static str { pub fn message(&self) -> &'static str {
@@ -408,6 +411,7 @@ impl Errno {
Errno::Txtbsy => "Text file busy.", Errno::Txtbsy => "Text file busy.",
Errno::Xdev => "Cross-device link.", Errno::Xdev => "Cross-device link.",
Errno::Notcapable => "Extension: Capabilities insufficient.", Errno::Notcapable => "Extension: Capabilities insufficient.",
Errno::Shutdown => "Cannot send after socket shutdown.",
} }
} }
} }

View File

@@ -13,7 +13,6 @@ edition = "2018"
[dependencies] [dependencies]
cfg-if = "1.0" cfg-if = "1.0"
thiserror = "1" thiserror = "1"
generational-arena = { version = "0.2" }
tracing = "0.1" tracing = "0.1"
getrandom = "0.2" getrandom = "0.2"
wasmer-wasi-types = { path = "../wasi-types", version = "=3.2.0-alpha.1" } wasmer-wasi-types = { path = "../wasi-types", version = "=3.2.0-alpha.1" }
@@ -61,6 +60,7 @@ wasmer-compiler-singlepass = { version = "=3.2.0-alpha.1", path = "../compiler-s
wasmer-compiler = { version = "=3.2.0-alpha.1", path = "../compiler", features = [ "translator" ], optional = true } wasmer-compiler = { version = "=3.2.0-alpha.1", path = "../compiler", features = [ "translator" ], optional = true }
http = "0.2.8" http = "0.2.8"
wai-bindgen-wasmer = { path = "../wai-bindgen-wasmer", version = "0.2.3", features = ["tracing"] } wai-bindgen-wasmer = { path = "../wai-bindgen-wasmer", version = "0.2.3", features = ["tracing"] }
heapless = "0.7.16"
[dependencies.reqwest] [dependencies.reqwest]
version = "0.11" version = "0.11"
@@ -125,6 +125,5 @@ disable-all-logging = [
enable-serde = [ enable-serde = [
"typetag", "typetag",
"wasmer-vfs/enable-serde", "wasmer-vfs/enable-serde",
"generational-arena/serde",
"wasmer-wasi-types/enable-serde", "wasmer-wasi-types/enable-serde",
] ]

View File

@@ -2,13 +2,10 @@ use std::{
borrow::Cow, borrow::Cow,
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},
path::PathBuf, path::PathBuf,
sync::{ sync::{atomic::AtomicU64, Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard},
atomic::{AtomicBool, AtomicU32, AtomicU64}, task::Waker,
Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard,
},
}; };
use generational_arena::Index as Inode;
#[cfg(feature = "enable-serde")] #[cfg(feature = "enable-serde")]
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use wasmer_vfs::{VirtualFile, WasiPipe}; use wasmer_vfs::{VirtualFile, WasiPipe};
@@ -16,12 +13,11 @@ use wasmer_wasi_types::wasi::{Fd as WasiFd, Fdflags, Filestat, Rights};
use crate::net::socket::InodeSocket; use crate::net::socket::InodeSocket;
use super::{InodeGuard, InodeWeakGuard};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct Fd { pub struct Fd {
/// The reference count is only increased when the FD is
/// duplicates - fd_close will not kill the inode until this reaches zero
pub ref_cnt: Arc<AtomicU32>,
pub rights: Rights, pub rights: Rights,
pub rights_inheriting: Rights, pub rights_inheriting: Rights,
pub flags: Fdflags, pub flags: Fdflags,
@@ -30,7 +26,7 @@ pub struct Fd {
/// ///
/// Used when reopening a [`VirtualFile`] during [`WasiState`] deserialization. /// Used when reopening a [`VirtualFile`] during [`WasiState`] deserialization.
pub open_flags: u16, pub open_flags: u16,
pub inode: Inode, pub inode: InodeGuard,
pub is_stdio: bool, pub is_stdio: bool,
} }
@@ -74,6 +70,21 @@ impl InodeVal {
} }
} }
#[derive(Debug)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct NotificationInner {
/// Used for event notifications by the user application or operating system
/// (positive number means there are events waiting to be processed)
pub counter: AtomicU64,
/// Counter used to prevent duplicate notification events
pub last_poll: AtomicU64,
/// Flag that indicates if this is operating
pub is_semaphore: bool,
/// Receiver that wakes sleeping threads
#[cfg_attr(feature = "enable-serde", serde(skip))]
pub wakers: Mutex<VecDeque<Waker>>,
}
/// The core of the filesystem abstraction. Includes directories, /// The core of the filesystem abstraction. Includes directories,
/// files, and symlinks. /// files, and symlinks.
#[derive(Debug)] #[derive(Debug)]
@@ -104,19 +115,19 @@ pub enum Kind {
}, },
Dir { Dir {
/// Parent directory /// Parent directory
parent: Option<Inode>, parent: InodeWeakGuard,
/// The path on the host system where the directory is located /// The path on the host system where the directory is located
// TODO: wrap it like VirtualFile // TODO: wrap it like VirtualFile
path: PathBuf, path: PathBuf,
/// The entries of a directory are lazily filled. /// The entries of a directory are lazily filled.
entries: HashMap<String, Inode>, entries: HashMap<String, InodeGuard>,
}, },
/// The same as Dir but without the irrelevant bits /// The same as Dir but without the irrelevant bits
/// The root is immutable after creation; generally the Kind::Root /// The root is immutable after creation; generally the Kind::Root
/// branch of whatever code you're writing will be a simpler version of /// branch of whatever code you're writing will be a simpler version of
/// your Kind::Dir logic /// your Kind::Dir logic
Root { Root {
entries: HashMap<String, Inode>, entries: HashMap<String, InodeGuard>,
}, },
/// The first two fields are data _about_ the symlink /// The first two fields are data _about_ the symlink
/// the last field is the data _inside_ the symlink /// the last field is the data _inside_ the symlink
@@ -135,16 +146,5 @@ pub enum Kind {
Buffer { Buffer {
buffer: Vec<u8>, buffer: Vec<u8>,
}, },
EventNotifications { EventNotifications(Arc<NotificationInner>),
/// Used for event notifications by the user application or operating system
/// (positive number means there are events waiting to be processed)
counter: Arc<AtomicU64>,
/// Flag that indicates if this is operating
is_semaphore: bool,
/// Receiver that wakes sleeping threads
#[cfg_attr(feature = "enable-serde", serde(skip))]
wakers: Arc<Mutex<VecDeque<tokio::sync::mpsc::UnboundedSender<()>>>>,
/// Immediate waker
immediate: Arc<AtomicBool>,
},
} }

View File

@@ -3,17 +3,11 @@ use std::{
io::{IoSlice, SeekFrom}, io::{IoSlice, SeekFrom},
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
pin::Pin, pin::Pin,
sync::{ sync::{atomic::Ordering, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
atomic::{AtomicU64, Ordering},
Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard,
},
task::{Context, Poll}, task::{Context, Poll},
}; };
use tokio::{ use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
io::{AsyncRead, AsyncSeek, AsyncWrite},
sync::mpsc,
};
use wasmer_vfs::{FsError, VirtualFile}; use wasmer_vfs::{FsError, VirtualFile};
use wasmer_vnet::{net_error_into_io_err, NetworkError}; use wasmer_vnet::{net_error_into_io_err, NetworkError};
use wasmer_wasi_types::{ use wasmer_wasi_types::{
@@ -22,24 +16,18 @@ use wasmer_wasi_types::{
wasi::{Errno, Event, EventFdReadwrite, EventUnion, Eventrwflags, Subscription}, wasi::{Errno, Event, EventFdReadwrite, EventUnion, Eventrwflags, Subscription},
}; };
use super::Kind; use super::{fd::NotificationInner, InodeGuard, Kind};
use crate::{ use crate::{
net::socket::{InodeSocketInner, InodeSocketKind}, net::socket::{InodeSocketInner, InodeSocketKind},
state::{iterate_poll_events, PollEvent, PollEventSet}, state::{iterate_poll_events, PollEvent, PollEventSet},
syscalls::map_io_err, syscalls::map_io_err,
WasiInodes, WasiState, WasiState,
}; };
pub(crate) enum InodeValFilePollGuardMode { pub(crate) enum InodeValFilePollGuardMode {
File(Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>), File(Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>),
EventNotifications { EventNotifications(Arc<NotificationInner>),
immediate: bool, Socket { inner: Arc<InodeSocketInner> },
waker: Mutex<mpsc::UnboundedReceiver<()>>,
counter: Arc<AtomicU64>,
},
Socket {
inner: Arc<RwLock<InodeSocketInner>>,
},
} }
pub(crate) struct InodeValFilePollGuard { pub(crate) struct InodeValFilePollGuard {
@@ -57,25 +45,8 @@ impl InodeValFilePollGuard {
guard: &Kind, guard: &Kind,
) -> Option<Self> { ) -> Option<Self> {
let mode = match guard.deref() { let mode = match guard.deref() {
Kind::EventNotifications { Kind::EventNotifications(inner) => {
counter, InodeValFilePollGuardMode::EventNotifications(inner.clone())
wakers,
immediate,
..
} => {
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
let immediate = {
let mut wakers = wakers.lock().unwrap();
wakers.push_back(tx);
immediate
.compare_exchange(true, false, Ordering::AcqRel, Ordering::Relaxed)
.is_ok()
};
InodeValFilePollGuardMode::EventNotifications {
immediate,
waker: Mutex::new(rx),
counter: counter.clone(),
}
} }
Kind::Socket { socket } => InodeValFilePollGuardMode::Socket { Kind::Socket { socket } => InodeValFilePollGuardMode::Socket {
inner: socket.inner.clone(), inner: socket.inner.clone(),
@@ -105,7 +76,7 @@ impl std::fmt::Debug for InodeValFilePollGuard {
write!(f, "guard-notifications") write!(f, "guard-notifications")
} }
InodeValFilePollGuardMode::Socket { inner } => { InodeValFilePollGuardMode::Socket { inner } => {
let inner = inner.read().unwrap(); let inner = inner.protected.read().unwrap();
match inner.kind { match inner.kind {
InodeSocketKind::TcpListener { .. } => write!(f, "guard-tcp-listener"), InodeSocketKind::TcpListener { .. } => write!(f, "guard-tcp-listener"),
InodeSocketKind::TcpStream { ref socket, .. } => { InodeSocketKind::TcpStream { ref socket, .. } => {
@@ -125,20 +96,6 @@ impl std::fmt::Debug for InodeValFilePollGuard {
} }
} }
impl InodeValFilePollGuard {
#[allow(dead_code)]
pub fn is_open(&self) -> bool {
match &self.mode {
InodeValFilePollGuardMode::File(file) => {
let guard = file.read().unwrap();
guard.is_open()
}
InodeValFilePollGuardMode::EventNotifications { .. }
| InodeValFilePollGuardMode::Socket { .. } => true,
}
}
}
pub(crate) struct InodeValFilePollGuardJoin<'a> { pub(crate) struct InodeValFilePollGuardJoin<'a> {
mode: &'a mut InodeValFilePollGuardMode, mode: &'a mut InodeValFilePollGuardMode,
fd: u32, fd: u32,
@@ -161,14 +118,17 @@ impl<'a> InodeValFilePollGuardJoin<'a> {
} }
impl<'a> Future for InodeValFilePollGuardJoin<'a> { impl<'a> Future for InodeValFilePollGuardJoin<'a> {
type Output = Event; type Output = heapless::Vec<Event, 4>;
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 fd = self.fd();
let waker = cx.waker();
let mut has_read = false; let mut has_read = false;
let mut has_write = false; let mut has_write = false;
let mut has_close = false; let mut has_close = false;
let mut has_hangup = false; let mut has_hangup = false;
let mut ret = heapless::Vec::new();
for in_event in iterate_poll_events(self.peb) { for in_event in iterate_poll_events(self.peb) {
match in_event { match in_event {
PollEvent::PollIn => { PollEvent::PollIn => {
@@ -197,10 +157,8 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
} }
InodeValFilePollGuardMode::EventNotifications { .. } => false, InodeValFilePollGuardMode::EventNotifications { .. } => false,
InodeValFilePollGuardMode::Socket { ref inner } => { InodeValFilePollGuardMode::Socket { ref inner } => {
let mut guard = inner.write().unwrap(); let mut guard = inner.protected.write().unwrap();
let is_closed = if let InodeSocketKind::Closed = guard.kind { let is_closed = if has_read || has_write {
true
} 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 {
@@ -217,11 +175,15 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
_ => false, _ => false,
} }
}; };
is_closed if is_closed {
std::mem::replace(&mut guard.notifications.closed, true) == false
} else {
false
}
} }
}; };
if is_closed { if is_closed {
return Poll::Ready(Event { ret.push(Event {
userdata: self.subscription.userdata, userdata: self.subscription.userdata,
error: Errno::Success, error: Errno::Success,
type_: self.subscription.type_, type_: self.subscription.type_,
@@ -238,192 +200,211 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
}, },
Eventtype::Clock => EventUnion { clock: 0 }, Eventtype::Clock => EventUnion { clock: 0 },
}, },
}); })
.ok();
} }
} }
if has_read { if has_read {
let mut poll_result = match &mut self.mode { let poll_result = match &mut self.mode {
InodeValFilePollGuardMode::File(file) => { InodeValFilePollGuardMode::File(file) => {
let mut guard = file.write().unwrap(); let mut guard = file.write().unwrap();
let file = Pin::new(guard.as_mut()); let file = Pin::new(guard.as_mut());
file.poll_read_ready(cx) file.poll_read_ready(cx)
} }
InodeValFilePollGuardMode::EventNotifications { InodeValFilePollGuardMode::EventNotifications(inner) => {
waker, {
counter, let mut guard = inner.wakers.lock().unwrap();
immediate, if guard.iter().any(|a| a.will_wake(waker)) == false {
.. guard.push_front(waker.clone());
} => { }
if *immediate { }
let cnt = counter.load(Ordering::Acquire); let val = inner.counter.load(Ordering::Acquire);
Poll::Ready(Ok(cnt as usize)) if inner.last_poll.swap(val, Ordering::AcqRel) != val {
Poll::Ready(Ok(val as usize))
} else { } else {
let counter = counter.clone(); Poll::Pending
let mut waker = waker.lock().unwrap();
let mut notifications = Pin::new(waker.deref_mut());
notifications.poll_recv(cx).map(|_| {
let cnt = counter.load(Ordering::Acquire);
Ok(cnt as usize)
})
} }
} }
InodeValFilePollGuardMode::Socket { ref inner } => { InodeValFilePollGuardMode::Socket { ref inner } => {
let mut guard = inner.write().unwrap(); let mut guard = inner.protected.write().unwrap();
guard.poll_read_ready(cx).map_err(net_error_into_io_err) let res = guard.poll_read_ready(cx).map_err(net_error_into_io_err);
match res {
Poll::Ready(Err(err)) if is_err_closed(&err) => {
tracing::trace!("socket read ready error (fd={}) - {}", fd, err);
if std::mem::replace(&mut guard.notifications.closed, true) == false {
Poll::Ready(Ok(0))
} else {
Poll::Pending
}
}
Poll::Ready(Err(err)) => {
tracing::debug!("poll socket error - {}", err);
if std::mem::replace(&mut guard.notifications.failed, true) == false {
Poll::Ready(Ok(0))
} else {
Poll::Pending
}
}
res => res,
}
} }
}; };
if has_close { match poll_result {
poll_result = match poll_result { Poll::Ready(Err(err)) if has_close && is_err_closed(&err) => {
Poll::Ready(Err(err)) ret.push(Event {
if err.kind() == std::io::ErrorKind::ConnectionAborted userdata: self.subscription.userdata,
|| err.kind() == std::io::ErrorKind::ConnectionRefused error: Errno::Success,
|| err.kind() == std::io::ErrorKind::ConnectionReset type_: self.subscription.type_,
|| err.kind() == std::io::ErrorKind::BrokenPipe u: match self.subscription.type_ {
|| err.kind() == std::io::ErrorKind::NotConnected Eventtype::FdRead | Eventtype::FdWrite => EventUnion {
|| err.kind() == std::io::ErrorKind::UnexpectedEof => fd_readwrite: EventFdReadwrite {
{ nbytes: 0,
return Poll::Ready(Event { flags: if has_hangup {
userdata: self.subscription.userdata, Eventrwflags::FD_READWRITE_HANGUP
error: Errno::Success, } else {
type_: self.subscription.type_, Eventrwflags::empty()
u: match self.subscription.type_ {
Eventtype::FdRead | Eventtype::FdWrite => EventUnion {
fd_readwrite: EventFdReadwrite {
nbytes: 0,
flags: if has_hangup {
Eventrwflags::FD_READWRITE_HANGUP
} else {
Eventrwflags::empty()
},
}, },
}, },
Eventtype::Clock => EventUnion { clock: 0 },
}, },
}); Eventtype::Clock => EventUnion { clock: 0 },
} },
a => a, })
}; .ok();
} }
if let Poll::Ready(bytes_available) = poll_result { Poll::Ready(bytes_available) => {
let mut error = Errno::Success; let mut error = Errno::Success;
let bytes_available = match bytes_available { let bytes_available = match bytes_available {
Ok(a) => a, Ok(a) => a,
Err(e) => { Err(e) => {
error = map_io_err(e); error = map_io_err(e);
0 0
} }
}; };
return Poll::Ready(Event { ret.push(Event {
userdata: self.subscription.userdata, userdata: self.subscription.userdata,
error, error,
type_: self.subscription.type_, type_: self.subscription.type_,
u: match self.subscription.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,
flags: if bytes_available == 0 { flags: if bytes_available == 0 {
Eventrwflags::FD_READWRITE_HANGUP Eventrwflags::FD_READWRITE_HANGUP
} else { } else {
Eventrwflags::empty() Eventrwflags::empty()
},
}, },
}, },
Eventtype::Clock => EventUnion { clock: 0 },
}, },
Eventtype::Clock => EventUnion { clock: 0 }, })
}, .ok();
}); }
} Poll::Pending => {}
};
} }
if has_write { if has_write {
let mut poll_result = match &mut self.mode { let poll_result = match &mut self.mode {
InodeValFilePollGuardMode::File(file) => { InodeValFilePollGuardMode::File(file) => {
let mut guard = file.write().unwrap(); let mut guard = file.write().unwrap();
let file = Pin::new(guard.as_mut()); let file = Pin::new(guard.as_mut());
file.poll_write_ready(cx) file.poll_write_ready(cx)
} }
InodeValFilePollGuardMode::EventNotifications { InodeValFilePollGuardMode::EventNotifications(inner) => {
waker, {
counter, let mut guard = inner.wakers.lock().unwrap();
immediate, if guard.iter().any(|a| a.will_wake(waker)) == false {
.. guard.push_front(waker.clone());
} => { }
if *immediate { }
let cnt = counter.load(Ordering::Acquire); let val = inner.counter.load(Ordering::Acquire);
Poll::Ready(Ok(cnt as usize)) if inner.last_poll.swap(val, Ordering::AcqRel) != val {
Poll::Ready(Ok(val as usize))
} else { } else {
let counter = counter.clone(); Poll::Pending
let mut waker = waker.lock().unwrap();
let mut notifications = Pin::new(waker.deref_mut());
notifications.poll_recv(cx).map(|_| {
let cnt = counter.load(Ordering::Acquire);
Ok(cnt as usize)
})
} }
} }
InodeValFilePollGuardMode::Socket { ref inner } => { InodeValFilePollGuardMode::Socket { ref inner } => {
let mut guard = inner.write().unwrap(); let mut guard = inner.protected.write().unwrap();
guard.poll_write_ready(cx).map_err(net_error_into_io_err) let res = guard.poll_write_ready(cx).map_err(net_error_into_io_err);
match res {
Poll::Ready(Err(err)) if is_err_closed(&err) => {
tracing::trace!("socket write ready error (fd={}) - {}", fd, err);
if std::mem::replace(&mut guard.notifications.closed, true) == false {
Poll::Ready(Ok(0))
} else {
Poll::Pending
}
}
Poll::Ready(Err(err)) => {
tracing::debug!("poll socket error - {}", err);
if std::mem::replace(&mut guard.notifications.failed, true) == false {
Poll::Ready(Ok(0))
} else {
Poll::Pending
}
}
res => res,
}
} }
}; };
if has_close { match poll_result {
poll_result = match poll_result { Poll::Ready(Err(err)) if has_close && is_err_closed(&err) => {
Poll::Ready(Err(err)) ret.push(Event {
if err.kind() == std::io::ErrorKind::ConnectionAborted userdata: self.subscription.userdata,
|| err.kind() == std::io::ErrorKind::ConnectionRefused error: Errno::Success,
|| err.kind() == std::io::ErrorKind::ConnectionReset type_: self.subscription.type_,
|| err.kind() == std::io::ErrorKind::BrokenPipe u: match self.subscription.type_ {
|| err.kind() == std::io::ErrorKind::NotConnected Eventtype::FdRead | Eventtype::FdWrite => EventUnion {
|| err.kind() == std::io::ErrorKind::UnexpectedEof => fd_readwrite: EventFdReadwrite {
{ nbytes: 0,
return Poll::Ready(Event { flags: if has_hangup {
userdata: self.subscription.userdata, Eventrwflags::FD_READWRITE_HANGUP
error: Errno::Success, } else {
type_: self.subscription.type_, Eventrwflags::empty()
u: match self.subscription.type_ {
Eventtype::FdRead | Eventtype::FdWrite => EventUnion {
fd_readwrite: EventFdReadwrite {
nbytes: 0,
flags: if has_hangup {
Eventrwflags::FD_READWRITE_HANGUP
} else {
Eventrwflags::empty()
},
}, },
}, },
Eventtype::Clock => EventUnion { clock: 0 },
}, },
}); Eventtype::Clock => EventUnion { clock: 0 },
} },
a => a, })
}; .ok();
} }
if let Poll::Ready(bytes_available) = poll_result { Poll::Ready(bytes_available) => {
let mut error = Errno::Success; let mut error = Errno::Success;
let bytes_available = match bytes_available { let bytes_available = match bytes_available {
Ok(a) => a, Ok(a) => a,
Err(e) => { Err(e) => {
error = map_io_err(e); error = map_io_err(e);
0 0
} }
}; };
return Poll::Ready(Event { ret.push(Event {
userdata: self.subscription.userdata, userdata: self.subscription.userdata,
error, error,
type_: self.subscription.type_, type_: self.subscription.type_,
u: match self.subscription.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,
flags: if bytes_available == 0 { flags: if bytes_available == 0 {
Eventrwflags::FD_READWRITE_HANGUP Eventrwflags::FD_READWRITE_HANGUP
} else { } else {
Eventrwflags::empty() Eventrwflags::empty()
},
}, },
}, },
Eventtype::Clock => EventUnion { clock: 0 },
}, },
Eventtype::Clock => EventUnion { clock: 0 }, })
}, .ok();
}); }
} Poll::Pending => {}
};
}
if ret.len() > 0 {
return Poll::Ready(ret);
} }
Poll::Pending Poll::Pending
} }
@@ -431,16 +412,18 @@ impl<'a> Future for InodeValFilePollGuardJoin<'a> {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct InodeValFileReadGuard { pub(crate) struct InodeValFileReadGuard {
#[allow(dead_code)]
file: Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>,
guard: RwLockReadGuard<'static, Box<dyn VirtualFile + Send + Sync + 'static>>, guard: RwLockReadGuard<'static, Box<dyn VirtualFile + Send + Sync + 'static>>,
// we must keep a reference as the lifetime of the guard becomes owned using unsafe code
// (warning!! The fields of a struct are dropped in declaration order thus this must be at the end)
// (https://doc.rust-lang.org/reference/destructors.html#:~:text=The%20fields%20of%20a%20struct,first%20element%20to%20the%20last.)
_file: Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>,
} }
impl InodeValFileReadGuard { impl InodeValFileReadGuard {
pub(crate) fn new(file: &Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>) -> Self { pub(crate) fn new(file: &Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>) -> Self {
let guard = file.read().unwrap(); let guard = file.read().unwrap();
Self { Self {
file: file.clone(), _file: file.clone(),
guard: unsafe { std::mem::transmute(guard) }, guard: unsafe { std::mem::transmute(guard) },
} }
} }
@@ -457,7 +440,7 @@ impl InodeValFileReadGuard {
fd, fd,
peb, peb,
subscription, subscription,
mode: InodeValFilePollGuardMode::File(self.file), mode: InodeValFilePollGuardMode::File(self._file),
} }
} }
} }
@@ -471,16 +454,18 @@ impl Deref for InodeValFileReadGuard {
#[derive(Debug)] #[derive(Debug)]
pub struct InodeValFileWriteGuard { pub struct InodeValFileWriteGuard {
#[allow(dead_code)]
file: Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>,
guard: RwLockWriteGuard<'static, Box<dyn VirtualFile + Send + Sync + 'static>>, guard: RwLockWriteGuard<'static, Box<dyn VirtualFile + Send + Sync + 'static>>,
// we must keep a reference as the lifetime of the guard becomes owned using unsafe code
// (warning!! The fields of a struct are dropped in declaration order thus this must be at the end)
// (https://doc.rust-lang.org/reference/destructors.html#:~:text=The%20fields%20of%20a%20struct,first%20element%20to%20the%20last.)
_file: Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>,
} }
impl InodeValFileWriteGuard { impl InodeValFileWriteGuard {
pub(crate) fn new(file: &Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>) -> Self { pub(crate) fn new(file: &Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>) -> Self {
let guard = file.write().unwrap(); let guard = file.write().unwrap();
Self { Self {
file: file.clone(), _file: file.clone(),
guard: unsafe { std::mem::transmute(guard) }, guard: unsafe { std::mem::transmute(guard) },
} }
} }
@@ -507,32 +492,23 @@ impl DerefMut for InodeValFileWriteGuard {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct WasiStateFileGuard { pub(crate) struct WasiStateFileGuard {
inodes: Arc<RwLock<WasiInodes>>, inode: InodeGuard,
inode: generational_arena::Index,
} }
impl WasiStateFileGuard { impl WasiStateFileGuard {
pub fn new(state: &WasiState, fd: wasi::Fd) -> Result<Option<Self>, FsError> { pub fn new(state: &WasiState, fd: wasi::Fd) -> Result<Option<Self>, FsError> {
let inodes = state.inodes.read().unwrap();
let fd_map = state.fs.fd_map.read().unwrap(); let fd_map = state.fs.fd_map.read().unwrap();
if let Some(fd) = fd_map.get(&fd) { if let Some(fd) = fd_map.get(&fd) {
let guard = inodes.arena[fd.inode].read(); Ok(Some(Self {
if let Kind::File { .. } = guard.deref() { inode: fd.inode.clone(),
Ok(Some(Self { }))
inodes: state.inodes.clone(),
inode: fd.inode,
}))
} else {
// Our public API should ensure that this is not possible
Err(FsError::NotAFile)
}
} else { } else {
Ok(None) Ok(None)
} }
} }
pub fn lock_read(&self, inodes: &RwLockReadGuard<WasiInodes>) -> Option<InodeValFileReadGuard> { pub fn lock_read(&self) -> Option<InodeValFileReadGuard> {
let guard = inodes.arena[self.inode].read(); let guard = self.inode.read();
if let Kind::File { handle, .. } = guard.deref() { if let Kind::File { handle, .. } = guard.deref() {
handle.as_ref().map(InodeValFileReadGuard::new) handle.as_ref().map(InodeValFileReadGuard::new)
} else { } else {
@@ -541,11 +517,8 @@ impl WasiStateFileGuard {
} }
} }
pub fn lock_write( pub fn lock_write(&self) -> Option<InodeValFileWriteGuard> {
&self, let guard = self.inode.read();
inodes: &RwLockReadGuard<WasiInodes>,
) -> Option<InodeValFileWriteGuard> {
let guard = inodes.arena[self.inode].read();
if let Kind::File { handle, .. } = guard.deref() { if let Kind::File { handle, .. } = guard.deref() {
handle.as_ref().map(InodeValFileWriteGuard::new) handle.as_ref().map(InodeValFileWriteGuard::new)
} else { } else {
@@ -557,8 +530,7 @@ impl WasiStateFileGuard {
impl VirtualFile for WasiStateFileGuard { impl VirtualFile for WasiStateFileGuard {
fn last_accessed(&self) -> u64 { fn last_accessed(&self) -> u64 {
let inodes = self.inodes.read().unwrap(); let guard = self.lock_read();
let guard = self.lock_read(&inodes);
if let Some(file) = guard.as_ref() { if let Some(file) = guard.as_ref() {
file.last_accessed() file.last_accessed()
} else { } else {
@@ -567,8 +539,7 @@ impl VirtualFile for WasiStateFileGuard {
} }
fn last_modified(&self) -> u64 { fn last_modified(&self) -> u64 {
let inodes = self.inodes.read().unwrap(); let guard = self.lock_read();
let guard = self.lock_read(&inodes);
if let Some(file) = guard.as_ref() { if let Some(file) = guard.as_ref() {
file.last_modified() file.last_modified()
} else { } else {
@@ -577,8 +548,7 @@ impl VirtualFile for WasiStateFileGuard {
} }
fn created_time(&self) -> u64 { fn created_time(&self) -> u64 {
let inodes = self.inodes.read().unwrap(); let guard = self.lock_read();
let guard = self.lock_read(&inodes);
if let Some(file) = guard.as_ref() { if let Some(file) = guard.as_ref() {
file.created_time() file.created_time()
} else { } else {
@@ -587,8 +557,7 @@ impl VirtualFile for WasiStateFileGuard {
} }
fn size(&self) -> u64 { fn size(&self) -> u64 {
let inodes = self.inodes.read().unwrap(); let guard = self.lock_read();
let guard = self.lock_read(&inodes);
if let Some(file) = guard.as_ref() { if let Some(file) = guard.as_ref() {
file.size() file.size()
} else { } else {
@@ -597,8 +566,7 @@ impl VirtualFile for WasiStateFileGuard {
} }
fn set_len(&mut self, new_size: u64) -> Result<(), FsError> { fn set_len(&mut self, new_size: u64) -> Result<(), FsError> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(file) = guard.as_mut() { if let Some(file) = guard.as_mut() {
file.set_len(new_size) file.set_len(new_size)
} else { } else {
@@ -607,8 +575,7 @@ impl VirtualFile for WasiStateFileGuard {
} }
fn unlink(&mut self) -> Result<(), FsError> { fn unlink(&mut self) -> Result<(), FsError> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(file) = guard.as_mut() { if let Some(file) = guard.as_mut() {
file.unlink() file.unlink()
} else { } else {
@@ -617,8 +584,7 @@ impl VirtualFile for WasiStateFileGuard {
} }
fn is_open(&self) -> bool { fn is_open(&self) -> bool {
let inodes = self.inodes.read().unwrap(); let guard = self.lock_read();
let guard = self.lock_read(&inodes);
if let Some(file) = guard.as_ref() { if let Some(file) = guard.as_ref() {
file.is_open() file.is_open()
} else { } else {
@@ -627,8 +593,7 @@ impl VirtualFile for WasiStateFileGuard {
} }
fn poll_read_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<usize>> { fn poll_read_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<usize>> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(file) = guard.as_mut() { if let Some(file) = guard.as_mut() {
let file = Pin::new(file.deref_mut()); let file = Pin::new(file.deref_mut());
file.poll_read_ready(cx) file.poll_read_ready(cx)
@@ -641,8 +606,7 @@ impl VirtualFile for WasiStateFileGuard {
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<std::io::Result<usize>> { ) -> Poll<std::io::Result<usize>> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(file) = guard.as_mut() { if let Some(file) = guard.as_mut() {
let file = Pin::new(file.deref_mut()); let file = Pin::new(file.deref_mut());
file.poll_write_ready(cx) file.poll_write_ready(cx)
@@ -654,8 +618,7 @@ impl VirtualFile for WasiStateFileGuard {
impl AsyncSeek for WasiStateFileGuard { impl AsyncSeek for WasiStateFileGuard {
fn start_seek(self: Pin<&mut Self>, position: SeekFrom) -> std::io::Result<()> { fn start_seek(self: Pin<&mut Self>, position: SeekFrom) -> std::io::Result<()> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(guard) = guard.as_mut() { if let Some(guard) = guard.as_mut() {
let file = Pin::new(guard.deref_mut()); let file = Pin::new(guard.deref_mut());
file.start_seek(position) file.start_seek(position)
@@ -664,8 +627,7 @@ impl AsyncSeek for WasiStateFileGuard {
} }
} }
fn poll_complete(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<u64>> { fn poll_complete(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<u64>> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(guard) = guard.as_mut() { if let Some(guard) = guard.as_mut() {
let file = Pin::new(guard.deref_mut()); let file = Pin::new(guard.deref_mut());
file.poll_complete(cx) file.poll_complete(cx)
@@ -681,8 +643,7 @@ impl AsyncWrite for WasiStateFileGuard {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &[u8], buf: &[u8],
) -> Poll<std::io::Result<usize>> { ) -> Poll<std::io::Result<usize>> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(guard) = guard.as_mut() { if let Some(guard) = guard.as_mut() {
let file = Pin::new(guard.deref_mut()); let file = Pin::new(guard.deref_mut());
file.poll_write(cx, buf) file.poll_write(cx, buf)
@@ -691,8 +652,7 @@ impl AsyncWrite for WasiStateFileGuard {
} }
} }
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(guard) = guard.as_mut() { if let Some(guard) = guard.as_mut() {
let file = Pin::new(guard.deref_mut()); let file = Pin::new(guard.deref_mut());
file.poll_flush(cx) file.poll_flush(cx)
@@ -701,8 +661,7 @@ impl AsyncWrite for WasiStateFileGuard {
} }
} }
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(guard) = guard.as_mut() { if let Some(guard) = guard.as_mut() {
let file = Pin::new(guard.deref_mut()); let file = Pin::new(guard.deref_mut());
file.poll_shutdown(cx) file.poll_shutdown(cx)
@@ -715,8 +674,7 @@ impl AsyncWrite for WasiStateFileGuard {
cx: &mut Context<'_>, cx: &mut Context<'_>,
bufs: &[IoSlice<'_>], bufs: &[IoSlice<'_>],
) -> Poll<std::io::Result<usize>> { ) -> Poll<std::io::Result<usize>> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(guard) = guard.as_mut() { if let Some(guard) = guard.as_mut() {
let file = Pin::new(guard.deref_mut()); let file = Pin::new(guard.deref_mut());
file.poll_write_vectored(cx, bufs) file.poll_write_vectored(cx, bufs)
@@ -725,8 +683,7 @@ impl AsyncWrite for WasiStateFileGuard {
} }
} }
fn is_write_vectored(&self) -> bool { fn is_write_vectored(&self) -> bool {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(guard) = guard.as_mut() { if let Some(guard) = guard.as_mut() {
let file = Pin::new(guard.deref_mut()); let file = Pin::new(guard.deref_mut());
file.is_write_vectored() file.is_write_vectored()
@@ -742,8 +699,7 @@ impl AsyncRead for WasiStateFileGuard {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>, buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<std::io::Result<()>> { ) -> Poll<std::io::Result<()>> {
let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write();
let mut guard = self.lock_write(&inodes);
if let Some(guard) = guard.as_mut() { if let Some(guard) = guard.as_mut() {
let file = Pin::new(guard.deref_mut()); let file = Pin::new(guard.deref_mut());
file.poll_read(cx, buf) file.poll_read(cx, buf)
@@ -752,3 +708,12 @@ impl AsyncRead for WasiStateFileGuard {
} }
} }
} }
fn is_err_closed(err: &std::io::Error) -> bool {
err.kind() == std::io::ErrorKind::ConnectionAborted
|| err.kind() == std::io::ErrorKind::ConnectionRefused
|| err.kind() == std::io::ErrorKind::ConnectionReset
|| err.kind() == std::io::ErrorKind::BrokenPipe
|| err.kind() == std::io::ErrorKind::NotConnected
|| err.kind() == std::io::ErrorKind::UnexpectedEof
}

File diff suppressed because it is too large Load Diff

View File

@@ -86,6 +86,21 @@ macro_rules! wasi_try_bus_ok {
}}; }};
} }
/// Like the `try!` macro or `?` syntax: returns the value if the computation
/// succeeded or returns the error value.
#[allow(unused_macros)]
macro_rules! wasi_try_bus_ok_ok {
($expr:expr) => {{
let res: Result<_, crate::BusErrno> = $expr;
match res {
Ok(val) => val
Err(err) => {
return Ok(Err(err));
}
}
}};
}
/// Like `wasi_try` but converts a `MemoryAccessError` to a `wasi::Errno`. /// Like `wasi_try` but converts a `MemoryAccessError` to a `wasi::Errno`.
macro_rules! wasi_try_mem { macro_rules! wasi_try_mem {
($expr:expr) => {{ ($expr:expr) => {{
@@ -109,6 +124,14 @@ macro_rules! wasi_try_mem_bus_ok {
}}; }};
} }
/// Like `wasi_try` but converts a `MemoryAccessError` to a __bus_errno_t`.
#[allow(unused_macros)]
macro_rules! wasi_try_mem_bus_ok_ok {
($expr:expr) => {{
wasi_try_bus_ok_ok!($expr.map_err($crate::mem_error_to_bus))
}};
}
/// Like `wasi_try` but converts a `MemoryAccessError` to a `wasi::Errno`. /// Like `wasi_try` but converts a `MemoryAccessError` to a `wasi::Errno`.
macro_rules! wasi_try_mem_ok { macro_rules! wasi_try_mem_ok {
($expr:expr) => {{ ($expr:expr) => {{
@@ -120,6 +143,17 @@ macro_rules! wasi_try_mem_ok {
}}; }};
} }
/// Like `wasi_try` but converts a `MemoryAccessError` to a `wasi::Errno`.
macro_rules! wasi_try_mem_ok_ok {
($expr:expr) => {{
wasi_try_ok_ok!($expr.map_err($crate::mem_error_to_wasi))
}};
($expr:expr, $thread:expr) => {{
wasi_try_ok_ok!($expr.map_err($crate::mem_error_to_wasi), $thread)
}};
}
/// Reads a string from Wasm memory. /// Reads a string from Wasm memory.
macro_rules! get_input_str { macro_rules! get_input_str {
($memory:expr, $data:expr, $len:expr) => {{ ($memory:expr, $data:expr, $len:expr) => {{

View File

@@ -386,6 +386,42 @@ pub fn net_error_into_wasi_err(net_error: NetworkError) -> Errno {
NetworkError::UnexpectedEof => Errno::Proto, NetworkError::UnexpectedEof => Errno::Proto,
NetworkError::WouldBlock => Errno::Again, NetworkError::WouldBlock => Errno::Again,
NetworkError::WriteZero => Errno::Nospc, NetworkError::WriteZero => Errno::Nospc,
NetworkError::OsError(code) => match code {
libc::EPERM => Errno::Perm,
libc::ENOENT => Errno::Noent,
libc::ESRCH => Errno::Srch,
libc::EINTR => Errno::Intr,
libc::EIO => Errno::Io,
libc::ENXIO => Errno::Nxio,
libc::E2BIG => Errno::Toobig,
libc::ENOEXEC => Errno::Noexec,
libc::EBADF => Errno::Badf,
libc::ECHILD => Errno::Badf,
libc::EAGAIN => Errno::Again,
libc::ENOMEM => Errno::Badf,
libc::EACCES => Errno::Access,
libc::EFAULT => Errno::Fault,
libc::EBUSY => Errno::Busy,
libc::EEXIST => Errno::Exist,
libc::EXDEV => Errno::Xdev,
libc::ENODEV => Errno::Nodev,
libc::ENOTDIR => Errno::Notdir,
libc::EISDIR => Errno::Isdir,
libc::EINVAL => Errno::Inval,
libc::ENFILE => Errno::Nfile,
libc::EMFILE => Errno::Mfile,
libc::ENOTTY => Errno::Notty,
libc::ETXTBSY => Errno::Txtbsy,
libc::EFBIG => Errno::Fbig,
libc::ENOSPC => Errno::Nospc,
libc::ESPIPE => Errno::Spipe,
libc::EROFS => Errno::Rofs,
libc::EMLINK => Errno::Mlink,
libc::EPIPE => Errno::Pipe,
libc::EDOM => Errno::Dom,
libc::ERANGE => Errno::Range,
_ => Errno::Io,
},
NetworkError::Unsupported => Errno::Notsup, NetworkError::Unsupported => Errno::Notsup,
NetworkError::UnknownError => Errno::Io, NetworkError::UnknownError => Errno::Io,
} }

View File

@@ -66,7 +66,6 @@ pub enum InodeSocketKind {
socket: Box<dyn VirtualUdpSocket + Sync>, socket: Box<dyn VirtualUdpSocket + Sync>,
peer: Option<SocketAddr>, peer: Option<SocketAddr>,
}, },
Closed,
} }
pub enum WasiSocketOption { pub enum WasiSocketOption {
@@ -154,20 +153,39 @@ pub enum TimeType {
#[derive(Debug)] #[derive(Debug)]
//#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] //#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub(crate) struct InodeSocketInner { pub(crate) struct InodeSocketProtected {
pub kind: InodeSocketKind, pub kind: InodeSocketKind,
pub notifications: InodeSocketNotifications,
}
#[derive(Debug, Default)]
//#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub(crate) struct InodeSocketNotifications {
pub closed: bool,
pub failed: bool,
}
#[derive(Debug)]
//#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub(crate) struct InodeSocketInner {
pub protected: RwLock<InodeSocketProtected>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
//#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] //#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct InodeSocket { pub struct InodeSocket {
pub(crate) inner: Arc<RwLock<InodeSocketInner>>, pub(crate) inner: Arc<InodeSocketInner>,
} }
impl InodeSocket { impl InodeSocket {
pub fn new(kind: InodeSocketKind) -> Self { pub fn new(kind: InodeSocketKind) -> Self {
Self { Self {
inner: Arc::new(RwLock::new(InodeSocketInner { kind })), inner: Arc::new(InodeSocketInner {
protected: RwLock::new(InodeSocketProtected {
kind,
notifications: Default::default(),
}),
}),
} }
} }
@@ -184,7 +202,7 @@ impl InodeSocket {
.unwrap_or(Duration::from_secs(30)); .unwrap_or(Duration::from_secs(30));
let socket = { let socket = {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::PreSocket { InodeSocketKind::PreSocket {
family, family,
@@ -255,7 +273,7 @@ impl InodeSocket {
.unwrap_or(Duration::from_secs(30)); .unwrap_or(Duration::from_secs(30));
let socket = { let socket = {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
match &inner.kind { match &inner.kind {
InodeSocketKind::PreSocket { InodeSocketKind::PreSocket {
ty, ty,
@@ -283,10 +301,6 @@ impl InodeSocket {
return Err(Errno::Notsup); return Err(Errno::Notsup);
} }
}, },
InodeSocketKind::Closed => {
tracing::warn!("wasi[?]::sock_listen - failed - socket closed");
return Err(Errno::Io);
}
_ => { _ => {
tracing::warn!("wasi[?]::sock_listen - failed - not supported(2)"); tracing::warn!("wasi[?]::sock_listen - failed - not supported(2)");
return Err(Errno::Notsup); return Err(Errno::Notsup);
@@ -328,7 +342,7 @@ impl InodeSocket {
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> { ) -> std::task::Poll<Self::Output> {
let mut inner = self.sock.inner.write().unwrap(); let mut inner = self.sock.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::TcpListener { socket, .. } => { InodeSocketKind::TcpListener { socket, .. } => {
if self.nonblocking { if self.nonblocking {
@@ -342,7 +356,6 @@ impl InodeSocket {
} }
} }
InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)), InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)),
InodeSocketKind::Closed => Poll::Ready(Err(Errno::Io)),
_ => Poll::Ready(Err(Errno::Notsup)), _ => Poll::Ready(Err(Errno::Notsup)),
} }
} }
@@ -355,7 +368,7 @@ impl InodeSocket {
} }
pub fn close(&self) -> Result<(), Errno> { pub fn close(&self) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::TcpListener { .. } => {} InodeSocketKind::TcpListener { .. } => {}
InodeSocketKind::TcpStream { socket, .. } => { InodeSocketKind::TcpStream { socket, .. } => {
@@ -366,7 +379,6 @@ impl InodeSocket {
InodeSocketKind::WebSocket(_) => {} InodeSocketKind::WebSocket(_) => {}
InodeSocketKind::Raw(_) => {} InodeSocketKind::Raw(_) => {}
InodeSocketKind::PreSocket { .. } => return Err(Errno::Notconn), InodeSocketKind::PreSocket { .. } => return Err(Errno::Notconn),
InodeSocketKind::Closed => return Err(Errno::Notconn),
}; };
Ok(()) Ok(())
} }
@@ -380,12 +392,12 @@ impl InodeSocket {
#[derive(Debug)] #[derive(Debug)]
struct SocketFlusher<'a> { struct SocketFlusher<'a> {
sock: &'a RwLock<InodeSocketInner>, inner: &'a InodeSocketInner,
} }
impl<'a> Future for SocketFlusher<'a> { impl<'a> Future for SocketFlusher<'a> {
type Output = Result<(), Errno>; type Output = Result<(), Errno>;
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
let mut inner = self.sock.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::TcpListener { .. } => Poll::Ready(Ok(())), InodeSocketKind::TcpListener { .. } => Poll::Ready(Ok(())),
InodeSocketKind::TcpStream { socket, .. } => { InodeSocketKind::TcpStream { socket, .. } => {
@@ -396,13 +408,12 @@ impl InodeSocket {
InodeSocketKind::WebSocket(_) => Poll::Ready(Ok(())), InodeSocketKind::WebSocket(_) => Poll::Ready(Ok(())),
InodeSocketKind::Raw(_) => Poll::Ready(Ok(())), InodeSocketKind::Raw(_) => Poll::Ready(Ok(())),
InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)), InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)),
InodeSocketKind::Closed => Poll::Ready(Err(Errno::Notconn)),
} }
} }
} }
tokio::select! { tokio::select! {
res = SocketFlusher { sock: &self.inner } => res, res = SocketFlusher { inner: &self.inner } => res,
_ = tasks.sleep_now(timeout) => Err(Errno::Timedout) _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
} }
} }
@@ -420,7 +431,7 @@ impl InodeSocket {
let timeout = timeout.unwrap_or(Duration::from_secs(30)); let timeout = timeout.unwrap_or(Duration::from_secs(30));
let connect = { let connect = {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::PreSocket { InodeSocketKind::PreSocket {
ty, ty,
@@ -455,7 +466,6 @@ impl InodeSocket {
target_peer.replace(peer); target_peer.replace(peer);
return Ok(None); return Ok(None);
} }
InodeSocketKind::Closed => return Err(Errno::Io),
_ => return Err(Errno::Notsup), _ => return Err(Errno::Notsup),
} }
}; };
@@ -472,20 +482,19 @@ impl InodeSocket {
} }
pub fn status(&self) -> Result<WasiSocketStatus, Errno> { pub fn status(&self) -> Result<WasiSocketStatus, Errno> {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
Ok(match &inner.kind { Ok(match &inner.kind {
InodeSocketKind::PreSocket { .. } => WasiSocketStatus::Opening, InodeSocketKind::PreSocket { .. } => WasiSocketStatus::Opening,
InodeSocketKind::WebSocket(_) => WasiSocketStatus::Opened, InodeSocketKind::WebSocket(_) => WasiSocketStatus::Opened,
InodeSocketKind::TcpListener { .. } => WasiSocketStatus::Opened, InodeSocketKind::TcpListener { .. } => WasiSocketStatus::Opened,
InodeSocketKind::TcpStream { .. } => WasiSocketStatus::Opened, InodeSocketKind::TcpStream { .. } => WasiSocketStatus::Opened,
InodeSocketKind::UdpSocket { .. } => WasiSocketStatus::Opened, InodeSocketKind::UdpSocket { .. } => WasiSocketStatus::Opened,
InodeSocketKind::Closed => WasiSocketStatus::Closed,
_ => WasiSocketStatus::Failed, _ => WasiSocketStatus::Failed,
}) })
} }
pub fn addr_local(&self) -> Result<SocketAddr, Errno> { pub fn addr_local(&self) -> Result<SocketAddr, Errno> {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
Ok(match &inner.kind { Ok(match &inner.kind {
InodeSocketKind::PreSocket { family, addr, .. } => { InodeSocketKind::PreSocket { family, addr, .. } => {
if let Some(addr) = addr { if let Some(addr) = addr {
@@ -511,13 +520,12 @@ impl InodeSocket {
InodeSocketKind::UdpSocket { socket, .. } => { InodeSocketKind::UdpSocket { socket, .. } => {
socket.addr_local().map_err(net_error_into_wasi_err)? socket.addr_local().map_err(net_error_into_wasi_err)?
} }
InodeSocketKind::Closed => return Err(Errno::Io),
_ => return Err(Errno::Notsup), _ => return Err(Errno::Notsup),
}) })
} }
pub fn addr_peer(&self) -> Result<SocketAddr, Errno> { pub fn addr_peer(&self) -> Result<SocketAddr, Errno> {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
Ok(match &inner.kind { Ok(match &inner.kind {
InodeSocketKind::PreSocket { family, .. } => SocketAddr::new( InodeSocketKind::PreSocket { family, .. } => SocketAddr::new(
match *family { match *family {
@@ -548,13 +556,12 @@ impl InodeSocket {
) )
}) })
})?, })?,
InodeSocketKind::Closed => return Err(Errno::Io),
_ => return Err(Errno::Notsup), _ => return Err(Errno::Notsup),
}) })
} }
pub fn set_opt_flag(&mut self, option: WasiSocketOption, val: bool) -> Result<(), Errno> { pub fn set_opt_flag(&mut self, option: WasiSocketOption, val: bool) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::PreSocket { InodeSocketKind::PreSocket {
only_v6, only_v6,
@@ -593,14 +600,13 @@ impl InodeSocket {
.map_err(net_error_into_wasi_err)?, .map_err(net_error_into_wasi_err)?,
_ => return Err(Errno::Inval), _ => return Err(Errno::Inval),
}, },
InodeSocketKind::Closed => return Err(Errno::Io),
_ => return Err(Errno::Notsup), _ => return Err(Errno::Notsup),
} }
Ok(()) Ok(())
} }
pub fn get_opt_flag(&self, option: WasiSocketOption) -> Result<bool, Errno> { pub fn get_opt_flag(&self, option: WasiSocketOption) -> Result<bool, Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
Ok(match &mut inner.kind { Ok(match &mut inner.kind {
InodeSocketKind::PreSocket { InodeSocketKind::PreSocket {
only_v6, only_v6,
@@ -635,13 +641,12 @@ impl InodeSocket {
.map_err(net_error_into_wasi_err)?, .map_err(net_error_into_wasi_err)?,
_ => return Err(Errno::Inval), _ => return Err(Errno::Inval),
}, },
InodeSocketKind::Closed => return Err(Errno::Io),
_ => return Err(Errno::Notsup), _ => return Err(Errno::Notsup),
}) })
} }
pub fn set_send_buf_size(&mut self, size: usize) -> Result<(), Errno> { pub fn set_send_buf_size(&mut self, size: usize) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::PreSocket { send_buf_size, .. } => { InodeSocketKind::PreSocket { send_buf_size, .. } => {
*send_buf_size = Some(size); *send_buf_size = Some(size);
@@ -651,14 +656,13 @@ impl InodeSocket {
.set_send_buf_size(size) .set_send_buf_size(size)
.map_err(net_error_into_wasi_err)?; .map_err(net_error_into_wasi_err)?;
} }
InodeSocketKind::Closed => return Err(Errno::Io),
_ => return Err(Errno::Notsup), _ => return Err(Errno::Notsup),
} }
Ok(()) Ok(())
} }
pub fn send_buf_size(&self) -> Result<usize, Errno> { pub fn send_buf_size(&self) -> Result<usize, Errno> {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
match &inner.kind { match &inner.kind {
InodeSocketKind::PreSocket { send_buf_size, .. } => { InodeSocketKind::PreSocket { send_buf_size, .. } => {
Ok((*send_buf_size).unwrap_or_default()) Ok((*send_buf_size).unwrap_or_default())
@@ -666,13 +670,12 @@ impl InodeSocket {
InodeSocketKind::TcpStream { socket, .. } => { InodeSocketKind::TcpStream { socket, .. } => {
socket.send_buf_size().map_err(net_error_into_wasi_err) socket.send_buf_size().map_err(net_error_into_wasi_err)
} }
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn set_recv_buf_size(&mut self, size: usize) -> Result<(), Errno> { pub fn set_recv_buf_size(&mut self, size: usize) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::PreSocket { recv_buf_size, .. } => { InodeSocketKind::PreSocket { recv_buf_size, .. } => {
*recv_buf_size = Some(size); *recv_buf_size = Some(size);
@@ -682,14 +685,13 @@ impl InodeSocket {
.set_recv_buf_size(size) .set_recv_buf_size(size)
.map_err(net_error_into_wasi_err)?; .map_err(net_error_into_wasi_err)?;
} }
InodeSocketKind::Closed => return Err(Errno::Io),
_ => return Err(Errno::Notsup), _ => return Err(Errno::Notsup),
} }
Ok(()) Ok(())
} }
pub fn recv_buf_size(&self) -> Result<usize, Errno> { pub fn recv_buf_size(&self) -> Result<usize, Errno> {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
match &inner.kind { match &inner.kind {
InodeSocketKind::PreSocket { recv_buf_size, .. } => { InodeSocketKind::PreSocket { recv_buf_size, .. } => {
Ok((*recv_buf_size).unwrap_or_default()) Ok((*recv_buf_size).unwrap_or_default())
@@ -697,31 +699,28 @@ impl InodeSocket {
InodeSocketKind::TcpStream { socket, .. } => { InodeSocketKind::TcpStream { socket, .. } => {
socket.recv_buf_size().map_err(net_error_into_wasi_err) socket.recv_buf_size().map_err(net_error_into_wasi_err)
} }
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn set_linger(&mut self, linger: Option<std::time::Duration>) -> Result<(), Errno> { pub fn set_linger(&mut self, linger: Option<std::time::Duration>) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::TcpStream { socket, .. } => { InodeSocketKind::TcpStream { socket, .. } => {
socket.set_linger(linger).map_err(net_error_into_wasi_err) socket.set_linger(linger).map_err(net_error_into_wasi_err)
} }
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn linger(&self) -> Result<Option<std::time::Duration>, Errno> { pub fn linger(&self) -> Result<Option<std::time::Duration>, Errno> {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
match &inner.kind { match &inner.kind {
InodeSocketKind::TcpStream { socket, .. } => { InodeSocketKind::TcpStream { socket, .. } => {
socket.linger().map_err(net_error_into_wasi_err) socket.linger().map_err(net_error_into_wasi_err)
} }
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
@@ -731,7 +730,7 @@ impl InodeSocket {
ty: TimeType, ty: TimeType,
timeout: Option<std::time::Duration>, timeout: Option<std::time::Duration>,
) -> Result<(), Errno> { ) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::TcpStream { InodeSocketKind::TcpStream {
write_timeout, write_timeout,
@@ -768,13 +767,12 @@ impl InodeSocket {
} }
Ok(()) Ok(())
} }
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn opt_time(&self, ty: TimeType) -> Result<Option<std::time::Duration>, Errno> { pub fn opt_time(&self, ty: TimeType) -> Result<Option<std::time::Duration>, Errno> {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
match &inner.kind { match &inner.kind {
InodeSocketKind::TcpStream { InodeSocketKind::TcpStream {
read_timeout, read_timeout,
@@ -802,13 +800,12 @@ impl InodeSocket {
TimeType::WriteTimeout => Ok(*write_timeout), TimeType::WriteTimeout => Ok(*write_timeout),
_ => Err(Errno::Inval), _ => Err(Errno::Inval),
}, },
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn set_ttl(&self, ttl: u32) -> Result<(), Errno> { pub fn set_ttl(&self, ttl: u32) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::TcpStream { socket, .. } => { InodeSocketKind::TcpStream { socket, .. } => {
socket.set_ttl(ttl).map_err(net_error_into_wasi_err) socket.set_ttl(ttl).map_err(net_error_into_wasi_err)
@@ -817,13 +814,12 @@ impl InodeSocket {
socket.set_ttl(ttl).map_err(net_error_into_wasi_err) socket.set_ttl(ttl).map_err(net_error_into_wasi_err)
} }
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn ttl(&self) -> Result<u32, Errno> { pub fn ttl(&self) -> Result<u32, Errno> {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
match &inner.kind { match &inner.kind {
InodeSocketKind::TcpStream { socket, .. } => { InodeSocketKind::TcpStream { socket, .. } => {
socket.ttl().map_err(net_error_into_wasi_err) socket.ttl().map_err(net_error_into_wasi_err)
@@ -832,79 +828,72 @@ impl InodeSocket {
socket.ttl().map_err(net_error_into_wasi_err) socket.ttl().map_err(net_error_into_wasi_err)
} }
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> Result<(), Errno> { pub fn set_multicast_ttl_v4(&self, ttl: u32) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::UdpSocket { socket, .. } => socket InodeSocketKind::UdpSocket { socket, .. } => socket
.set_multicast_ttl_v4(ttl) .set_multicast_ttl_v4(ttl)
.map_err(net_error_into_wasi_err), .map_err(net_error_into_wasi_err),
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn multicast_ttl_v4(&self) -> Result<u32, Errno> { pub fn multicast_ttl_v4(&self) -> Result<u32, Errno> {
let inner = self.inner.read().unwrap(); let inner = self.inner.protected.read().unwrap();
match &inner.kind { match &inner.kind {
InodeSocketKind::UdpSocket { socket, .. } => { InodeSocketKind::UdpSocket { socket, .. } => {
socket.multicast_ttl_v4().map_err(net_error_into_wasi_err) socket.multicast_ttl_v4().map_err(net_error_into_wasi_err)
} }
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn join_multicast_v4(&self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), Errno> { pub fn join_multicast_v4(&self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::UdpSocket { socket, .. } => socket InodeSocketKind::UdpSocket { socket, .. } => socket
.join_multicast_v4(multiaddr, iface) .join_multicast_v4(multiaddr, iface)
.map_err(net_error_into_wasi_err), .map_err(net_error_into_wasi_err),
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn leave_multicast_v4(&self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), Errno> { pub fn leave_multicast_v4(&self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::UdpSocket { socket, .. } => socket InodeSocketKind::UdpSocket { socket, .. } => socket
.leave_multicast_v4(multiaddr, iface) .leave_multicast_v4(multiaddr, iface)
.map_err(net_error_into_wasi_err), .map_err(net_error_into_wasi_err),
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn join_multicast_v6(&self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), Errno> { pub fn join_multicast_v6(&self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::UdpSocket { socket, .. } => socket InodeSocketKind::UdpSocket { socket, .. } => socket
.join_multicast_v6(multiaddr, iface) .join_multicast_v6(multiaddr, iface)
.map_err(net_error_into_wasi_err), .map_err(net_error_into_wasi_err),
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
pub fn leave_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), Errno> { pub fn leave_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::UdpSocket { socket, .. } => socket InodeSocketKind::UdpSocket { socket, .. } => socket
.leave_multicast_v6(multiaddr, iface) .leave_multicast_v6(multiaddr, iface)
.map_err(net_error_into_wasi_err), .map_err(net_error_into_wasi_err),
InodeSocketKind::PreSocket { .. } => Err(Errno::Io), InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
InodeSocketKind::Closed => Err(Errno::Io),
_ => Err(Errno::Notsup), _ => Err(Errno::Notsup),
} }
} }
@@ -924,14 +913,14 @@ impl InodeSocket {
#[derive(Debug)] #[derive(Debug)]
struct SocketSender<'a, 'b> { struct SocketSender<'a, 'b> {
sock: &'a RwLock<InodeSocketInner>, inner: &'a InodeSocketInner,
data: &'b [u8], data: &'b [u8],
nonblocking: bool, nonblocking: bool,
} }
impl<'a, 'b> Future for SocketSender<'a, 'b> { impl<'a, 'b> Future for SocketSender<'a, 'b> {
type Output = Result<usize, Errno>; type Output = Result<usize, Errno>;
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
let mut inner = self.sock.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::WebSocket(sock) => sock InodeSocketKind::WebSocket(sock) => sock
.poll_send(cx, self.data) .poll_send(cx, self.data)
@@ -976,14 +965,13 @@ impl InodeSocket {
} }
} }
InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)), InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)),
InodeSocketKind::Closed => Poll::Ready(Err(Errno::Io)),
_ => Poll::Ready(Err(Errno::Notsup)), _ => Poll::Ready(Err(Errno::Notsup)),
} }
} }
} }
tokio::select! { tokio::select! {
res = SocketSender { sock: &self.inner, data: buf, nonblocking } => res, res = SocketSender { inner: &self.inner, data: buf, nonblocking } => res,
_ = tasks.sleep_now(timeout) => Err(Errno::Timedout) _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
} }
} }
@@ -1004,7 +992,7 @@ impl InodeSocket {
#[derive(Debug)] #[derive(Debug)]
struct SocketSender<'a, 'b> { struct SocketSender<'a, 'b> {
sock: &'a RwLock<InodeSocketInner>, inner: &'a InodeSocketInner,
data: &'b [u8], data: &'b [u8],
addr: SocketAddr, addr: SocketAddr,
nonblocking: bool, nonblocking: bool,
@@ -1012,7 +1000,7 @@ impl InodeSocket {
impl<'a, 'b> Future for SocketSender<'a, 'b> { impl<'a, 'b> Future for SocketSender<'a, 'b> {
type Output = Result<usize, Errno>; type Output = Result<usize, Errno>;
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
let mut inner = self.sock.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::Icmp(sock) => { InodeSocketKind::Icmp(sock) => {
if self.nonblocking { if self.nonblocking {
@@ -1038,14 +1026,13 @@ impl InodeSocket {
} }
} }
InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)), InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)),
InodeSocketKind::Closed => Poll::Ready(Err(Errno::Io)),
_ => Poll::Ready(Err(Errno::Notsup)), _ => Poll::Ready(Err(Errno::Notsup)),
} }
} }
} }
tokio::select! { tokio::select! {
res = SocketSender { sock: &self.inner, data: buf, addr, nonblocking } => res, res = SocketSender { inner: &self.inner, data: buf, addr, nonblocking } => res,
_ = tasks.sleep_now(timeout) => Err(Errno::Timedout) _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
} }
} }
@@ -1065,7 +1052,7 @@ impl InodeSocket {
#[derive(Debug)] #[derive(Debug)]
struct SocketReceiver<'a, 'b> { struct SocketReceiver<'a, 'b> {
sock: &'a RwLock<InodeSocketInner>, inner: &'a InodeSocketInner,
data: &'b mut [MaybeUninit<u8>], data: &'b mut [MaybeUninit<u8>],
nonblocking: bool, nonblocking: bool,
} }
@@ -1075,7 +1062,7 @@ impl InodeSocket {
mut self: Pin<&mut Self>, mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
) -> Poll<Self::Output> { ) -> Poll<Self::Output> {
let mut inner = self.sock.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::WebSocket(sock) => sock InodeSocketKind::WebSocket(sock) => sock
.poll_recv(cx, self.data) .poll_recv(cx, self.data)
@@ -1132,14 +1119,13 @@ impl InodeSocket {
} }
} }
InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)), InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)),
InodeSocketKind::Closed => Poll::Ready(Err(Errno::Io)),
_ => Poll::Ready(Err(Errno::Notsup)), _ => Poll::Ready(Err(Errno::Notsup)),
} }
} }
} }
tokio::select! { tokio::select! {
res = SocketReceiver { sock: &self.inner, data: buf, nonblocking } => res, res = SocketReceiver { inner: &self.inner, data: buf, nonblocking } => res,
_ = tasks.sleep_now(timeout) => Err(Errno::Timedout) _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
} }
} }
@@ -1159,7 +1145,7 @@ impl InodeSocket {
#[derive(Debug)] #[derive(Debug)]
struct SocketReceiver<'a, 'b> { struct SocketReceiver<'a, 'b> {
sock: &'a RwLock<InodeSocketInner>, inner: &'a InodeSocketInner,
data: &'b mut [MaybeUninit<u8>], data: &'b mut [MaybeUninit<u8>],
nonblocking: bool, nonblocking: bool,
} }
@@ -1169,7 +1155,7 @@ impl InodeSocket {
mut self: Pin<&mut Self>, mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
) -> Poll<Self::Output> { ) -> Poll<Self::Output> {
let mut inner = self.sock.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::Icmp(sock) => { InodeSocketKind::Icmp(sock) => {
if self.nonblocking { if self.nonblocking {
@@ -1195,33 +1181,31 @@ impl InodeSocket {
} }
} }
InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)), InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)),
InodeSocketKind::Closed => Poll::Ready(Err(Errno::Io)),
_ => Poll::Ready(Err(Errno::Notsup)), _ => Poll::Ready(Err(Errno::Notsup)),
} }
} }
} }
tokio::select! { tokio::select! {
res = SocketReceiver { sock: &self.inner, data: buf, nonblocking } => res, res = SocketReceiver { inner: &self.inner, data: buf, nonblocking } => res,
_ = tasks.sleep_now(timeout) => Err(Errno::Timedout) _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
} }
} }
pub fn shutdown(&mut self, how: std::net::Shutdown) -> Result<(), Errno> { pub fn shutdown(&mut self, how: std::net::Shutdown) -> Result<(), Errno> {
let mut inner = self.inner.write().unwrap(); let mut inner = self.inner.protected.write().unwrap();
match &mut inner.kind { match &mut inner.kind {
InodeSocketKind::TcpStream { socket, .. } => { InodeSocketKind::TcpStream { socket, .. } => {
socket.shutdown(how).map_err(net_error_into_wasi_err)?; socket.shutdown(how).map_err(net_error_into_wasi_err)?;
} }
InodeSocketKind::PreSocket { .. } => return Err(Errno::Notconn), InodeSocketKind::PreSocket { .. } => return Err(Errno::Notconn),
InodeSocketKind::Closed => return Err(Errno::Io),
_ => return Err(Errno::Notsup), _ => return Err(Errno::Notsup),
} }
Ok(()) Ok(())
} }
pub async fn can_write(&self) -> bool { pub async fn can_write(&self) -> bool {
if let Ok(mut guard) = self.inner.try_write() { if let Ok(mut guard) = self.inner.protected.try_write() {
#[allow(clippy::match_like_matches_macro)] #[allow(clippy::match_like_matches_macro)]
match &mut guard.kind { match &mut guard.kind {
InodeSocketKind::TcpStream { .. } InodeSocketKind::TcpStream { .. }
@@ -1236,7 +1220,7 @@ impl InodeSocket {
} }
} }
impl InodeSocketInner { impl InodeSocketProtected {
pub fn poll_read_ready( pub fn poll_read_ready(
&mut self, &mut self,
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
@@ -1251,9 +1235,6 @@ impl InodeSocketInner {
InodeSocketKind::PreSocket { .. } => { InodeSocketKind::PreSocket { .. } => {
std::task::Poll::Ready(Err(wasmer_vnet::NetworkError::IOError)) std::task::Poll::Ready(Err(wasmer_vnet::NetworkError::IOError))
} }
InodeSocketKind::Closed => {
std::task::Poll::Ready(Err(wasmer_vnet::NetworkError::ConnectionAborted))
}
} }
} }
@@ -1271,9 +1252,6 @@ impl InodeSocketInner {
InodeSocketKind::PreSocket { .. } => { InodeSocketKind::PreSocket { .. } => {
std::task::Poll::Ready(Err(wasmer_vnet::NetworkError::IOError)) std::task::Poll::Ready(Err(wasmer_vnet::NetworkError::IOError))
} }
InodeSocketKind::Closed => {
std::task::Poll::Ready(Err(wasmer_vnet::NetworkError::ConnectionAborted))
}
} }
} }
} }

View File

@@ -65,7 +65,7 @@ impl CmdWasmer {
let mut config = config.take().ok_or(VirtualBusError::UnknownError)?.conf(); let mut config = config.take().ok_or(VirtualBusError::UnknownError)?.conf();
// Set the arguments of the environment by replacing the state // Set the arguments of the environment by replacing the state
let mut state = config.env().state.fork(true); let mut state = config.env().state.fork();
args.insert(0, what.clone()); args.insert(0, what.clone());
state.args = args; state.args = args;
config.env_mut().state = Arc::new(state); config.env_mut().state = Arc::new(state);

View File

@@ -2,12 +2,10 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
ops::{Deref, DerefMut},
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::{Arc, RwLock}, sync::Arc,
}; };
use generational_arena::Arena;
use rand::Rng; use rand::Rng;
use thiserror::Error; use thiserror::Error;
use wasmer::AsStoreMut; use wasmer::AsStoreMut;
@@ -49,7 +47,7 @@ pub struct WasiStateBuilder {
vfs_preopens: Vec<String>, vfs_preopens: Vec<String>,
compiled_modules: Arc<ModuleCache>, compiled_modules: Arc<ModuleCache>,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
setup_fs_fn: Option<Box<dyn Fn(&mut WasiInodes, &mut WasiFs) -> Result<(), String> + Send>>, setup_fs_fn: Option<Box<dyn Fn(&WasiInodes, &mut WasiFs) -> Result<(), String> + Send>>,
stdout_override: Option<Box<dyn VirtualFile + Send + Sync + 'static>>, stdout_override: Option<Box<dyn VirtualFile + Send + Sync + 'static>>,
stderr_override: Option<Box<dyn VirtualFile + Send + Sync + 'static>>, stderr_override: Option<Box<dyn VirtualFile + Send + Sync + 'static>>,
stdin_override: Option<Box<dyn VirtualFile + Send + Sync + 'static>>, stdin_override: Option<Box<dyn VirtualFile + Send + Sync + 'static>>,
@@ -109,7 +107,7 @@ fn validate_mapped_dir_alias(alias: &str) -> Result<(), WasiStateCreationError>
Ok(()) Ok(())
} }
pub type SetupFsFn = Box<dyn Fn(&mut WasiInodes, &mut WasiFs) -> Result<(), String> + Send>; pub type SetupFsFn = Box<dyn Fn(&WasiInodes, &mut WasiFs) -> Result<(), String> + Send>;
// TODO add other WasiFS APIs here like swapping out stdout, for example (though we need to // TODO add other WasiFS APIs here like swapping out stdout, for example (though we need to
// return stdout somehow, it's unclear what that API should look like) // return stdout somehow, it's unclear what that API should look like)
@@ -510,46 +508,35 @@ impl WasiStateBuilder {
.unwrap_or_else(|| WasiFsRoot::Sandbox(Arc::new(TmpFileSystem::new()))); .unwrap_or_else(|| WasiFsRoot::Sandbox(Arc::new(TmpFileSystem::new())));
// self.preopens are checked in [`PreopenDirBuilder::build`] // self.preopens are checked in [`PreopenDirBuilder::build`]
let inodes = RwLock::new(crate::state::WasiInodes { let inodes = crate::state::WasiInodes::new();
arena: Arena::new(),
orphan_fds: HashMap::new(),
});
let wasi_fs = { let wasi_fs = {
let mut inodes = inodes.write().unwrap();
// self.preopens are checked in [`PreopenDirBuilder::build`] // self.preopens are checked in [`PreopenDirBuilder::build`]
let mut wasi_fs = WasiFs::new_with_preopen( let mut wasi_fs =
inodes.deref_mut(), WasiFs::new_with_preopen(&inodes, &self.preopens, &self.vfs_preopens, fs_backing)
&self.preopens, .map_err(WasiStateCreationError::WasiFsCreationError)?;
&self.vfs_preopens,
fs_backing,
)
.map_err(WasiStateCreationError::WasiFsCreationError)?;
// set up the file system, overriding base files and calling the setup function // set up the file system, overriding base files and calling the setup function
wasi_fs wasi_fs
.swap_file(inodes.deref(), __WASI_STDIN_FILENO, stdin) .swap_file(__WASI_STDIN_FILENO, stdin)
.map_err(WasiStateCreationError::FileSystemError)?; .map_err(WasiStateCreationError::FileSystemError)?;
if let Some(stdout_override) = self.stdout_override.take() { if let Some(stdout_override) = self.stdout_override.take() {
wasi_fs wasi_fs
.swap_file(inodes.deref(), __WASI_STDOUT_FILENO, stdout_override) .swap_file(__WASI_STDOUT_FILENO, stdout_override)
.map_err(WasiStateCreationError::FileSystemError)?; .map_err(WasiStateCreationError::FileSystemError)?;
} }
if let Some(stderr_override) = self.stderr_override.take() { if let Some(stderr_override) = self.stderr_override.take() {
wasi_fs wasi_fs
.swap_file(inodes.deref(), __WASI_STDERR_FILENO, stderr_override) .swap_file(__WASI_STDERR_FILENO, stderr_override)
.map_err(WasiStateCreationError::FileSystemError)?; .map_err(WasiStateCreationError::FileSystemError)?;
} }
if let Some(f) = &self.setup_fs_fn { if let Some(f) = &self.setup_fs_fn {
f(inodes.deref_mut(), &mut wasi_fs) f(&inodes, &mut wasi_fs).map_err(WasiStateCreationError::WasiFsSetupError)?;
.map_err(WasiStateCreationError::WasiFsSetupError)?;
} }
wasi_fs wasi_fs
}; };
let inodes = Arc::new(inodes);
Ok(WasiState { Ok(WasiState {
fs: wasi_fs, fs: wasi_fs,

View File

@@ -1,7 +1,4 @@
use std::{ use std::{ops::Deref, sync::Arc};
ops::Deref,
sync::{Arc, RwLockReadGuard, RwLockWriteGuard},
};
use derivative::Derivative; use derivative::Derivative;
use tracing::{trace, warn}; use tracing::{trace, warn};
@@ -200,6 +197,8 @@ pub struct WasiEnv {
pub stack_base: u64, pub stack_base: u64,
/// Start of the stack memory that is allocated for this thread /// Start of the stack memory that is allocated for this thread
pub stack_start: u64, pub stack_start: u64,
/// Seed used to rotate around the events returned by `poll_oneoff`
pub poll_seed: u64,
/// Shared state of the WASI system. Manages all the data that the /// Shared state of the WASI system. Manages all the data that the
/// executing WASI program can see. /// executing WASI program can see.
pub state: Arc<WasiState>, pub state: Arc<WasiState>,
@@ -234,7 +233,7 @@ impl WasiEnv {
let thread = handle.as_thread(); let thread = handle.as_thread();
thread.copy_stack_from(&self.thread); thread.copy_stack_from(&self.thread);
let state = Arc::new(self.state.fork(true)); let state = Arc::new(self.state.fork());
let bin_factory = { let bin_factory = {
let mut bin_factory = self.bin_factory.clone(); let mut bin_factory = self.bin_factory.clone();
@@ -246,6 +245,7 @@ impl WasiEnv {
process, process,
thread, thread,
vfork: None, vfork: None,
poll_seed: 0,
stack_base: self.stack_base, stack_base: self.stack_base,
stack_start: self.stack_start, stack_start: self.stack_start,
bin_factory, bin_factory,
@@ -293,6 +293,7 @@ impl WasiEnv {
process, process,
thread: thread.as_thread(), thread: thread.as_thread(),
vfork: None, vfork: None,
poll_seed: 0,
stack_base: DEFAULT_STACK_SIZE, stack_base: DEFAULT_STACK_SIZE,
stack_start: 0, stack_start: 0,
state, state,
@@ -529,21 +530,10 @@ impl WasiEnv {
&'a self, &'a self,
store: &'a impl AsStoreRef, store: &'a impl AsStoreRef,
_mem_index: u32, _mem_index: u32,
) -> (MemoryView<'a>, &WasiState, RwLockReadGuard<WasiInodes>) { ) -> (MemoryView<'a>, &WasiState, &WasiInodes) {
let memory = self.memory_view(store); let memory = self.memory_view(store);
let state = self.state.deref(); let state = self.state.deref();
let inodes = state.inodes.read().unwrap(); let inodes = &state.inodes;
(memory, state, inodes)
}
pub(crate) fn get_memory_and_wasi_state_and_inodes_mut<'a>(
&'a self,
store: &'a impl AsStoreRef,
_mem_index: u32,
) -> (MemoryView<'a>, &WasiState, RwLockWriteGuard<WasiInodes>) {
let memory = self.memory_view(store);
let state = self.state.deref();
let inodes = state.inodes.write().unwrap();
(memory, state, inodes) (memory, state, inodes)
} }
@@ -693,9 +683,7 @@ impl WasiEnv {
// If this is the main thread then also close all the files // If this is the main thread then also close all the files
if self.thread.is_main() { if self.thread.is_main() {
trace!("wasi[{}]:: cleaning up open file handles", self.pid()); trace!("wasi[{}]:: cleaning up open file handles", self.pid());
self.state.fs.close_all();
let inodes = self.state.inodes.read().unwrap();
self.state.fs.close_all(inodes.deref());
// Now send a signal that the thread is terminated // Now send a signal that the thread is terminated
self.process.signal_process(Signal::Sigquit); self.process.signal_process(Signal::Sigquit);

View File

@@ -31,7 +31,6 @@ use std::{
}; };
use derivative::Derivative; use derivative::Derivative;
pub use generational_arena::Index as Inode;
#[cfg(feature = "enable-serde")] #[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use wasmer::Store; use wasmer::Store;
@@ -46,6 +45,7 @@ pub use self::{
func_env::WasiFunctionEnv, func_env::WasiFunctionEnv,
types::*, types::*,
}; };
pub use crate::fs::{InodeGuard, InodeWeakGuard};
use crate::{ use crate::{
fs::{fs_error_into_wasi_err, WasiFs, WasiFsRoot, WasiInodes, WasiStateFileGuard}, fs::{fs_error_into_wasi_err, WasiFs, WasiFsRoot, WasiInodes, WasiStateFileGuard},
os::task::process::WasiProcessId, os::task::process::WasiProcessId,
@@ -243,7 +243,7 @@ impl WasiBusState {
pub struct WasiState { pub struct WasiState {
pub fs: WasiFs, pub fs: WasiFs,
pub secret: [u8; 32], pub secret: [u8; 32],
pub inodes: Arc<RwLock<WasiInodes>>, pub inodes: WasiInodes,
// TODO: review allow... // TODO: review allow...
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) threading: RwLock<WasiStateThreading>, pub(crate) threading: RwLock<WasiStateThreading>,
@@ -343,9 +343,9 @@ impl WasiState {
} }
/// Forking the WasiState is used when either fork or vfork is called /// Forking the WasiState is used when either fork or vfork is called
pub fn fork(&self, inc_refs: bool) -> Self { pub fn fork(&self) -> Self {
WasiState { WasiState {
fs: self.fs.fork(inc_refs), fs: self.fs.fork(),
secret: self.secret, secret: self.secret,
inodes: self.inodes.clone(), inodes: self.inodes.clone(),
threading: Default::default(), threading: Default::default(),

View File

@@ -105,8 +105,9 @@ pub(crate) use crate::{
}, },
runtime::{task_manager::VirtualTaskManagerExt, SpawnType}, runtime::{task_manager::VirtualTaskManagerExt, SpawnType},
state::{ state::{
self, bus_errno_into_vbus_error, iterate_poll_events, vbus_error_into_bus_errno, Inode, self, bus_errno_into_vbus_error, iterate_poll_events, vbus_error_into_bus_errno,
PollEvent, PollEventBuilder, WasiBusCall, WasiFutex, WasiState, WasiThreadContext, InodeGuard, InodeWeakGuard, PollEvent, PollEventBuilder, WasiBusCall, WasiFutex, WasiState,
WasiThreadContext,
}, },
utils::{self, map_io_err}, utils::{self, map_io_err},
VirtualTaskManager, WasiEnv, WasiEnvInner, WasiError, WasiFunctionEnv, VirtualTaskManager, WasiEnv, WasiEnvInner, WasiError, WasiFunctionEnv,
@@ -118,6 +119,7 @@ use crate::{
MAX_SYMLINKS, MAX_SYMLINKS,
}, },
utils::store::InstanceSnapshot, utils::store::InstanceSnapshot,
WasiInodes,
}; };
pub(crate) use crate::{net::net_error_into_wasi_err, utils::WasiParkingLot}; pub(crate) use crate::{net::net_error_into_wasi_err, utils::WasiParkingLot};
@@ -248,11 +250,9 @@ pub(crate) fn read_bytes<T: Read, M: MemorySize>(
pub async fn stderr_write(ctx: &FunctionEnvMut<'_, WasiEnv>, buf: &[u8]) -> Result<(), Errno> { pub async fn stderr_write(ctx: &FunctionEnvMut<'_, WasiEnv>, buf: &[u8]) -> Result<(), Errno> {
let env = ctx.data(); let env = ctx.data();
let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes_mut(ctx, 0); let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(ctx, 0);
let mut stderr = inodes let mut stderr = WasiInodes::stderr_mut(&state.fs.fd_map).map_err(fs_error_into_wasi_err)?;
.stderr_mut(&state.fs.fd_map)
.map_err(fs_error_into_wasi_err)?;
stderr.write_all(buf).await.map_err(map_io_err) stderr.write_all(buf).await.map_err(map_io_err)
} }
@@ -465,19 +465,13 @@ where
F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Fut, F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Fut,
Fut: std::future::Future<Output = Result<T, Errno>>, Fut: std::future::Future<Output = Result<T, Errno>>,
{ {
let state = env.state.clone(); let fd_entry = env.state.fs.get_fd(sock)?;
let inodes = state.inodes.clone();
let fd_entry = state.fs.get_fd(sock)?;
if !rights.is_empty() && !fd_entry.rights.contains(rights) { if !rights.is_empty() && !fd_entry.rights.contains(rights) {
return Err(Errno::Access); return Err(Errno::Access);
} }
let work = { let work = {
let inodes_guard = inodes.read().unwrap(); let inode = fd_entry.inode.clone();
let inode_idx = fd_entry.inode;
let inode = &inodes_guard.arena[inode_idx];
let tasks = env.tasks.clone(); let tasks = env.tasks.clone();
let mut guard = inode.read(); let mut guard = inode.read();
match guard.deref() { match guard.deref() {
@@ -514,24 +508,18 @@ where
let env = ctx.data(); let env = ctx.data();
let tasks = env.tasks.clone(); let tasks = env.tasks.clone();
let state = env.state.clone(); let fd_entry = env.state.fs.get_fd(sock)?;
let inodes = state.inodes.clone();
let fd_entry = state.fs.get_fd(sock)?;
if !rights.is_empty() && !fd_entry.rights.contains(rights) { if !rights.is_empty() && !fd_entry.rights.contains(rights) {
return Err(Errno::Access); return Err(Errno::Access);
} }
let inode_idx = fd_entry.inode; let inode = fd_entry.inode.clone();
let inodes_guard = inodes.read().unwrap();
let inode = &inodes_guard.arena[inode_idx];
let mut guard = inode.write(); let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::Socket { socket } => { Kind::Socket { socket } => {
// Clone the socket and release the lock // Clone the socket and release the lock
let socket = socket.clone(); let socket = socket.clone();
drop(guard); drop(guard);
drop(inodes_guard);
// Start the work using the socket // Start the work using the socket
let work = actor(socket, fd_entry); let work = actor(socket, fd_entry);
@@ -558,17 +546,12 @@ where
let env = ctx.data(); let env = ctx.data();
let tasks = env.tasks.clone(); let tasks = env.tasks.clone();
let state = env.state.clone(); let fd_entry = env.state.fs.get_fd(sock)?;
let inodes = state.inodes.clone();
let fd_entry = state.fs.get_fd(sock)?;
if !rights.is_empty() && !fd_entry.rights.contains(rights) { if !rights.is_empty() && !fd_entry.rights.contains(rights) {
return Err(Errno::Access); return Err(Errno::Access);
} }
let inodes_guard = inodes.read().unwrap(); let inode = fd_entry.inode.clone();
let inode_idx = fd_entry.inode;
let inode = &inodes_guard.arena[inode_idx];
let tasks = env.tasks.clone(); let tasks = env.tasks.clone();
let mut guard = inode.read(); let mut guard = inode.read();
@@ -602,24 +585,18 @@ where
let env = ctx.data(); let env = ctx.data();
let tasks = env.tasks.clone(); let tasks = env.tasks.clone();
let state = env.state.clone(); let fd_entry = env.state.fs.get_fd(sock)?;
let inodes = state.inodes.clone();
let fd_entry = state.fs.get_fd(sock)?;
if !rights.is_empty() && !fd_entry.rights.contains(rights) { if !rights.is_empty() && !fd_entry.rights.contains(rights) {
return Err(Errno::Access); return Err(Errno::Access);
} }
let inode_idx = fd_entry.inode; let inode = fd_entry.inode.clone();
let inodes_guard = inodes.read().unwrap();
let inode = &inodes_guard.arena[inode_idx];
let mut guard = inode.write(); let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::Socket { socket } => { Kind::Socket { socket } => {
// Clone the socket and release the lock // Clone the socket and release the lock
let socket = socket.clone(); let socket = socket.clone();
drop(guard); drop(guard);
drop(inodes_guard);
// Start the work using the socket // Start the work using the socket
actor(socket, fd_entry) actor(socket, fd_entry)
@@ -642,10 +619,7 @@ where
Fut: std::future::Future<Output = Result<Option<crate::net::socket::InodeSocket>, Errno>> + 'a, Fut: std::future::Future<Output = Result<Option<crate::net::socket::InodeSocket>, Errno>> + 'a,
{ {
let env = ctx.data(); let env = ctx.data();
let state = env.state.clone(); let fd_entry = env.state.fs.get_fd(sock)?;
let inodes = state.inodes.clone();
let fd_entry = state.fs.get_fd(sock)?;
if !rights.is_empty() && !fd_entry.rights.contains(rights) { if !rights.is_empty() && !fd_entry.rights.contains(rights) {
tracing::warn!( tracing::warn!(
"wasi[{}:{}]::sock_upgrade(fd={}, rights={:?}) - failed - no access rights to upgrade", "wasi[{}:{}]::sock_upgrade(fd={}, rights={:?}) - failed - no access rights to upgrade",
@@ -659,15 +633,12 @@ where
let tasks = env.tasks.clone(); let tasks = env.tasks.clone();
{ {
let inode_idx = fd_entry.inode; let inode = fd_entry.inode.clone();
let inodes_guard = inodes.read().unwrap();
let inode = &inodes_guard.arena[inode_idx];
let mut guard = inode.write(); let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::Socket { socket } => { Kind::Socket { socket } => {
let socket = socket.clone(); let socket = socket.clone();
drop(guard); drop(guard);
drop(inodes_guard);
// Start the work using the socket // Start the work using the socket
let work = actor(socket); let work = actor(socket);
@@ -681,8 +652,6 @@ where
let new_socket = rx.recv().unwrap()?; let new_socket = rx.recv().unwrap()?;
if let Some(mut new_socket) = new_socket { if let Some(mut new_socket) = new_socket {
let inodes_guard = inodes.read().unwrap();
let inode = &inodes_guard.arena[inode_idx];
let mut guard = inode.write(); let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::Socket { socket } => { Kind::Socket { socket } => {
@@ -1096,7 +1065,7 @@ pub(crate) fn handle_rewind<M: MemorySize>(ctx: &mut FunctionEnvMut<'_, WasiEnv>
pub(crate) fn _prepare_wasi(wasi_env: &mut WasiEnv, args: Option<Vec<String>>) { pub(crate) fn _prepare_wasi(wasi_env: &mut WasiEnv, args: Option<Vec<String>>) {
// Swap out the arguments with the new ones // Swap out the arguments with the new ones
if let Some(args) = args { if let Some(args) = args {
let mut wasi_state = wasi_env.state.fork(false); let mut wasi_state = wasi_env.state.fork();
wasi_state.args = args; wasi_state.args = args;
wasi_env.state = Arc::new(wasi_state); wasi_env.state = Arc::new(wasi_state);
} }
@@ -1120,8 +1089,7 @@ pub(crate) fn _prepare_wasi(wasi_env: &mut WasiEnv, args: Option<Vec<String>>) {
// Now close all these files // Now close all these files
for fd in close_fds { for fd in close_fds {
let inodes = wasi_env.state.inodes.read().unwrap(); let _ = wasi_env.state.fs.close_fd(fd);
let _ = wasi_env.state.fs.close_fd(inodes.deref(), fd);
} }
} }

View File

@@ -22,7 +22,7 @@ pub fn fd_allocate(
ctx.data().tid() ctx.data().tid()
); );
let env = ctx.data(); let env = ctx.data();
let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
let fd_entry = wasi_try!(state.fs.get_fd(fd)); let fd_entry = wasi_try!(state.fs.get_fd(fd));
let inode = fd_entry.inode; let inode = fd_entry.inode;
@@ -31,7 +31,7 @@ pub fn fd_allocate(
} }
let new_size = wasi_try!(offset.checked_add(len).ok_or(Errno::Inval)); let new_size = wasi_try!(offset.checked_add(len).ok_or(Errno::Inval));
{ {
let mut guard = inodes.arena[inode].write(); let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::File { handle, .. } => { Kind::File { handle, .. } => {
if let Some(handle) = handle { if let Some(handle) = handle {
@@ -51,7 +51,7 @@ pub fn fd_allocate(
Kind::Dir { .. } | Kind::Root { .. } => return Errno::Isdir, Kind::Dir { .. } | Kind::Root { .. } => return Errno::Isdir,
} }
} }
inodes.arena[inode].stat.write().unwrap().st_size = new_size; inode.stat.write().unwrap().st_size = new_size;
debug!("New file size: {}", new_size); debug!("New file size: {}", new_size);
Errno::Success Errno::Success

View File

@@ -19,37 +19,10 @@ pub fn fd_close(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result<Errn
ctx.data().tid(), ctx.data().tid(),
fd fd
); );
let ret = {
let env = ctx.data();
let (mut memory, _, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let fd_entry = wasi_try_ok!(env.state.fs.get_fd(fd));
let is_non_blocking = fd_entry.flags.contains(Fdflags::NONBLOCK);
let inode_idx = fd_entry.inode;
if let Some(inode) = inodes.arena.get(inode_idx) {
let mut guard = inode.write();
match guard.deref_mut() {
Kind::Socket { socket } => {
let socket = socket.clone();
drop(guard);
drop(inodes);
__asyncify(&mut ctx, None, async move {
socket.close().map(|()| Errno::Success)
})?
.unwrap_or_else(|a| a)
}
_ => Errno::Success,
}
} else {
return Ok(Errno::Success);
}
};
let env = ctx.data(); let env = ctx.data();
let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
wasi_try_ok!(state.fs.close_fd(inodes.deref(), fd)); wasi_try_ok!(state.fs.close_fd(fd));
Ok(ret) Ok(Errno::Success)
} }

View File

@@ -14,18 +14,12 @@ pub fn fd_datasync(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result<E
); );
let env = ctx.data(); let env = ctx.data();
let state = env.state.clone(); let state = env.state.clone();
let inodes = state.inodes.clone();
let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
if !fd_entry.rights.contains(Rights::FD_DATASYNC) { if !fd_entry.rights.contains(Rights::FD_DATASYNC) {
return Ok(Errno::Access); return Ok(Errno::Access);
} }
Ok(wasi_try_ok!(__asyncify(&mut ctx, None, async move { Ok(wasi_try_ok!(__asyncify(&mut ctx, None, async move {
let inodes = inodes.read().unwrap(); state.fs.flush(fd).await.map(|_| Errno::Success)
state
.fs
.flush(inodes.deref(), fd)
.await
.map(|_| Errno::Success)
})?)) })?))
} }

View File

@@ -1,5 +1,5 @@
use super::*; use super::*;
use crate::syscalls::*; use crate::{fs::NotificationInner, syscalls::*};
/// ### `fd_event()` /// ### `fd_event()`
/// Creates a file handle for event notifications /// Creates a file handle for event notifications
@@ -12,17 +12,17 @@ pub fn fd_event<M: MemorySize>(
debug!("wasi[{}:{}]::fd_event", ctx.data().pid(), ctx.data().tid()); debug!("wasi[{}:{}]::fd_event", ctx.data().pid(), ctx.data().tid());
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(&ctx, 0);
let kind = Kind::EventNotifications { let kind = Kind::EventNotifications(Arc::new(NotificationInner {
counter: Arc::new(AtomicU64::new(initial_val)), counter: AtomicU64::new(initial_val),
last_poll: AtomicU64::new(0),
is_semaphore: flags & EVENT_FD_FLAGS_SEMAPHORE != 0, is_semaphore: flags & EVENT_FD_FLAGS_SEMAPHORE != 0,
wakers: Default::default(), wakers: Default::default(),
immediate: Arc::new(AtomicBool::new(false)), }));
};
let inode = state.fs.create_inode_with_default_stat( let inode = state.fs.create_inode_with_default_stat(
inodes.deref_mut(), inodes.deref(),
kind, kind,
false, false,
"event".to_string().into(), "event".to_string().into(),

View File

@@ -23,7 +23,7 @@ pub fn fd_fdstat_get<M: MemorySize>(
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let stat = wasi_try!(state.fs.fdstat(inodes.deref(), fd)); let stat = wasi_try!(state.fs.fdstat(fd));
let buf = buf_ptr.deref(&memory); let buf = buf_ptr.deref(&memory);

View File

@@ -26,7 +26,7 @@ pub fn fd_fdstat_set_flags(
let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let mut fd_map = state.fs.fd_map.write().unwrap(); let mut fd_map = state.fs.fd_map.write().unwrap();
let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf)); let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
let inode = fd_entry.inode; let inode = fd_entry.inode.clone();
if !fd_entry.rights.contains(Rights::FD_FDSTAT_SET_FLAGS) { if !fd_entry.rights.contains(Rights::FD_FDSTAT_SET_FLAGS) {
debug!( debug!(

View File

@@ -42,7 +42,7 @@ pub(crate) fn fd_filestat_get_internal<M: MemorySize>(
return Errno::Access; return Errno::Access;
} }
let stat = wasi_try!(state.fs.filestat_fd(inodes.deref(), fd)); let stat = wasi_try!(state.fs.filestat_fd(fd));
let buf = buf.deref(&memory); let buf = buf.deref(&memory);
wasi_try_mem!(buf.write(stat)); wasi_try_mem!(buf.write(stat));

View File

@@ -19,7 +19,7 @@ pub fn fd_filestat_set_size(
ctx.data().tid() ctx.data().tid()
); );
let env = ctx.data(); let env = ctx.data();
let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
let fd_entry = wasi_try!(state.fs.get_fd(fd)); let fd_entry = wasi_try!(state.fs.get_fd(fd));
let inode = fd_entry.inode; let inode = fd_entry.inode;
@@ -28,7 +28,7 @@ pub fn fd_filestat_set_size(
} }
{ {
let mut guard = inodes.arena[inode].write(); let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::File { handle, .. } => { Kind::File { handle, .. } => {
if let Some(handle) = handle { if let Some(handle) = handle {
@@ -48,7 +48,7 @@ pub fn fd_filestat_set_size(
Kind::Dir { .. } | Kind::Root { .. } => return Errno::Isdir, Kind::Dir { .. } | Kind::Root { .. } => return Errno::Isdir,
} }
} }
inodes.arena[inode].stat.write().unwrap().st_size = st_size; inode.stat.write().unwrap().st_size = st_size;
Errno::Success Errno::Success
} }

View File

@@ -23,7 +23,7 @@ pub fn fd_filestat_set_times(
ctx.data().tid() ctx.data().tid()
); );
let env = ctx.data(); let env = ctx.data();
let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
let fd_entry = wasi_try!(state.fs.get_fd(fd)); let fd_entry = wasi_try!(state.fs.get_fd(fd));
if !fd_entry.rights.contains(Rights::FD_FILESTAT_SET_TIMES) { if !fd_entry.rights.contains(Rights::FD_FILESTAT_SET_TIMES) {
@@ -36,8 +36,7 @@ pub fn fd_filestat_set_times(
return Errno::Inval; return Errno::Inval;
} }
let inode_idx = fd_entry.inode; let inode = fd_entry.inode;
let inode = &inodes.arena[inode_idx];
if fst_flags.contains(Fstflags::SET_ATIM) || fst_flags.contains(Fstflags::SET_ATIM_NOW) { if fst_flags.contains(Fstflags::SET_ATIM) || fst_flags.contains(Fstflags::SET_ATIM_NOW) {
let time_to_set = if fst_flags.contains(Fstflags::SET_ATIM) { let time_to_set = if fst_flags.contains(Fstflags::SET_ATIM) {

View File

@@ -15,25 +15,24 @@ pub fn fd_prestat_dir_name<M: MemorySize>(
path_len path_len
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
let path_chars = wasi_try_mem!(path.slice(&memory, path_len)); let path_chars = wasi_try_mem!(path.slice(&memory, path_len));
let real_inode = wasi_try!(state.fs.get_fd_inode(fd)); let inode = wasi_try!(state.fs.get_fd_inode(fd));
let inode_val = &inodes.arena[real_inode];
// check inode-val.is_preopened? // check inode-val.is_preopened?
trace!("=> inode: {:?}", inode_val); trace!("=> inode: {:?}", inode);
let guard = inode_val.read(); let guard = inode.read();
match guard.deref() { match guard.deref() {
Kind::Dir { .. } | Kind::Root { .. } => { Kind::Dir { .. } | Kind::Root { .. } => {
// TODO: verify this: null termination, etc // TODO: verify this: null termination, etc
let path_len: u64 = path_len.into(); let path_len: u64 = path_len.into();
if (inode_val.name.len() as u64) < path_len { if (inode.name.len() as u64) < path_len {
wasi_try_mem!(path_chars wasi_try_mem!(path_chars
.subslice(0..inode_val.name.len() as u64) .subslice(0..inode.name.len() as u64)
.write_slice(inode_val.name.as_bytes())); .write_slice(inode.name.as_bytes()));
wasi_try_mem!(path_chars.index(inode_val.name.len() as u64).write(0)); wasi_try_mem!(path_chars.index(inode.name.len() as u64).write(0));
//trace!("=> result: \"{}\"", inode_val.name); //trace!("=> result: \"{}\"", inode_val.name);

View File

@@ -21,16 +21,14 @@ pub fn fd_prestat_get<M: MemorySize>(
fd fd
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
let prestat_ptr = buf.deref(&memory); let prestat_ptr = buf.deref(&memory);
wasi_try_mem!( wasi_try_mem!(
prestat_ptr.write(wasi_try!(state.fs.prestat_fd(inodes.deref(), fd).map_err( prestat_ptr.write(wasi_try!(state.fs.prestat_fd(fd).map_err(|code| {
|code| { debug!("fd_prestat_get failed (fd={}) - errno={}", fd, code);
debug!("fd_prestat_get failed (fd={}) - errno={}", fd, code); code
code })))
}
)))
); );
Errno::Success Errno::Success

View File

@@ -1,7 +1,9 @@
use std::{collections::VecDeque, task::Waker};
use wasmer_vfs::AsyncReadExt; use wasmer_vfs::AsyncReadExt;
use super::*; use super::*;
use crate::syscalls::*; use crate::{fs::NotificationInner, syscalls::*};
/// ### `fd_read()` /// ### `fd_read()`
/// Read data from file descriptor /// Read data from file descriptor
@@ -35,15 +37,45 @@ pub fn fd_read<M: MemorySize>(
fd_entry.offset.load(Ordering::Acquire) as usize fd_entry.offset.load(Ordering::Acquire) as usize
}; };
let ret = fd_read_internal::<M>(ctx, fd, iovs, iovs_len, offset, nread, true); let res = fd_read_internal::<M>(&mut ctx, fd, iovs, iovs_len, offset, nread, true)?;
trace!(
%fd, let mut ret = Errno::Success;
"wasi[{}:{}]::fd_read - {:?}", let bytes_read = match res {
pid, Ok(bytes_read) => {
tid, trace!(
ret %fd,
); %bytes_read,
ret "wasi[{}:{}]::fd_read",
ctx.data().pid(),
ctx.data().tid(),
);
bytes_read
}
Err(err) => {
let read_err = err.name();
trace!(
%fd,
%read_err,
"wasi[{}:{}]::fd_read",
ctx.data().pid(),
ctx.data().tid(),
);
ret = err;
0
}
};
let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow));
let env = ctx.data();
let memory = env.memory_view(&ctx);
let env = ctx.data();
let memory = env.memory_view(&ctx);
let nread_ref = nread.deref(&memory);
wasi_try_mem_ok!(nread_ref.write(bytes_read));
Ok(ret)
} }
/// ### `fd_pread()` /// ### `fd_pread()`
@@ -62,7 +94,7 @@ pub fn fd_read<M: MemorySize>(
/// - `size_t nread` /// - `size_t nread`
/// The number of bytes read /// The number of bytes read
pub fn fd_pread<M: MemorySize>( pub fn fd_pread<M: MemorySize>(
ctx: FunctionEnvMut<'_, WasiEnv>, mut ctx: FunctionEnvMut<'_, WasiEnv>,
fd: WasiFd, fd: WasiFd,
iovs: WasmPtr<__wasi_iovec_t<M>, M>, iovs: WasmPtr<__wasi_iovec_t<M>, M>,
iovs_len: M::Offset, iovs_len: M::Offset,
@@ -72,86 +104,100 @@ pub fn fd_pread<M: MemorySize>(
let pid = ctx.data().pid(); let pid = ctx.data().pid();
let tid = ctx.data().tid(); let tid = ctx.data().tid();
let ret = fd_read_internal::<M>(ctx, fd, iovs, iovs_len, offset as usize, nread, false); let res = fd_read_internal::<M>(&mut ctx, fd, iovs, iovs_len, offset as usize, nread, false)?;
trace!(
%fd, let mut ret = Errno::Success;
%offset, let bytes_read = match res {
"wasi[{}:{}]::fd_pread - {:?}", Ok(bytes_read) => {
pid, trace!(
tid, %fd,
ret %offset,
); %bytes_read,
ret "wasi[{}:{}]::fd_pread - {:?}",
ctx.data().pid(),
ctx.data().tid(),
ret
);
bytes_read
}
Err(err) => {
let read_err = err.name();
trace!(
%fd,
%offset,
%read_err,
"wasi[{}:{}]::fd_pread - {:?}",
ctx.data().pid(),
ctx.data().tid(),
ret
);
ret = err;
0
}
};
let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow));
let env = ctx.data();
let memory = env.memory_view(&ctx);
let env = ctx.data();
let memory = env.memory_view(&ctx);
let nread_ref = nread.deref(&memory);
wasi_try_mem_ok!(nread_ref.write(bytes_read));
Ok(ret)
} }
/// ### `fd_pread()`
/// Read from the file at the given offset without updating the file cursor.
/// This acts like a stateless version of Seek + Read
/// Inputs:
/// - `Fd fd`
/// The file descriptor to read the data with
/// - `const __wasi_iovec_t* iovs'
/// Vectors where the data will be stored
/// - `size_t iovs_len`
/// The number of vectors to store the data into
/// - `Filesize offset`
/// The file cursor to use: the starting position from which data will be read
/// Output:
/// - `size_t nread`
/// The number of bytes read
fn fd_read_internal<M: MemorySize>( fn fd_read_internal<M: MemorySize>(
mut ctx: FunctionEnvMut<'_, WasiEnv>, ctx: &mut FunctionEnvMut<'_, WasiEnv>,
fd: WasiFd, fd: WasiFd,
iovs: WasmPtr<__wasi_iovec_t<M>, M>, iovs: WasmPtr<__wasi_iovec_t<M>, M>,
iovs_len: M::Offset, iovs_len: M::Offset,
offset: usize, offset: usize,
nread: WasmPtr<M::Offset, M>, nread: WasmPtr<M::Offset, M>,
should_update_cursor: bool, should_update_cursor: bool,
) -> Result<Errno, WasiError> { ) -> Result<Result<usize, Errno>, WasiError> {
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); wasi_try_ok_ok!(WasiEnv::process_signals_and_exit(ctx)?);
let mut env = ctx.data(); let mut env = ctx.data();
let state = env.state.clone(); let state = env.state.clone();
let inodes = state.inodes.clone();
let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); let fd_entry = wasi_try_ok_ok!(state.fs.get_fd(fd));
let is_stdio = fd_entry.is_stdio; let is_stdio = fd_entry.is_stdio;
let bytes_read = { let bytes_read = {
if !is_stdio && !fd_entry.rights.contains(Rights::FD_READ) { if !is_stdio && !fd_entry.rights.contains(Rights::FD_READ) {
// TODO: figure out the error to return when lacking rights // TODO: figure out the error to return when lacking rights
return Ok(Errno::Access); return Ok(Err(Errno::Access));
} }
let inode_idx = fd_entry.inode; let inode = fd_entry.inode;
let fd_flags = fd_entry.flags; let fd_flags = fd_entry.flags;
let max_size = { let max_size = {
let memory = env.memory_view(&ctx); let memory = env.memory_view(ctx);
let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len)); let iovs_arr = wasi_try_mem_ok_ok!(iovs.slice(&memory, iovs_len));
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_ok!(iovs.read());
let buf_len: usize = let buf_len: usize =
wasi_try_ok!(iovs.buf_len.try_into().map_err(|_| Errno::Overflow)); wasi_try_ok_ok!(iovs.buf_len.try_into().map_err(|_| Errno::Overflow));
max_size += buf_len; max_size += buf_len;
} }
max_size max_size
}; };
let (bytes_read, can_update_cursor) = { let (bytes_read, can_update_cursor) = {
let inodes = inodes.read().unwrap();
let inode = &inodes.arena[inode_idx];
let mut guard = inode.write(); let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::File { handle, .. } => { Kind::File { handle, .. } => {
if let Some(handle) = handle { if let Some(handle) = handle {
let handle = handle.clone(); let handle = handle.clone();
drop(guard); drop(guard);
drop(inodes);
let data = wasi_try_ok!(__asyncify( let data = wasi_try_ok_ok!(__asyncify(
&mut ctx, ctx,
if fd_flags.contains(Fdflags::NONBLOCK) { if fd_flags.contains(Fdflags::NONBLOCK) {
Some(Duration::ZERO) Some(Duration::ZERO)
} else { } else {
@@ -166,8 +212,7 @@ fn fd_read_internal<M: MemorySize>(
.map_err(map_io_err)?; .map_err(map_io_err)?;
} }
// TODO: optimize with MaybeUninit let mut data = Vec::with_capacity(max_size);
let mut data = vec![0u8; max_size];
unsafe { data.set_len(max_size) }; unsafe { data.set_len(max_size) };
let amt = handle.read(&mut data[..]).await.map_err(|err| { let amt = handle.read(&mut data[..]).await.map_err(|err| {
let err = From::<std::io::Error>::from(err); let err = From::<std::io::Error>::from(err);
@@ -193,22 +238,21 @@ fn fd_read_internal<M: MemorySize>(
env = ctx.data(); env = ctx.data();
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len)); let iovs_arr = wasi_try_mem_ok_ok!(iovs.slice(&memory, iovs_len));
let read = wasi_try_ok!(read_bytes(&data[..], &memory, iovs_arr)); let read = wasi_try_ok_ok!(read_bytes(&data[..], &memory, iovs_arr));
(read, true) (read, true)
} else { } else {
return Ok(Errno::Inval); return Ok(Err(Errno::Badf));
} }
} }
Kind::Socket { socket } => { Kind::Socket { socket } => {
let socket = socket.clone(); let socket = socket.clone();
drop(guard); drop(guard);
drop(inodes);
let tasks = env.tasks.clone(); let tasks = env.tasks.clone();
let res = __asyncify( let res = __asyncify(
&mut ctx, ctx,
if fd_flags.contains(Fdflags::NONBLOCK) { if fd_flags.contains(Fdflags::NONBLOCK) {
Some(Duration::ZERO) Some(Duration::ZERO)
} else { } else {
@@ -238,14 +282,14 @@ fn fd_read_internal<M: MemorySize>(
match res { match res {
Err(Errno::Connaborted) | Err(Errno::Connreset) => (0, false), Err(Errno::Connaborted) | Err(Errno::Connreset) => (0, false),
res => { res => {
let data = wasi_try_ok!(res); let data = wasi_try_ok_ok!(res);
env = ctx.data(); env = ctx.data();
let data_len = data.len(); let data_len = data.len();
let mut reader = &data[..]; let mut reader = &data[..];
let memory = env.memory_view(&ctx); let memory = env.memory_view(&ctx);
let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len)); let iovs_arr = wasi_try_mem_ok_ok!(iovs.slice(&memory, iovs_len));
let bytes_read = wasi_try_ok!( let bytes_read = wasi_try_ok_ok!(
read_bytes(reader, &memory, iovs_arr).map(|_| data_len) read_bytes(reader, &memory, iovs_arr).map(|_| data_len)
); );
(bytes_read, false) (bytes_read, false)
@@ -256,10 +300,9 @@ fn fd_read_internal<M: MemorySize>(
let mut pipe = pipe.clone(); let mut pipe = pipe.clone();
drop(guard); drop(guard);
drop(inodes);
let data = wasi_try_ok!(__asyncify( let data = wasi_try_ok_ok!(__asyncify(
&mut ctx, ctx,
if fd_flags.contains(Fdflags::NONBLOCK) { if fd_flags.contains(Fdflags::NONBLOCK) {
Some(Duration::ZERO) Some(Duration::ZERO)
} else { } else {
@@ -284,78 +327,103 @@ fn fd_read_internal<M: MemorySize>(
let data_len = data.len(); let data_len = data.len();
let mut reader = &data[..]; let mut reader = &data[..];
let memory = env.memory_view(&ctx); let memory = env.memory_view(ctx);
let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len)); let iovs_arr = wasi_try_mem_ok_ok!(iovs.slice(&memory, iovs_len));
let bytes_read = let bytes_read =
wasi_try_ok!(read_bytes(reader, &memory, iovs_arr).map(|_| data_len)); wasi_try_ok_ok!(read_bytes(reader, &memory, iovs_arr).map(|_| data_len));
(bytes_read, false) (bytes_read, false)
} }
Kind::Dir { .. } | Kind::Root { .. } => { Kind::Dir { .. } | Kind::Root { .. } => {
// TODO: verify // TODO: verify
return Ok(Errno::Isdir); return Ok(Err(Errno::Isdir));
} }
Kind::EventNotifications { Kind::EventNotifications(inner) => {
counter: ref_counter, // Create a poller
is_semaphore: ref_is_semaphore, struct NotifyPoller {
wakers: ref_wakers, inner: Arc<NotificationInner>,
.. non_blocking: bool,
} => {
let counter = Arc::clone(ref_counter);
let is_semaphore: bool = *ref_is_semaphore;
let wakers = Arc::clone(ref_wakers);
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
{
let mut guard = wakers.lock().unwrap();
guard.push_front(tx);
} }
let poller = NotifyPoller {
inner: inner.clone(),
non_blocking: fd_flags.contains(Fdflags::NONBLOCK),
};
drop(guard); drop(guard);
drop(inodes);
let ret; // The poller will register itself for notifications and wait for the
loop { // counter to drop
let val = counter.load(Ordering::Acquire); impl Future for NotifyPoller {
if val > 0 { type Output = Result<u64, Errno>;
let new_val = if is_semaphore { val - 1 } else { 0 }; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if counter if !self.non_blocking {
.compare_exchange(val, new_val, Ordering::AcqRel, Ordering::Acquire) let waker = cx.waker();
.is_ok() let mut guard = self.inner.wakers.lock().unwrap();
{ if guard.iter().any(|w| w.will_wake(waker)) == false {
let mut memory = env.memory_view(&ctx); guard.push_front(waker.clone());
let reader = val.to_ne_bytes(); }
let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len)); }
ret = wasi_try_ok!(read_bytes(&reader[..], &memory, iovs_arr));
break; let wake_all = || {
} else { self.inner.last_poll.store(u64::MAX, Ordering::Release);
continue; let mut guard = self.inner.wakers.lock().unwrap();
while let Some(waker) = guard.pop_front() {
waker.wake();
}
};
loop {
let val = self.inner.counter.load(Ordering::Acquire);
if val > 0 {
let new_val = if self.inner.is_semaphore { val - 1 } else { 0 };
if self
.inner
.counter
.compare_exchange(
val,
new_val,
Ordering::AcqRel,
Ordering::Acquire,
)
.is_ok()
{
wake_all();
return Poll::Ready(Ok(val));
} else {
continue;
}
}
// If its none blocking then exit
if self.non_blocking {
wake_all();
return Poll::Ready(Err(Errno::Again));
}
return Poll::Pending;
} }
} }
}
// If its none blocking then exit // Yield until the notifications are triggered
if fd_flags.contains(Fdflags::NONBLOCK) { let tasks_inner = env.tasks.clone();
return Ok(Errno::Again); let val = wasi_try_ok_ok!(__asyncify(ctx, None, async { poller.await })?
}
// Yield until the notifications are triggered
let tasks_inner = env.tasks.clone();
rx = wasi_try_ok!(__asyncify(&mut ctx, None, async move {
let _ = rx.recv().await;
Ok(rx)
})?
.map_err(|err| match err { .map_err(|err| match err {
Errno::Timedout => Errno::Again, Errno::Timedout => Errno::Again,
a => a, a => a,
})); }));
env = ctx.data(); env = ctx.data();
}
let mut memory = env.memory_view(ctx);
let reader = val.to_ne_bytes();
let iovs_arr = wasi_try_mem_ok_ok!(iovs.slice(&memory, iovs_len));
let ret = wasi_try_ok_ok!(read_bytes(&reader[..], &memory, iovs_arr));
(ret, false) (ret, false)
} }
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"), Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"),
Kind::Buffer { buffer } => { Kind::Buffer { buffer } => {
let memory = env.memory_view(&ctx); let memory = env.memory_view(ctx);
let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len)); let iovs_arr = wasi_try_mem_ok_ok!(iovs.slice(&memory, iovs_len));
let read = wasi_try_ok!(read_bytes(&buffer[offset..], &memory, iovs_arr)); let read = wasi_try_ok_ok!(read_bytes(&buffer[offset..], &memory, iovs_arr));
(read, true) (read, true)
} }
} }
@@ -364,7 +432,7 @@ fn fd_read_internal<M: MemorySize>(
if !is_stdio && should_update_cursor && can_update_cursor { if !is_stdio && should_update_cursor && can_update_cursor {
// reborrow // reborrow
let mut fd_map = state.fs.fd_map.write().unwrap(); let mut fd_map = state.fs.fd_map.write().unwrap();
let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf)); let fd_entry = wasi_try_ok_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
let old = fd_entry let old = fd_entry
.offset .offset
.fetch_add(bytes_read as u64, Ordering::AcqRel); .fetch_add(bytes_read as u64, Ordering::AcqRel);
@@ -373,19 +441,5 @@ fn fd_read_internal<M: MemorySize>(
bytes_read bytes_read
}; };
let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow)); Ok(Ok(bytes_read))
trace!(
"wasi[{}:{}]::fd_read: fd={},bytes_read={}",
ctx.data().pid(),
ctx.data().tid(),
fd,
bytes_read
);
let env = ctx.data();
let memory = env.memory_view(&ctx);
let nread_ref = nread.deref(&memory);
wasi_try_mem_ok!(nread_ref.write(bytes_read));
Ok(Errno::Success)
} }

View File

@@ -30,7 +30,7 @@ pub fn fd_readdir<M: MemorySize>(
ctx.data().tid() ctx.data().tid()
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
// TODO: figure out how this is supposed to work; // TODO: figure out how this is supposed to work;
// is it supposed to pack the buffer full every time until it can't? or do one at a time? // is it supposed to pack the buffer full every time until it can't? or do one at a time?
@@ -41,7 +41,7 @@ pub fn fd_readdir<M: MemorySize>(
let mut buf_idx = 0usize; let mut buf_idx = 0usize;
let entries: Vec<(String, Filetype, u64)> = { let entries: Vec<(String, Filetype, u64)> = {
let guard = inodes.arena[working_dir.inode].read(); let guard = working_dir.inode.read();
match guard.deref() { match guard.deref() {
Kind::Dir { path, entries, .. } => { Kind::Dir { path, entries, .. } => {
debug!("Reading dir {:?}", path); debug!("Reading dir {:?}", path);
@@ -65,16 +65,12 @@ pub fn fd_readdir<M: MemorySize>(
)) ))
}) })
.collect::<Result<Vec<(String, Filetype, u64)>, _>>()); .collect::<Result<Vec<(String, Filetype, u64)>, _>>());
entry_vec.extend( entry_vec.extend(entries.iter().filter(|(_, inode)| inode.is_preopened).map(
entries |(name, inode)| {
.iter() let stat = inode.stat.read().unwrap();
.filter(|(_, inode)| inodes.arena[**inode].is_preopened) (inode.name.to_string(), stat.st_filetype, stat.st_ino)
.map(|(name, inode)| { },
let entry = &inodes.arena[*inode]; ));
let stat = entry.stat.read().unwrap();
(entry.name.to_string(), stat.st_filetype, stat.st_ino)
}),
);
// adding . and .. special folders // adding . and .. special folders
// TODO: inode // TODO: inode
entry_vec.push((".".to_string(), Filetype::Directory, 0)); entry_vec.push((".".to_string(), Filetype::Directory, 0));
@@ -85,17 +81,18 @@ pub fn fd_readdir<M: MemorySize>(
Kind::Root { entries } => { Kind::Root { entries } => {
debug!("Reading root"); debug!("Reading root");
let sorted_entries = { let sorted_entries = {
let mut entry_vec: Vec<(String, Inode)> = let mut entry_vec: Vec<(String, InodeGuard)> = entries
entries.iter().map(|(a, b)| (a.clone(), *b)).collect(); .iter()
.map(|(a, b)| (a.clone(), b.clone()))
.collect();
entry_vec.sort_by(|a, b| a.0.cmp(&b.0)); entry_vec.sort_by(|a, b| a.0.cmp(&b.0));
entry_vec entry_vec
}; };
sorted_entries sorted_entries
.into_iter() .into_iter()
.map(|(name, inode)| { .map(|(name, inode)| {
let entry = &inodes.arena[inode]; let stat = inode.stat.read().unwrap();
let stat = entry.stat.read().unwrap(); (format!("/{}", inode.name), stat.st_filetype, stat.st_ino)
(format!("/{}", entry.name), stat.st_filetype, stat.st_ino)
}) })
.collect() .collect()
} }

View File

@@ -20,25 +20,18 @@ pub fn fd_renumber(ctx: FunctionEnvMut<'_, WasiEnv>, from: WasiFd, to: WasiFd) -
return Errno::Success; return Errno::Success;
} }
let env = ctx.data(); let env = ctx.data();
let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
let mut fd_map = state.fs.fd_map.write().unwrap(); let mut fd_map = state.fs.fd_map.write().unwrap();
let fd_entry = wasi_try!(fd_map.get_mut(&from).ok_or(Errno::Badf)); let fd_entry = wasi_try!(fd_map.get_mut(&from).ok_or(Errno::Badf));
fd_entry.ref_cnt.fetch_add(1, Ordering::Acquire);
let new_fd_entry = Fd { let new_fd_entry = Fd {
// TODO: verify this is correct // TODO: verify this is correct
ref_cnt: fd_entry.ref_cnt.clone(),
offset: fd_entry.offset.clone(), offset: fd_entry.offset.clone(),
rights: fd_entry.rights_inheriting, rights: fd_entry.rights_inheriting,
inode: fd_entry.inode.clone(),
..*fd_entry ..*fd_entry
}; };
if let Some(fd_entry) = fd_map.get(&to).cloned() {
if fd_entry.ref_cnt.fetch_sub(1, Ordering::AcqRel) == 1 {
wasi_try!(state.fs.close_fd_ext(inodes.deref(), &mut fd_map, to));
}
}
fd_map.insert(to, new_fd_entry); fd_map.insert(to, new_fd_entry);
Errno::Success Errno::Success

View File

@@ -33,7 +33,7 @@ pub fn fd_seek<M: MemorySize>(
let env = ctx.data(); let env = ctx.data();
let state = env.state.clone(); let state = env.state.clone();
let (memory, _, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (memory, _) = env.get_memory_and_wasi_state(&ctx, 0);
let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
if !fd_entry.rights.contains(Rights::FD_SEEK) { if !fd_entry.rights.contains(Rights::FD_SEEK) {
@@ -60,15 +60,13 @@ pub fn fd_seek<M: MemorySize>(
} }
Whence::End => { Whence::End => {
use std::io::SeekFrom; use std::io::SeekFrom;
let inode_idx = fd_entry.inode; let mut guard = fd_entry.inode.write();
let mut guard = inodes.arena[inode_idx].write();
let deref_mut = guard.deref_mut(); let deref_mut = guard.deref_mut();
match deref_mut { match deref_mut {
Kind::File { ref mut handle, .. } => { Kind::File { ref mut handle, .. } => {
if let Some(handle) = handle { if let Some(handle) = handle {
let handle = handle.clone(); let handle = handle.clone();
drop(guard); drop(guard);
drop(inodes);
wasi_try_ok!(__asyncify(&mut ctx, None, async move { wasi_try_ok!(__asyncify(&mut ctx, None, async move {
let mut handle = handle.write().unwrap(); let mut handle = handle.write().unwrap();

View File

@@ -14,7 +14,7 @@ pub fn fd_sync(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result<Errno
debug!("wasi[{}:{}]::fd_sync", ctx.data().pid(), ctx.data().tid()); debug!("wasi[{}:{}]::fd_sync", ctx.data().pid(), ctx.data().tid());
debug!("=> fd={}", fd); debug!("=> fd={}", fd);
let env = ctx.data(); let env = ctx.data();
let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
if !fd_entry.rights.contains(Rights::FD_SYNC) { if !fd_entry.rights.contains(Rights::FD_SYNC) {
return Ok(Errno::Access); return Ok(Errno::Access);
@@ -23,14 +23,12 @@ pub fn fd_sync(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result<Errno
// TODO: implement this for more than files // TODO: implement this for more than files
{ {
let mut guard = inodes.arena[inode].write(); let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::File { handle, .. } => { Kind::File { handle, .. } => {
if let Some(handle) = handle { if let Some(handle) = handle {
let handle = handle.clone(); let handle = handle.clone();
drop(fd_entry);
drop(guard); drop(guard);
drop(inodes);
let size = { let size = {
wasi_try_ok!(__asyncify(&mut ctx, None, async move { wasi_try_ok!(__asyncify(&mut ctx, None, async move {
@@ -45,11 +43,11 @@ pub fn fd_sync(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result<Errno
{ {
let env = ctx.data(); let env = ctx.data();
let (_, mut state, inodes) = let (_, mut state, inodes) =
env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); let fd_entry = wasi_try_ok!(state.fs.get_fd(fd));
let inode = fd_entry.inode; let inode = fd_entry.inode;
let mut guard = inodes.arena[inode].stat.write().unwrap(); let mut guard = inode.stat.write().unwrap();
guard.st_size = size; guard.st_size = size;
} }
} else { } else {

View File

@@ -113,18 +113,15 @@ fn fd_write_internal<M: MemorySize>(
} }
let fd_flags = fd_entry.flags; let fd_flags = fd_entry.flags;
let inode_idx = fd_entry.inode;
let (bytes_written, can_update_cursor) = { let (bytes_written, can_update_cursor) = {
let (mut memory, _, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (mut memory, _) = env.get_memory_and_wasi_state(&ctx, 0);
let inode = &inodes.arena[inode_idx]; let mut guard = fd_entry.inode.write();
let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::File { handle, .. } => { Kind::File { handle, .. } => {
if let Some(handle) = handle { if let Some(handle) = handle {
let handle = handle.clone(); let handle = handle.clone();
drop(guard); drop(guard);
drop(inodes);
let buf_len: M::Offset = iovs_arr let buf_len: M::Offset = iovs_arr
.iter() .iter()
@@ -168,7 +165,6 @@ fn fd_write_internal<M: MemorySize>(
Kind::Socket { socket } => { Kind::Socket { socket } => {
let socket = socket.clone(); let socket = socket.clone();
drop(guard); drop(guard);
drop(inodes);
let buf_len: M::Offset = iovs_arr let buf_len: M::Offset = iovs_arr
.iter() .iter()
@@ -203,12 +199,7 @@ fn fd_write_internal<M: MemorySize>(
// TODO: verify // TODO: verify
return Ok(Errno::Isdir); return Ok(Errno::Isdir);
} }
Kind::EventNotifications { Kind::EventNotifications(inner) => {
counter,
wakers,
immediate,
..
} => {
let mut val: [MaybeUninit<u8>; 8] = let mut val: [MaybeUninit<u8>; 8] =
unsafe { MaybeUninit::uninit().assume_init() }; unsafe { MaybeUninit::uninit().assume_init() };
let written = wasi_try_ok!(copy_to_slice(&memory, iovs_arr, &mut val[..])); let written = wasi_try_ok!(copy_to_slice(&memory, iovs_arr, &mut val[..]));
@@ -217,12 +208,12 @@ fn fd_write_internal<M: MemorySize>(
} }
let val = u64::from_ne_bytes(unsafe { std::mem::transmute(val) }); let val = u64::from_ne_bytes(unsafe { std::mem::transmute(val) });
counter.fetch_add(val, Ordering::AcqRel); inner.counter.fetch_add(val, Ordering::AcqRel);
inner.last_poll.store(u64::MAX, Ordering::Release);
{ {
let mut guard = wakers.lock().unwrap(); let mut guard = inner.wakers.lock().unwrap();
immediate.store(true, Ordering::Release);
while let Some(wake) = guard.pop_back() { while let Some(wake) = guard.pop_back() {
let _ = wake.send(()); wake.wake();
} }
} }
@@ -252,9 +243,8 @@ fn fd_write_internal<M: MemorySize>(
// we set the size but we don't return any errors if it fails as // we set the size but we don't return any errors if it fails as
// pipes and sockets will not do anything with this // pipes and sockets will not do anything with this
let (mut memory, _, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let (mut memory, _, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let inode = &inodes.arena[inode_idx];
// Cast is valid because we don't support 128 bit systems... // Cast is valid because we don't support 128 bit systems...
inode.stat.write().unwrap().st_size += bytes_written as u64; fd_entry.inode.stat.write().unwrap().st_size += bytes_written as u64;
} }
bytes_written bytes_written
}; };

View File

@@ -26,11 +26,11 @@ pub fn path_create_directory<M: MemorySize>(
ctx.data().tid() ctx.data().tid()
); );
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, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let working_dir = wasi_try!(state.fs.get_fd(fd)); let working_dir = wasi_try!(state.fs.get_fd(fd));
{ {
let guard = inodes.arena[working_dir.inode].read(); let guard = working_dir.inode.read();
if let Kind::Root { .. } = guard.deref() { if let Kind::Root { .. } = guard.deref() {
return Errno::Access; return Errno::Access;
} }
@@ -71,7 +71,9 @@ pub fn path_create_directory<M: MemorySize>(
let mut cur_dir_inode = working_dir.inode; let mut cur_dir_inode = working_dir.inode;
for comp in &path_vec { for comp in &path_vec {
debug!("Creating dir {}", comp); debug!("Creating dir {}", comp);
let mut guard = inodes.arena[cur_dir_inode].write();
let processing_cur_dir_inode = cur_dir_inode.clone();
let mut guard = processing_cur_dir_inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::Dir { Kind::Dir {
ref mut entries, ref mut entries,
@@ -80,8 +82,8 @@ pub fn path_create_directory<M: MemorySize>(
} => { } => {
match comp.borrow() { match comp.borrow() {
".." => { ".." => {
if let Some(p) = parent { if let Some(p) = parent.upgrade() {
cur_dir_inode = *p; cur_dir_inode = p;
continue; continue;
} }
} }
@@ -89,7 +91,7 @@ pub fn path_create_directory<M: MemorySize>(
_ => (), _ => (),
} }
if let Some(child) = entries.get(comp) { if let Some(child) = entries.get(comp) {
cur_dir_inode = *child; cur_dir_inode = child.clone();
} else { } else {
let mut adjusted_path = path.clone(); let mut adjusted_path = path.clone();
drop(guard); drop(guard);
@@ -99,7 +101,7 @@ pub fn path_create_directory<M: MemorySize>(
if let Ok(adjusted_path_stat) = path_filestat_get_internal( if let Ok(adjusted_path_stat) = path_filestat_get_internal(
&memory, &memory,
state, state,
inodes.deref_mut(), inodes,
fd, fd,
0, 0,
&adjusted_path.to_string_lossy(), &adjusted_path.to_string_lossy(),
@@ -111,25 +113,21 @@ pub fn path_create_directory<M: MemorySize>(
wasi_try!(state.fs_create_dir(&adjusted_path)); wasi_try!(state.fs_create_dir(&adjusted_path));
} }
let kind = Kind::Dir { let kind = Kind::Dir {
parent: Some(cur_dir_inode), parent: cur_dir_inode.downgrade(),
path: adjusted_path, path: adjusted_path,
entries: Default::default(), entries: Default::default(),
}; };
let new_inode = wasi_try!(state.fs.create_inode( let new_inode =
inodes.deref_mut(), wasi_try!(state.fs.create_inode(inodes, kind, false, comp.to_string()));
kind,
false,
comp.to_string()
));
// reborrow to insert // reborrow to insert
{ {
let mut guard = inodes.arena[cur_dir_inode].write(); let mut guard = cur_dir_inode.write();
if let Kind::Dir { if let Kind::Dir {
ref mut entries, .. ref mut entries, ..
} = guard.deref_mut() } = guard.deref_mut()
{ {
entries.insert(comp.to_string(), new_inode); entries.insert(comp.to_string(), new_inode.clone());
} }
} }
cur_dir_inode = new_inode; cur_dir_inode = new_inode;

View File

@@ -24,7 +24,7 @@ pub fn path_filestat_get<M: MemorySize>(
buf: WasmPtr<Filestat, M>, buf: WasmPtr<Filestat, M>,
) -> Errno { ) -> Errno {
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let mut path_string = unsafe { get_input_str!(&memory, path, path_len) }; let mut path_string = unsafe { get_input_str!(&memory, path, path_len) };
debug!( debug!(
@@ -49,7 +49,7 @@ pub fn path_filestat_get<M: MemorySize>(
let stat = wasi_try!(path_filestat_get_internal( let stat = wasi_try!(path_filestat_get_internal(
&memory, &memory,
state, state,
inodes.deref_mut(), inodes,
fd, fd,
flags, flags,
&path_string &path_string
@@ -77,7 +77,7 @@ pub fn path_filestat_get<M: MemorySize>(
pub fn path_filestat_get_internal( pub fn path_filestat_get_internal(
memory: &MemoryView, memory: &MemoryView,
state: &WasiState, state: &WasiState,
inodes: &mut crate::WasiInodes, inodes: &crate::WasiInodes,
fd: WasiFd, fd: WasiFd,
flags: LookupFlags, flags: LookupFlags,
path_string: &str, path_string: &str,
@@ -95,10 +95,10 @@ pub fn path_filestat_get_internal(
path_string, path_string,
flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0,
)?; )?;
if inodes.arena[file_inode].is_preopened { if file_inode.is_preopened {
Ok(*inodes.arena[file_inode].stat.read().unwrap().deref()) Ok(file_inode.stat.read().unwrap().deref().clone())
} else { } else {
let guard = inodes.arena[file_inode].read(); let guard = file_inode.read();
state.fs.get_stat_for_kind(inodes.deref(), guard.deref()) state.fs.get_stat_for_kind(guard.deref())
} }
} }

View File

@@ -34,7 +34,7 @@ pub fn path_filestat_set_times<M: MemorySize>(
ctx.data().tid() ctx.data().tid()
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let fd_entry = wasi_try!(state.fs.get_fd(fd)); let fd_entry = wasi_try!(state.fs.get_fd(fd));
let fd_inode = fd_entry.inode; let fd_inode = fd_entry.inode;
if !fd_entry.rights.contains(Rights::PATH_FILESTAT_SET_TIMES) { if !fd_entry.rights.contains(Rights::PATH_FILESTAT_SET_TIMES) {
@@ -61,25 +61,23 @@ pub fn path_filestat_set_times<M: MemorySize>(
} }
let file_inode = wasi_try!(state.fs.get_inode_at_path( let file_inode = wasi_try!(state.fs.get_inode_at_path(
inodes.deref_mut(), inodes,
fd, fd,
&path_string, &path_string,
flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0,
)); ));
let stat = { let stat = {
let guard = inodes.arena[file_inode].read(); let guard = file_inode.read();
wasi_try!(state.fs.get_stat_for_kind(inodes.deref(), guard.deref())) wasi_try!(state.fs.get_stat_for_kind(guard.deref()))
}; };
let inode = &inodes.arena[fd_inode];
if fst_flags.contains(Fstflags::SET_ATIM) || fst_flags.contains(Fstflags::SET_ATIM_NOW) { if fst_flags.contains(Fstflags::SET_ATIM) || fst_flags.contains(Fstflags::SET_ATIM_NOW) {
let time_to_set = if fst_flags.contains(Fstflags::SET_ATIM) { let time_to_set = if fst_flags.contains(Fstflags::SET_ATIM) {
st_atim st_atim
} else { } else {
wasi_try!(get_current_time_in_nanos()) wasi_try!(get_current_time_in_nanos())
}; };
inode.stat.write().unwrap().st_atim = time_to_set; fd_inode.stat.write().unwrap().st_atim = time_to_set;
} }
if fst_flags.contains(Fstflags::SET_MTIM) || fst_flags.contains(Fstflags::SET_MTIM_NOW) { if fst_flags.contains(Fstflags::SET_MTIM) || fst_flags.contains(Fstflags::SET_MTIM_NOW) {
let time_to_set = if fst_flags.contains(Fstflags::SET_MTIM) { let time_to_set = if fst_flags.contains(Fstflags::SET_MTIM) {
@@ -87,7 +85,7 @@ pub fn path_filestat_set_times<M: MemorySize>(
} else { } else {
wasi_try!(get_current_time_in_nanos()) wasi_try!(get_current_time_in_nanos())
}; };
inode.stat.write().unwrap().st_mtim = time_to_set; fd_inode.stat.write().unwrap().st_mtim = time_to_set;
} }
Errno::Success Errno::Success

View File

@@ -33,7 +33,7 @@ pub fn path_link<M: MemorySize>(
debug!(" - will follow symlinks when opening path"); debug!(" - will follow symlinks when opening path");
} }
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let mut old_path_str = unsafe { get_input_str!(&memory, old_path, old_path_len) }; let mut old_path_str = unsafe { get_input_str!(&memory, old_path, old_path_len) };
let mut new_path_str = unsafe { get_input_str!(&memory, new_path, new_path_len) }; let mut new_path_str = unsafe { get_input_str!(&memory, new_path, new_path_len) };
let source_fd = wasi_try!(state.fs.get_fd(old_fd)); let source_fd = wasi_try!(state.fs.get_fd(old_fd));
@@ -54,30 +54,28 @@ pub fn path_link<M: MemorySize>(
new_path_str = ctx.data().state.fs.relative_path_to_absolute(new_path_str); new_path_str = ctx.data().state.fs.relative_path_to_absolute(new_path_str);
let source_inode = wasi_try!(state.fs.get_inode_at_path( let source_inode = wasi_try!(state.fs.get_inode_at_path(
inodes.deref_mut(), inodes,
old_fd, old_fd,
&old_path_str, &old_path_str,
old_flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, old_flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0,
)); ));
let target_path_arg = std::path::PathBuf::from(&new_path_str); let target_path_arg = std::path::PathBuf::from(&new_path_str);
let (target_parent_inode, new_entry_name) = wasi_try!(state.fs.get_parent_inode_at_path( let (target_parent_inode, new_entry_name) =
inodes.deref_mut(), wasi_try!(state
new_fd, .fs
&target_path_arg, .get_parent_inode_at_path(inodes, new_fd, &target_path_arg, false));
false
));
if inodes.arena[source_inode].stat.write().unwrap().st_nlink == Linkcount::max_value() { if source_inode.stat.write().unwrap().st_nlink == Linkcount::max_value() {
return Errno::Mlink; return Errno::Mlink;
} }
{ {
let mut guard = inodes.arena[target_parent_inode].write(); let mut guard = target_parent_inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::Dir { entries, .. } => { Kind::Dir { entries, .. } => {
if entries.contains_key(&new_entry_name) { if entries.contains_key(&new_entry_name) {
return Errno::Exist; return Errno::Exist;
} }
entries.insert(new_entry_name, source_inode); entries.insert(new_entry_name, source_inode.clone());
} }
Kind::Root { .. } => return Errno::Inval, Kind::Root { .. } => return Errno::Inval,
Kind::File { .. } Kind::File { .. }
@@ -88,7 +86,7 @@ pub fn path_link<M: MemorySize>(
| Kind::EventNotifications { .. } => return Errno::Notdir, | Kind::EventNotifications { .. } => return Errno::Notdir,
} }
} }
inodes.arena[source_inode].stat.write().unwrap().st_nlink += 1; source_inode.stat.write().unwrap().st_nlink += 1;
Errno::Success Errno::Success
} }

View File

@@ -42,7 +42,7 @@ pub fn path_open<M: MemorySize>(
debug!(" - will follow symlinks when opening path"); debug!(" - will follow symlinks when opening path");
} }
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
/* TODO: find actual upper bound on name size (also this is a path, not a name :think-fish:) */ /* TODO: find actual upper bound on name size (also this is a path, not a name :think-fish:) */
let path_len64: u64 = path_len.into(); let path_len64: u64 = path_len.into();
if path_len64 > 1024u64 * 1024u64 { if path_len64 > 1024u64 * 1024u64 {
@@ -81,7 +81,7 @@ pub fn path_open<M: MemorySize>(
let path_arg = std::path::PathBuf::from(&path_string); let path_arg = std::path::PathBuf::from(&path_string);
let maybe_inode = state.fs.get_inode_at_path( let maybe_inode = state.fs.get_inode_at_path(
inodes.deref_mut(), inodes,
dirfd, dirfd,
&path_string, &path_string,
dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0,
@@ -148,7 +148,9 @@ pub fn path_open<M: MemorySize>(
let inode = if let Ok(inode) = maybe_inode { let inode = if let Ok(inode) = maybe_inode {
// Happy path, we found the file we're trying to open // Happy path, we found the file we're trying to open
let mut guard = inodes.arena[inode].write(); let processing_inode = inode.clone();
let mut guard = processing_inode.write();
let deref_mut = guard.deref_mut(); let deref_mut = guard.deref_mut();
match deref_mut { match deref_mut {
Kind::File { Kind::File {
@@ -244,13 +246,13 @@ pub fn path_open<M: MemorySize>(
// strip end file name // strip end file name
let (parent_inode, new_entity_name) = wasi_try!(state.fs.get_parent_inode_at_path( let (parent_inode, new_entity_name) = wasi_try!(state.fs.get_parent_inode_at_path(
inodes.deref_mut(), inodes,
dirfd, dirfd,
&path_arg, &path_arg,
dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0
)); ));
let new_file_host_path = { let new_file_host_path = {
let guard = inodes.arena[parent_inode].read(); let guard = parent_inode.read();
match guard.deref() { match guard.deref() {
Kind::Dir { path, .. } => { Kind::Dir { path, .. } => {
let mut new_path = path.clone(); let mut new_path = path.clone();
@@ -301,21 +303,18 @@ pub fn path_open<M: MemorySize>(
path: new_file_host_path, path: new_file_host_path,
fd: None, fd: None,
}; };
wasi_try!(state.fs.create_inode( wasi_try!(state
inodes.deref_mut(), .fs
kind, .create_inode(inodes, kind, false, new_entity_name.clone()))
false,
new_entity_name.clone()
))
}; };
{ {
let mut guard = inodes.arena[parent_inode].write(); let mut guard = parent_inode.write();
if let Kind::Dir { if let Kind::Dir {
ref mut entries, .. ref mut entries, ..
} = guard.deref_mut() } = guard.deref_mut()
{ {
entries.insert(new_entity_name, new_inode); entries.insert(new_entity_name, new_inode.clone());
} }
} }

View File

@@ -32,7 +32,7 @@ pub fn path_readlink<M: MemorySize>(
ctx.data().tid() ctx.data().tid()
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let base_dir = wasi_try!(state.fs.get_fd(dir_fd)); let base_dir = wasi_try!(state.fs.get_fd(dir_fd));
if !base_dir.rights.contains(Rights::PATH_READLINK) { if !base_dir.rights.contains(Rights::PATH_READLINK) {
@@ -51,12 +51,10 @@ pub fn path_readlink<M: MemorySize>(
); );
} }
let inode = wasi_try!(state let inode = wasi_try!(state.fs.get_inode_at_path(inodes, dir_fd, &path_str, false));
.fs
.get_inode_at_path(inodes.deref_mut(), dir_fd, &path_str, false));
{ {
let guard = inodes.arena[inode].read(); let guard = inode.read();
if let Kind::Symlink { relative_path, .. } = guard.deref() { if let Kind::Symlink { relative_path, .. } = guard.deref() {
let rel_path_str = relative_path.to_string_lossy(); let rel_path_str = relative_path.to_string_lossy();
debug!("Result => {:?}", rel_path_str); debug!("Result => {:?}", rel_path_str);

View File

@@ -15,7 +15,7 @@ pub fn path_remove_directory<M: MemorySize>(
ctx.data().tid() ctx.data().tid()
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let base_dir = wasi_try!(state.fs.get_fd(fd)); let base_dir = wasi_try!(state.fs.get_fd(fd));
let mut path_str = unsafe { get_input_str!(&memory, path, path_len) }; let mut path_str = unsafe { get_input_str!(&memory, path, path_len) };
@@ -31,18 +31,16 @@ pub fn path_remove_directory<M: MemorySize>(
); );
} }
let inode = wasi_try!(state let inode = wasi_try!(state.fs.get_inode_at_path(inodes, fd, &path_str, false));
.fs
.get_inode_at_path(inodes.deref_mut(), fd, &path_str, false));
let (parent_inode, childs_name) = wasi_try!(state.fs.get_parent_inode_at_path( let (parent_inode, childs_name) = wasi_try!(state.fs.get_parent_inode_at_path(
inodes.deref_mut(), inodes,
fd, fd,
std::path::Path::new(&path_str), std::path::Path::new(&path_str),
false false
)); ));
let host_path_to_remove = { let host_path_to_remove = {
let guard = inodes.arena[inode].read(); let guard = inode.read();
match guard.deref() { match guard.deref() {
Kind::Dir { entries, path, .. } => { Kind::Dir { entries, path, .. } => {
if !entries.is_empty() || wasi_try!(state.fs_read_dir(path)).count() != 0 { if !entries.is_empty() || wasi_try!(state.fs_read_dir(path)).count() != 0 {
@@ -56,14 +54,14 @@ pub fn path_remove_directory<M: MemorySize>(
}; };
{ {
let mut guard = inodes.arena[parent_inode].write(); let mut guard = parent_inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::Dir { Kind::Dir {
ref mut entries, .. ref mut entries, ..
} => { } => {
let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(Errno::Inval)); let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(Errno::Inval));
// TODO: make this a debug assert in the future // TODO: make this a debug assert in the future
assert!(inode == removed_inode); assert!(inode.ino() == removed_inode.ino());
} }
Kind::Root { .. } => return Errno::Access, Kind::Root { .. } => return Errno::Access,
_ => unreachable!( _ => unreachable!(
@@ -74,7 +72,7 @@ pub fn path_remove_directory<M: MemorySize>(
if let Err(err) = state.fs_remove_dir(host_path_to_remove) { if let Err(err) = state.fs_remove_dir(host_path_to_remove) {
// reinsert to prevent FS from being in bad state // reinsert to prevent FS from being in bad state
let mut guard = inodes.arena[parent_inode].write(); let mut guard = parent_inode.write();
if let Kind::Dir { if let Kind::Dir {
ref mut entries, .. ref mut entries, ..
} = guard.deref_mut() } = guard.deref_mut()

View File

@@ -30,7 +30,7 @@ pub fn path_rename<M: MemorySize>(
old_fd, new_fd old_fd, new_fd
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let mut source_str = unsafe { get_input_str!(&memory, old_path, old_path_len) }; let mut source_str = unsafe { get_input_str!(&memory, old_path, old_path_len) };
source_str = ctx.data().state.fs.relative_path_to_absolute(source_str); source_str = ctx.data().state.fs.relative_path_to_absolute(source_str);
let source_path = std::path::Path::new(&source_str); let source_path = std::path::Path::new(&source_str);
@@ -52,29 +52,27 @@ pub fn path_rename<M: MemorySize>(
// this is to be sure the source file is fetch from filesystem if needed // this is to be sure the source file is fetch from filesystem if needed
wasi_try!(state.fs.get_inode_at_path( wasi_try!(state.fs.get_inode_at_path(
inodes.deref_mut(), inodes,
old_fd, old_fd,
source_path.to_str().as_ref().unwrap(), source_path.to_str().as_ref().unwrap(),
true true
)); ));
// Create the destination inode if the file exists. // Create the destination inode if the file exists.
let _ = state.fs.get_inode_at_path( let _ =
inodes.deref_mut(), state
new_fd, .fs
target_path.to_str().as_ref().unwrap(), .get_inode_at_path(inodes, new_fd, target_path.to_str().as_ref().unwrap(), true);
true,
);
let (source_parent_inode, source_entry_name) = let (source_parent_inode, source_entry_name) =
wasi_try!(state wasi_try!(state
.fs .fs
.get_parent_inode_at_path(inodes.deref_mut(), old_fd, source_path, true)); .get_parent_inode_at_path(inodes, old_fd, source_path, true));
let (target_parent_inode, target_entry_name) = let (target_parent_inode, target_entry_name) =
wasi_try!(state wasi_try!(state
.fs .fs
.get_parent_inode_at_path(inodes.deref_mut(), new_fd, target_path, true)); .get_parent_inode_at_path(inodes, new_fd, target_path, true));
let mut need_create = true; let mut need_create = true;
let host_adjusted_target_path = { let host_adjusted_target_path = {
let guard = inodes.arena[target_parent_inode].read(); let guard = target_parent_inode.read();
match guard.deref() { match guard.deref() {
Kind::Dir { entries, path, .. } => { Kind::Dir { entries, path, .. } => {
if entries.contains_key(&target_entry_name) { if entries.contains_key(&target_entry_name) {
@@ -96,7 +94,7 @@ pub fn path_rename<M: MemorySize>(
}; };
let source_entry = { let source_entry = {
let mut guard = inodes.arena[source_parent_inode].write(); let mut guard = source_parent_inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::Dir { entries, .. } => { Kind::Dir { entries, .. } => {
wasi_try!(entries.remove(&source_entry_name).ok_or(Errno::Noent)) wasi_try!(entries.remove(&source_entry_name).ok_or(Errno::Noent))
@@ -113,7 +111,7 @@ pub fn path_rename<M: MemorySize>(
}; };
{ {
let mut guard = inodes.arena[source_entry].write(); let mut guard = source_entry.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::File { Kind::File {
handle, ref path, .. handle, ref path, ..
@@ -131,7 +129,7 @@ pub fn path_rename<M: MemorySize>(
drop(guard); drop(guard);
let out = state.fs_rename(&path_clone, &host_adjusted_target_path); let out = state.fs_rename(&path_clone, &host_adjusted_target_path);
{ {
let mut guard = inodes.arena[source_entry].write(); let mut guard = source_entry.write();
if let Kind::File { ref mut path, .. } = guard.deref_mut() { if let Kind::File { ref mut path, .. } = guard.deref_mut() {
*path = host_adjusted_target_path; *path = host_adjusted_target_path;
} else { } else {
@@ -142,7 +140,7 @@ pub fn path_rename<M: MemorySize>(
}; };
// if the above operation failed we have to revert the previous change and then fail // if the above operation failed we have to revert the previous change and then fail
if let Err(e) = result { if let Err(e) = result {
let mut guard = inodes.arena[source_parent_inode].write(); let mut guard = source_parent_inode.write();
if let Kind::Dir { entries, .. } = guard.deref_mut() { if let Kind::Dir { entries, .. } = guard.deref_mut() {
entries.insert(source_entry_name, source_entry); entries.insert(source_entry_name, source_entry);
return e; return e;
@@ -156,7 +154,7 @@ pub fn path_rename<M: MemorySize>(
} }
{ {
drop(guard); drop(guard);
let mut guard = inodes.arena[source_entry].write(); let mut guard = source_entry.write();
if let Kind::Dir { path, .. } = guard.deref_mut() { if let Kind::Dir { path, .. } = guard.deref_mut() {
*path = host_adjusted_target_path; *path = host_adjusted_target_path;
} }
@@ -172,7 +170,7 @@ pub fn path_rename<M: MemorySize>(
} }
if need_create { if need_create {
let mut guard = inodes.arena[target_parent_inode].write(); let mut guard = target_parent_inode.write();
if let Kind::Dir { entries, .. } = guard.deref_mut() { if let Kind::Dir { entries, .. } = guard.deref_mut() {
let result = entries.insert(target_entry_name, source_entry); let result = entries.insert(target_entry_name, source_entry);
assert!( assert!(

View File

@@ -28,7 +28,7 @@ pub fn path_symlink<M: MemorySize>(
ctx.data().tid() ctx.data().tid()
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let mut old_path_str = unsafe { get_input_str!(&memory, old_path, old_path_len) }; let mut old_path_str = unsafe { get_input_str!(&memory, old_path, old_path_len) };
let mut new_path_str = unsafe { get_input_str!(&memory, new_path, new_path_len) }; let mut new_path_str = unsafe { get_input_str!(&memory, new_path, new_path_len) };
old_path_str = ctx.data().state.fs.relative_path_to_absolute(old_path_str); old_path_str = ctx.data().state.fs.relative_path_to_absolute(old_path_str);
@@ -43,10 +43,8 @@ pub fn path_symlink<M: MemorySize>(
let (source_inode, _) = let (source_inode, _) =
wasi_try!(state wasi_try!(state
.fs .fs
.get_parent_inode_at_path(inodes.deref_mut(), fd, old_path_path, true)); .get_parent_inode_at_path(inodes, fd, old_path_path, true));
let depth = state let depth = state.fs.path_depth_from_fd(fd, source_inode);
.fs
.path_depth_from_fd(inodes.deref(), fd, source_inode);
// depth == -1 means folder is not relative. See issue #3233. // depth == -1 means folder is not relative. See issue #3233.
let depth = match depth { let depth = match depth {
@@ -58,11 +56,11 @@ pub fn path_symlink<M: MemorySize>(
let (target_parent_inode, entry_name) = let (target_parent_inode, entry_name) =
wasi_try!(state wasi_try!(state
.fs .fs
.get_parent_inode_at_path(inodes.deref_mut(), fd, new_path_path, true)); .get_parent_inode_at_path(inodes, fd, new_path_path, true));
// short circuit if anything is wrong, before we create an inode // short circuit if anything is wrong, before we create an inode
{ {
let guard = inodes.arena[target_parent_inode].read(); let guard = target_parent_inode.read();
match guard.deref() { match guard.deref() {
Kind::Dir { entries, .. } => { Kind::Dir { entries, .. } => {
if entries.contains_key(&entry_name) { if entries.contains_key(&entry_name) {
@@ -96,15 +94,13 @@ pub fn path_symlink<M: MemorySize>(
path_to_symlink: std::path::PathBuf::from(new_path_str), path_to_symlink: std::path::PathBuf::from(new_path_str),
relative_path, relative_path,
}; };
let new_inode = state.fs.create_inode_with_default_stat( let new_inode =
inodes.deref_mut(), state
kind, .fs
false, .create_inode_with_default_stat(inodes, kind, false, entry_name.clone().into());
entry_name.clone().into(),
);
{ {
let mut guard = inodes.arena[target_parent_inode].write(); let mut guard = target_parent_inode.write();
if let Kind::Dir { if let Kind::Dir {
ref mut entries, .. ref mut entries, ..
} = guard.deref_mut() } = guard.deref_mut()

View File

@@ -22,7 +22,7 @@ pub fn path_unlink_file<M: MemorySize>(
ctx.data().tid() ctx.data().tid()
); );
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let base_dir = wasi_try!(state.fs.get_fd(fd)); let base_dir = wasi_try!(state.fs.get_fd(fd));
if !base_dir.rights.contains(Rights::PATH_UNLINK_FILE) { if !base_dir.rights.contains(Rights::PATH_UNLINK_FILE) {
@@ -42,26 +42,24 @@ pub fn path_unlink_file<M: MemorySize>(
); );
} }
let inode = wasi_try!(state let inode = wasi_try!(state.fs.get_inode_at_path(inodes, fd, &path_str, false));
.fs
.get_inode_at_path(inodes.deref_mut(), fd, &path_str, false));
let (parent_inode, childs_name) = wasi_try!(state.fs.get_parent_inode_at_path( let (parent_inode, childs_name) = wasi_try!(state.fs.get_parent_inode_at_path(
inodes.deref_mut(), inodes,
fd, fd,
std::path::Path::new(&path_str), std::path::Path::new(&path_str),
false false
)); ));
let removed_inode = { let removed_inode = {
let mut guard = inodes.arena[parent_inode].write(); let mut guard = parent_inode.write();
match guard.deref_mut() { match guard.deref_mut() {
Kind::Dir { Kind::Dir {
ref mut entries, .. ref mut entries, ..
} => { } => {
let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(Errno::Inval)); let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(Errno::Inval));
// TODO: make this a debug assert in the future // TODO: make this a debug assert in the future
assert!(inode == removed_inode); assert!(inode.ino() == removed_inode.ino());
debug_assert!(inodes.arena[inode].stat.read().unwrap().st_nlink > 0); debug_assert!(inode.stat.read().unwrap().st_nlink > 0);
removed_inode removed_inode
} }
Kind::Root { .. } => return Errno::Access, Kind::Root { .. } => return Errno::Access,
@@ -72,13 +70,13 @@ pub fn path_unlink_file<M: MemorySize>(
}; };
let st_nlink = { let st_nlink = {
let mut guard = inodes.arena[removed_inode].stat.write().unwrap(); let mut guard = removed_inode.stat.write().unwrap();
guard.st_nlink -= 1; guard.st_nlink -= 1;
guard.st_nlink guard.st_nlink
}; };
if st_nlink == 0 { if st_nlink == 0 {
{ {
let mut guard = inodes.arena[removed_inode].read(); let mut guard = removed_inode.read();
match guard.deref() { match guard.deref() {
Kind::File { handle, path, .. } => { Kind::File { handle, path, .. } => {
if let Some(h) = handle { if let Some(h) = handle {
@@ -100,27 +98,6 @@ pub fn path_unlink_file<M: MemorySize>(
_ => unimplemented!("wasi::path_unlink_file for Buffer"), _ => unimplemented!("wasi::path_unlink_file for Buffer"),
} }
} }
// TODO: test this on Windows and actually make it portable
// make the file an orphan fd if the fd is still open
let fd_is_orphaned = {
let guard = inodes.arena[removed_inode].read();
if let Kind::File { handle, .. } = guard.deref() {
handle.is_some()
} else {
false
}
};
let removed_inode_val = unsafe { state.fs.remove_inode(inodes.deref_mut(), removed_inode) };
assert!(
removed_inode_val.is_some(),
"Inode could not be removed because it doesn't exist"
);
if fd_is_orphaned {
inodes
.orphan_fds
.insert(removed_inode, removed_inode_val.unwrap());
}
} }
Errno::Success Errno::Success

View File

@@ -1,3 +1,5 @@
use std::f32::consts::E;
use wasmer_wasi_types::wasi::SubscriptionClock; use wasmer_wasi_types::wasi::SubscriptionClock;
use super::*; use super::*;
@@ -5,6 +7,7 @@ use crate::{
fs::{InodeValFilePollGuard, InodeValFilePollGuardJoin}, fs::{InodeValFilePollGuard, InodeValFilePollGuardJoin},
state::PollEventSet, state::PollEventSet,
syscalls::*, syscalls::*,
WasiInodes,
}; };
/// ### `poll_oneoff()` /// ### `poll_oneoff()`
@@ -28,12 +31,15 @@ pub fn poll_oneoff<M: MemorySize>(
) -> Result<Errno, WasiError> { ) -> Result<Errno, WasiError> {
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?);
ctx.data_mut().poll_seed += 1;
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 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); let mut subscriptions = Vec::with_capacity(subscription_array.len() as usize);
for sub in subscription_array.iter() { for n in 0..subscription_array.len() {
let n = (n + env.poll_seed) % subscription_array.len();
let sub = subscription_array.index(n);
let s = wasi_try_mem_ok!(sub.read()); let s = wasi_try_mem_ok!(sub.read());
subscriptions.push((None, PollEventSet::default(), s)); subscriptions.push((None, PollEventSet::default(), s));
} }
@@ -97,17 +103,18 @@ 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(evt) => { Poll::Ready(e) => {
tracing::trace!( for evt in e {
"wasi[{}:{}]::poll_oneoff triggered_fd (fd={}, userdata={}, type={:?})", tracing::trace!(
pid, "wasi[{}:{}]::poll_oneoff triggered_fd (fd={}, userdata={}, type={:?})",
tid, pid,
fd, tid,
evt.userdata, fd,
evt.type_, evt.userdata,
); evt.type_,
evts.push(evt); );
done = true; evts.push(evt);
}
} }
} }
} }
@@ -247,8 +254,6 @@ pub(crate) fn poll_oneoff_internal(
let mut guards = { let mut guards = {
// We start by building a list of files we are going to poll // We start by building a list of files we are going to poll
// and open a read lock on them all // and open a read lock on them all
let inodes = state.inodes.clone();
let inodes = inodes.read().unwrap();
let mut fd_guards = Vec::with_capacity(subs.len()); let mut fd_guards = Vec::with_capacity(subs.len());
#[allow(clippy::significant_drop_in_scrutinee)] #[allow(clippy::significant_drop_in_scrutinee)]
@@ -256,20 +261,17 @@ pub(crate) fn poll_oneoff_internal(
if let Some(fd) = fd { 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!(WasiInodes::stderr(&state.fs.fd_map)
.stderr(&state.fs.fd_map)
.map(|g| g.into_poll_guard(fd, peb, s)) .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!(WasiInodes::stdin(&state.fs.fd_map)
.stdin(&state.fs.fd_map)
.map(|g| g.into_poll_guard(fd, peb, s)) .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!(WasiInodes::stdout(&state.fs.fd_map)
.stdout(&state.fs.fd_map)
.map(|g| g.into_poll_guard(fd, peb, s)) .map(|g| g.into_poll_guard(fd, peb, s))
.map_err(fs_error_into_wasi_err)) .map_err(fs_error_into_wasi_err))
} }
@@ -281,7 +283,7 @@ pub(crate) fn poll_oneoff_internal(
let inode = fd_entry.inode; let inode = fd_entry.inode;
{ {
let guard = inodes.arena[inode].read(); let guard = inode.read();
if let Some(guard) = if let Some(guard) =
crate::fs::InodeValFilePollGuard::new(fd, peb, s, guard.deref()) crate::fs::InodeValFilePollGuard::new(fd, peb, s, guard.deref())
{ {
@@ -307,12 +309,16 @@ pub(crate) fn poll_oneoff_internal(
}; };
if let Some(time_to_sleep) = time_to_sleep.as_ref() { if let Some(time_to_sleep) = time_to_sleep.as_ref() {
tracing::trace!( if *time_to_sleep == Duration::ZERO {
"wasi[{}:{}]::poll_oneoff wait_for_timeout={}", tracing::trace!("wasi[{}:{}]::poll_oneoff non_blocking", pid, tid,);
pid, } else {
tid, tracing::trace!(
time_to_sleep.as_millis() "wasi[{}:{}]::poll_oneoff wait_for_timeout={}",
); pid,
tid,
time_to_sleep.as_millis()
);
}
} else { } else {
tracing::trace!("wasi[{}:{}]::poll_oneoff wait_for_infinite", pid, tid,); tracing::trace!("wasi[{}:{}]::poll_oneoff wait_for_infinite", pid, tid,);
} }

View File

@@ -75,11 +75,9 @@ pub fn bus_poll<M: MemorySize>(
// Function that turns a buffer into a readable file handle // Function that turns a buffer into a readable file handle
let buf_to_fd = { let buf_to_fd = {
let state = env.state.clone(); let state = env.state.clone();
let inodes = state.inodes.clone();
move |data: Vec<u8>| -> Result<WasiFd, BusErrno> { move |data: Vec<u8>| -> Result<WasiFd, BusErrno> {
let mut inodes = inodes.write().unwrap();
let inode = state.fs.create_inode_with_default_stat( let inode = state.fs.create_inode_with_default_stat(
inodes.deref_mut(), &state.inodes,
Kind::Buffer { buffer: data }, Kind::Buffer { buffer: data },
false, false,
"bus".into(), "bus".into(),

View File

@@ -16,20 +16,20 @@ pub fn fd_pipe<M: MemorySize>(
trace!("wasi[{}:{}]::fd_pipe", ctx.data().pid(), ctx.data().tid()); trace!("wasi[{}:{}]::fd_pipe", ctx.data().pid(), ctx.data().tid());
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, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let pipes = WasiBidirectionalPipePair::new(); let pipes = WasiBidirectionalPipePair::new();
let pipe1 = pipes.tx; let pipe1 = pipes.tx;
let pipe2 = pipes.rx; let pipe2 = pipes.rx;
let inode1 = state.fs.create_inode_with_default_stat( let inode1 = state.fs.create_inode_with_default_stat(
inodes.deref_mut(), inodes,
Kind::Pipe { pipe: pipe1 }, Kind::Pipe { pipe: pipe1 },
false, false,
"pipe".to_string().into(), "pipe".to_string().into(),
); );
let inode2 = state.fs.create_inode_with_default_stat( let inode2 = state.fs.create_inode_with_default_stat(
inodes.deref_mut(), inodes,
Kind::Pipe { pipe: pipe2 }, Kind::Pipe { pipe: pipe2 },
false, false,
"pipe".to_string().into(), "pipe".to_string().into(),

View File

@@ -12,11 +12,9 @@ pub fn getcwd<M: MemorySize>(
) -> Errno { ) -> Errno {
debug!("wasi[{}:{}]::getcwd", ctx.data().pid(), ctx.data().tid()); debug!("wasi[{}:{}]::getcwd", ctx.data().pid(), ctx.data().tid());
let env = ctx.data(); let env = ctx.data();
let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let (_, cur_dir) = wasi_try!(state let (_, cur_dir) = wasi_try!(state.fs.get_current_dir(inodes, crate::VIRTUAL_ROOT_FD,));
.fs
.get_current_dir(inodes.deref_mut(), crate::VIRTUAL_ROOT_FD,));
trace!( trace!(
"wasi[{}:{}]::getcwd(current_dir={})", "wasi[{}:{}]::getcwd(current_dir={})",
ctx.data().pid(), ctx.data().pid(),

View File

@@ -57,12 +57,8 @@ pub fn proc_exec<M: MemorySize>(
// Get the current working directory // Get the current working directory
let (_, cur_dir) = { let (_, cur_dir) = {
let (memory, state, mut inodes) = let (memory, state, inodes) = ctx.data().get_memory_and_wasi_state_and_inodes(&ctx, 0);
ctx.data().get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); match state.fs.get_current_dir(inodes, crate::VIRTUAL_ROOT_FD) {
match state
.fs
.get_current_dir(inodes.deref_mut(), crate::VIRTUAL_ROOT_FD)
{
Ok(a) => a, Ok(a) => a,
Err(err) => { Err(err) => {
warn!("failed to create subprocess for fork - {}", err); warn!("failed to create subprocess for fork - {}", err);

View File

@@ -117,7 +117,7 @@ pub fn proc_spawn_internal(
} }
}; };
if let Some(args) = args { if let Some(args) = args {
let mut child_state = env.state.fork(true); let mut child_state = env.state.fork();
child_state.args = args; child_state.args = args;
child_env.state = Arc::new(child_state); child_env.state = Arc::new(child_state);
} }
@@ -148,8 +148,8 @@ pub fn proc_spawn_internal(
// Replace the STDIO // Replace the STDIO
let (stdin, stdout, stderr) = { let (stdin, stdout, stderr) = {
let (_, child_state, mut child_inodes) = let (_, child_state, child_inodes) =
child_env.get_memory_and_wasi_state_and_inodes_mut(&new_store, 0); child_env.get_memory_and_wasi_state_and_inodes(&new_store, 0);
let mut conv_stdio_mode = |mode: WasiStdioMode, fd: WasiFd| -> Result<OptionFd, BusErrno> { let mut conv_stdio_mode = |mode: WasiStdioMode, fd: WasiFd| -> Result<OptionFd, BusErrno> {
match mode { match mode {
WasiStdioMode::Piped => { WasiStdioMode::Piped => {
@@ -157,13 +157,13 @@ pub fn proc_spawn_internal(
let pipe1 = pipes.rx; let pipe1 = pipes.rx;
let pipe2 = pipes.tx; let pipe2 = pipes.tx;
let inode1 = child_state.fs.create_inode_with_default_stat( let inode1 = child_state.fs.create_inode_with_default_stat(
child_inodes.deref_mut(), child_inodes,
Kind::Pipe { pipe: pipe1 }, Kind::Pipe { pipe: pipe1 },
false, false,
"pipe".into(), "pipe".into(),
); );
let inode2 = child_state.fs.create_inode_with_default_stat( let inode2 = child_state.fs.create_inode_with_default_stat(
child_inodes.deref_mut(), child_inodes,
Kind::Pipe { pipe: pipe2 }, Kind::Pipe { pipe: pipe2 },
false, false,
"pipe".into(), "pipe".into(),
@@ -198,7 +198,7 @@ pub fn proc_spawn_internal(
fd: u32::MAX, fd: u32::MAX,
}), }),
_ => { _ => {
child_state.fs.close_fd(child_inodes.deref(), fd); child_state.fs.close_fd(fd);
Ok(OptionFd { Ok(OptionFd {
tag: OptionTag::None, tag: OptionTag::None,
fd: u32::MAX, fd: u32::MAX,

View File

@@ -47,7 +47,7 @@ pub fn sock_accept<M: MemorySize>(
)); ));
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, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let kind = Kind::Socket { let kind = Kind::Socket {
socket: InodeSocket::new(InodeSocketKind::TcpStream { socket: InodeSocket::new(InodeSocketKind::TcpStream {
@@ -56,10 +56,9 @@ pub fn sock_accept<M: MemorySize>(
read_timeout: None, read_timeout: None,
}), }),
}; };
let inode = let inode = state
state .fs
.fs .create_inode_with_default_stat(inodes, kind, false, "socket".into());
.create_inode_with_default_stat(inodes.deref_mut(), kind, false, "socket".into());
let mut new_flags = Fdflags::empty(); let mut new_flags = Fdflags::empty();
if fd_flags.contains(Fdflags::NONBLOCK) { if fd_flags.contains(Fdflags::NONBLOCK) {

View File

@@ -30,7 +30,7 @@ pub fn sock_open<M: MemorySize>(
debug!("wasi[{}:{}]::sock_open", ctx.data().pid(), ctx.data().tid()); debug!("wasi[{}:{}]::sock_open", ctx.data().pid(), ctx.data().tid());
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, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let kind = match ty { let kind = match ty {
Socktype::Stream | Socktype::Dgram => Kind::Socket { Socktype::Stream | Socktype::Dgram => Kind::Socket {
@@ -53,12 +53,10 @@ pub fn sock_open<M: MemorySize>(
_ => return Errno::Notsup, _ => return Errno::Notsup,
}; };
let inode = state.fs.create_inode_with_default_stat( let inode =
inodes.deref_mut(), state
kind, .fs
false, .create_inode_with_default_stat(inodes, kind, false, "socket".to_string().into());
"socket".to_string().into(),
);
let rights = Rights::all_socket(); let rights = Rights::all_socket();
let fd = wasi_try!(state let fd = wasi_try!(state
.fs .fs

View File

@@ -25,27 +25,101 @@ pub fn sock_recv<M: MemorySize>(
ro_data_len: WasmPtr<M::Offset, M>, ro_data_len: WasmPtr<M::Offset, M>,
ro_flags: WasmPtr<RoFlags, M>, ro_flags: WasmPtr<RoFlags, M>,
) -> Result<Errno, WasiError> { ) -> Result<Errno, WasiError> {
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); let pid = ctx.data().pid();
let tid = ctx.data().tid();
let res = sock_recv_internal::<M>(
&mut ctx,
sock,
ri_data,
ri_data_len,
ri_flags,
ro_data_len,
ro_flags,
)?;
let mut ret = Errno::Success;
let bytes_read = match res {
Ok(bytes_read) => {
debug!(
%bytes_read,
"wasi[{}:{}]::sock_recv (fd={}, flags={:?})",
ctx.data().pid(),
ctx.data().tid(),
sock,
ri_flags
);
bytes_read
}
Err(err) => {
let socket_err = err.name();
debug!(
%socket_err,
"wasi[{}:{}]::sock_recv (fd={}, flags={:?})",
ctx.data().pid(),
ctx.data().tid(),
sock,
ri_flags
);
ret = err;
0
}
};
let env = ctx.data();
let memory = env.memory_view(&ctx);
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_data_len.write(&memory, bytes_read));
Ok(ret)
}
/// ### `sock_recv()`
/// Receive a message from a socket.
/// Note: This is similar to `recv` in POSIX, though it also supports reading
/// the data into multiple buffers in the manner of `readv`.
///
/// ## Parameters
///
/// * `ri_data` - List of scatter/gather vectors to which to store data.
/// * `ri_flags` - Message flags.
///
/// ## Return
///
/// Number of bytes stored in ri_data and message flags.
fn sock_recv_internal<M: MemorySize>(
ctx: &mut FunctionEnvMut<'_, WasiEnv>,
sock: WasiFd,
ri_data: WasmPtr<__wasi_iovec_t<M>, M>,
ri_data_len: M::Offset,
ri_flags: RiFlags,
ro_data_len: WasmPtr<M::Offset, M>,
ro_flags: WasmPtr<RoFlags, M>,
) -> Result<Result<usize, Errno>, WasiError> {
wasi_try_ok_ok!(WasiEnv::process_signals_and_exit(ctx)?);
let mut env = ctx.data(); let mut env = ctx.data();
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_ok!(ri_data.slice(&memory, ri_data_len));
let max_size = { 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_ok!(iovs.read());
let buf_len: usize = wasi_try_ok!(iovs.buf_len.try_into().map_err(|_| Errno::Overflow)); let buf_len: usize =
wasi_try_ok_ok!(iovs.buf_len.try_into().map_err(|_| Errno::Overflow));
max_size += buf_len; max_size += buf_len;
} }
max_size max_size
}; };
let bytes_read = { let res = {
if max_size <= 10240 { if max_size <= 10240 {
let mut buf: [MaybeUninit<u8>; 10240] = unsafe { MaybeUninit::uninit().assume_init() }; let mut buf: [MaybeUninit<u8>; 10240] = unsafe { MaybeUninit::uninit().assume_init() };
let writer = &mut buf[..max_size]; let writer = &mut buf[..max_size];
let amt = wasi_try_ok!(__sock_asyncify( let amt = wasi_try_ok_ok!(__sock_asyncify(
env, env,
sock, sock,
Rights::SOCK_RECV, Rights::SOCK_RECV,
@@ -55,12 +129,12 @@ pub fn sock_recv<M: MemorySize>(
if amt > 0 { if amt > 0 {
let buf: &[MaybeUninit<u8>] = &buf[..amt]; let buf: &[MaybeUninit<u8>] = &buf[..amt];
let buf: &[u8] = unsafe { std::mem::transmute(buf) }; let buf: &[u8] = unsafe { std::mem::transmute(buf) };
wasi_try_ok!(copy_from_slice(buf, &memory, iovs_arr).map(|_| amt)) copy_from_slice(buf, &memory, iovs_arr).map(|_| amt)
} else { } else {
0 Ok(0)
} }
} else { } else {
let data = wasi_try_ok!(__sock_asyncify( let data = wasi_try_ok_ok!(__sock_asyncify(
env, env,
sock, sock,
Rights::SOCK_RECV, Rights::SOCK_RECV,
@@ -85,25 +159,12 @@ pub fn sock_recv<M: MemorySize>(
let data_len = data.len(); let data_len = data.len();
if data_len > 0 { if data_len > 0 {
let mut reader = &data[..]; let mut reader = &data[..];
wasi_try_ok!(read_bytes(reader, &memory, iovs_arr).map(|_| data_len)) read_bytes(reader, &memory, iovs_arr).map(|_| data_len)
} else { } else {
0 Ok(0)
} }
} }
}; };
debug!( Ok(res)
"wasi[{}:{}]::sock_recv (fd={}, read={}, flags={:?})",
ctx.data().pid(),
ctx.data().tid(),
sock,
bytes_read,
ri_flags
);
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_data_len.write(&memory, bytes_read));
Ok(Errno::Success)
} }

View File

@@ -36,17 +36,9 @@ pub fn sock_send<M: MemorySize>(
.map(|a| a.buf_len) .map(|a| a.buf_len)
.sum() .sum()
}; };
debug!( let buf_len: usize = wasi_try_ok!(buf_len.try_into().map_err(|_| Errno::Overflow));
"wasi[{}:{}]::sock_send (fd={}, buf_len={}, flags={:?})",
ctx.data().pid(),
ctx.data().tid(),
sock,
buf_len,
si_flags
);
let buf_len: usize = wasi_try_ok!(buf_len.try_into().map_err(|_| Errno::Inval));
let bytes_written = { let res = {
if buf_len <= 10240 { if buf_len <= 10240 {
let mut buf: [MaybeUninit<u8>; 10240] = unsafe { MaybeUninit::uninit().assume_init() }; let mut buf: [MaybeUninit<u8>; 10240] = unsafe { MaybeUninit::uninit().assume_init() };
let writer = &mut buf[..buf_len]; let writer = &mut buf[..buf_len];
@@ -55,23 +47,47 @@ pub fn sock_send<M: MemorySize>(
let reader = &buf[..written]; let reader = &buf[..written];
let reader: &[u8] = unsafe { std::mem::transmute(reader) }; let reader: &[u8] = unsafe { std::mem::transmute(reader) };
wasi_try_ok!(__sock_asyncify( __sock_asyncify(env, sock, Rights::SOCK_SEND, |socket, fd| async move {
env, socket.send(env.tasks.deref(), reader, fd.flags).await
sock, })
Rights::SOCK_SEND,
|socket, fd| async move { socket.send(env.tasks.deref(), reader, fd.flags).await },
))
} else { } else {
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 reader = &buf; let reader = &buf;
wasi_try_ok!(__sock_asyncify( __sock_asyncify(env, sock, Rights::SOCK_SEND, |socket, fd| async move {
env, socket.send(env.tasks.deref(), reader, fd.flags).await
})
}
};
let mut ret = Errno::Success;
let bytes_written = match res {
Ok(bytes_written) => {
debug!(
%bytes_written,
"wasi[{}:{}]::sock_send (fd={}, buf_len={}, flags={:?})",
ctx.data().pid(),
ctx.data().tid(),
sock, sock,
Rights::SOCK_SEND, buf_len,
|socket, fd| async move { socket.send(env.tasks.deref(), reader, fd.flags).await }, si_flags
)) );
bytes_written
}
Err(err) => {
let socket_err = err.name();
debug!(
%socket_err,
"wasi[{}:{}]::sock_send (fd={}, buf_len={}, flags={:?})",
ctx.data().pid(),
ctx.data().tid(),
sock,
buf_len,
si_flags
);
ret = err;
0
} }
}; };
@@ -79,5 +95,5 @@ pub fn sock_send<M: MemorySize>(
wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow)); wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow));
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(ret)
} }

View File

@@ -1,7 +1,7 @@
use wasmer_vfs::AsyncReadExt; use wasmer_vfs::AsyncReadExt;
use super::*; use super::*;
use crate::syscalls::*; use crate::{syscalls::*, WasiInodes};
/// ### `sock_send_file()` /// ### `sock_send_file()`
/// Sends the entire contents of a file down a socket /// Sends the entire contents of a file down a socket
@@ -56,13 +56,11 @@ pub fn sock_send_file<M: MemorySize>(
let fd_flags = fd_entry.flags; let fd_flags = fd_entry.flags;
let data = { let data = {
let inodes = env.state.inodes.clone();
match in_fd { match in_fd {
__WASI_STDIN_FILENO => { __WASI_STDIN_FILENO => {
let inodes = inodes.read().unwrap(); let mut stdin =
let mut stdin = wasi_try_ok!(inodes wasi_try_ok!(WasiInodes::stdin_mut(&state.fs.fd_map)
.stdin_mut(&state.fs.fd_map) .map_err(fs_error_into_wasi_err));
.map_err(fs_error_into_wasi_err));
let data = wasi_try_ok!(__asyncify(&mut ctx, None, async move { let data = wasi_try_ok!(__asyncify(&mut ctx, None, async move {
// TODO: optimize with MaybeUninit // TODO: optimize with MaybeUninit
let mut buf = vec![0u8; sub_count as usize]; let mut buf = vec![0u8; sub_count as usize];
@@ -81,10 +79,7 @@ pub fn sock_send_file<M: MemorySize>(
} }
let offset = fd_entry.offset.load(Ordering::Acquire) as usize; let offset = fd_entry.offset.load(Ordering::Acquire) as usize;
let inode_idx = fd_entry.inode; let inode = fd_entry.inode;
let inodes = inodes.read().unwrap();
let inode = &inodes.arena[inode_idx];
let data = { let data = {
let mut guard = inode.write(); let mut guard = inode.write();
match guard.deref_mut() { match guard.deref_mut() {
@@ -116,7 +111,6 @@ pub fn sock_send_file<M: MemorySize>(
let socket = socket.clone(); let socket = socket.clone();
let tasks = tasks.clone(); let tasks = tasks.clone();
drop(guard); drop(guard);
drop(inodes);
let data = wasi_try_ok!(__asyncify(&mut ctx, None, async { let data = wasi_try_ok!(__asyncify(&mut ctx, None, async {
let mut buf = Vec::with_capacity(sub_count as usize); let mut buf = Vec::with_capacity(sub_count as usize);

View File

@@ -144,13 +144,35 @@ pub fn thread_spawn<M: MemorySize>(
let mut ret = Errno::Success; let mut ret = Errno::Success;
if let Err(err) = spawn.call(store, user_data_low as i32, user_data_high as i32) { if let Err(err) = spawn.call(store, user_data_low as i32, user_data_high as i32) {
debug!( match err.downcast::<WasiError>() {
"wasi[{}:{}]::thread_spawn - thread failed - start: {}", Ok(WasiError::Exit(0)) => ret = Errno::Success,
ctx.data(&store).pid(), Ok(WasiError::Exit(code)) => {
ctx.data(&store).tid(), debug!(
err %code,
); "wasi[{}:{}]::thread_spawn - thread exited",
ret = Errno::Noexec; ctx.data(&store).pid(),
ctx.data(&store).tid(),
);
ret = Errno::Noexec;
}
Ok(WasiError::UnknownWasiVersion) => {
debug!(
"wasi[{}:{}]::thread_spawn - thread failed as wasi version is unknown",
ctx.data(&store).pid(),
ctx.data(&store).tid(),
);
ret = Errno::Noexec;
}
Err(err) => {
debug!(
"wasi[{}:{}]::thread_spawn - thread failed with runtime error: {}",
ctx.data(&store).pid(),
ctx.data(&store).tid(),
err
);
ret = Errno::Noexec;
}
}
} }
trace!( trace!(
"wasi[{}:{}]::thread_spawn - thread callback finished (reactor={:?}, ret={})", "wasi[{}:{}]::thread_spawn - thread callback finished (reactor={:?}, ret={})",

View File

@@ -35,16 +35,15 @@ pub fn ws_connect<M: MemorySize>(
})?); })?);
env = ctx.data(); env = ctx.data();
let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0);
let kind = Kind::Socket { let kind = Kind::Socket {
socket: InodeSocket::new(InodeSocketKind::WebSocket(socket)), socket: InodeSocket::new(InodeSocketKind::WebSocket(socket)),
}; };
let inode = let inode = state
state .fs
.fs .create_inode_with_default_stat(inodes, kind, false, "socket".into());
.create_inode_with_default_stat(inodes.deref_mut(), kind, false, "socket".into());
let rights = Rights::all_socket(); let rights = Rights::all_socket();
let fd = wasi_try_ok!(state let fd = wasi_try_ok!(state
.fs .fs