diff --git a/crates/wasi-common/cap-std-sync/src/file.rs b/crates/wasi-common/cap-std-sync/src/file.rs index 8fe395fdaf8b..c54a5ead7145 100644 --- a/crates/wasi-common/cap-std-sync/src/file.rs +++ b/crates/wasi-common/cap-std-sync/src/file.rs @@ -5,6 +5,7 @@ use is_terminal::IsTerminal; use std::any::Any; use std::convert::TryInto; use std::io; +use std::sync::{Arc, RwLock, RwLockReadGuard}; use system_interface::{ fs::{FileIoExt, GetSetFdFlags}, io::{IoExt, ReadReady}, @@ -14,11 +15,48 @@ use wasi_common::{ Error, ErrorExt, }; -pub struct File(cap_std::fs::File); +#[cfg(unix)] +use io_lifetimes::{AsFd, BorrowedFd}; + +#[cfg(windows)] +use io_lifetimes::{AsHandle, BorrowedHandle}; + +#[cfg(windows)] +use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket}; + +pub struct BorrowedFile<'a>(RwLockReadGuard<'a, cap_std::fs::File>); + +#[cfg(unix)] +impl AsFd for BorrowedFile<'_> { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +#[cfg(windows)] +impl AsHandle for BorrowedFile<'_> { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.0.as_handle() + } +} + +#[cfg(windows)] +impl AsRawHandleOrSocket for BorrowedFile<'_> { + #[inline] + fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { + self.0.as_raw_handle_or_socket() + } +} + +pub struct File(RwLock); impl File { pub fn from_cap_std(file: cap_std::fs::File) -> Self { - File(file) + File(RwLock::new(file)) + } + + pub fn borrow(&self) -> BorrowedFile { + BorrowedFile(self.0.read().unwrap()) } } @@ -27,32 +65,35 @@ impl WasiFile for File { fn as_any(&self) -> &dyn Any { self } + #[cfg(unix)] - fn pollable(&self) -> Option { - Some(self.0.as_fd()) + fn pollable(&self) -> Option> { + Some(Arc::new(self.borrow())) } #[cfg(windows)] - fn pollable(&self) -> Option { - Some(self.0.as_raw_handle_or_socket()) + fn pollable(&self) -> Option> { + Some(Arc::new(BorrowedFile(self.0.read().unwrap()))) } - async fn datasync(&mut self) -> Result<(), Error> { - self.0.sync_data()?; + + async fn datasync(&self) -> Result<(), Error> { + self.0.read().unwrap().sync_data()?; Ok(()) } - async fn sync(&mut self) -> Result<(), Error> { - self.0.sync_all()?; + async fn sync(&self) -> Result<(), Error> { + self.0.read().unwrap().sync_all()?; Ok(()) } - async fn get_filetype(&mut self) -> Result { - let meta = self.0.metadata()?; + async fn get_filetype(&self) -> Result { + let meta = self.0.read().unwrap().metadata()?; Ok(filetype_from(&meta.file_type())) } - async fn get_fdflags(&mut self) -> Result { - let fdflags = get_fd_flags(&self.0)?; + async fn get_fdflags(&self) -> Result { + let file = self.0.read().unwrap(); + let fdflags = get_fd_flags(&*file)?; Ok(fdflags) } - async fn set_fdflags(&mut self, fdflags: FdFlags) -> Result<(), Error> { + async fn set_fdflags(&self, fdflags: FdFlags) -> Result<(), Error> { if fdflags.intersects( wasi_common::file::FdFlags::DSYNC | wasi_common::file::FdFlags::SYNC @@ -60,12 +101,13 @@ impl WasiFile for File { ) { return Err(Error::invalid_argument().context("cannot set DSYNC, SYNC, or RSYNC flag")); } - let set_fd_flags = self.0.new_set_fd_flags(to_sysif_fdflags(fdflags))?; - self.0.set_fd_flags(set_fd_flags)?; + let mut file = self.0.write().unwrap(); + let set_fd_flags = (*file).new_set_fd_flags(to_sysif_fdflags(fdflags))?; + (*file).set_fd_flags(set_fd_flags)?; Ok(()) } - async fn get_filestat(&mut self) -> Result { - let meta = self.0.metadata()?; + async fn get_filestat(&self) -> Result { + let meta = self.0.read().unwrap().metadata()?; Ok(Filestat { device_id: meta.dev(), inode: meta.ino(), @@ -77,63 +119,68 @@ impl WasiFile for File { ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None), }) } - async fn set_filestat_size(&mut self, size: u64) -> Result<(), Error> { - self.0.set_len(size)?; + async fn set_filestat_size(&self, size: u64) -> Result<(), Error> { + self.0.read().unwrap().set_len(size)?; Ok(()) } - async fn advise(&mut self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> { - self.0.advise(offset, len, convert_advice(advice))?; + async fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> { + self.0 + .read() + .unwrap() + .advise(offset, len, convert_advice(advice))?; Ok(()) } - async fn allocate(&mut self, offset: u64, len: u64) -> Result<(), Error> { - self.0.allocate(offset, len)?; + async fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> { + self.0.read().unwrap().allocate(offset, len)?; Ok(()) } async fn set_times( - &mut self, + &self, atime: Option, mtime: Option, ) -> Result<(), Error> { self.0 + .read() + .unwrap() .set_times(convert_systimespec(atime), convert_systimespec(mtime))?; Ok(()) } - async fn read_vectored<'a>(&mut self, bufs: &mut [io::IoSliceMut<'a>]) -> Result { - let n = self.0.read_vectored(bufs)?; + async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result { + let n = self.0.read().unwrap().read_vectored(bufs)?; Ok(n.try_into()?) } async fn read_vectored_at<'a>( - &mut self, + &self, bufs: &mut [io::IoSliceMut<'a>], offset: u64, ) -> Result { - let n = self.0.read_vectored_at(bufs, offset)?; + let n = self.0.read().unwrap().read_vectored_at(bufs, offset)?; Ok(n.try_into()?) } - async fn write_vectored<'a>(&mut self, bufs: &[io::IoSlice<'a>]) -> Result { - let n = self.0.write_vectored(bufs)?; + async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result { + let n = self.0.read().unwrap().write_vectored(bufs)?; Ok(n.try_into()?) } async fn write_vectored_at<'a>( - &mut self, + &self, bufs: &[io::IoSlice<'a>], offset: u64, ) -> Result { - let n = self.0.write_vectored_at(bufs, offset)?; + let n = self.0.read().unwrap().write_vectored_at(bufs, offset)?; Ok(n.try_into()?) } - async fn seek(&mut self, pos: std::io::SeekFrom) -> Result { - Ok(self.0.seek(pos)?) + async fn seek(&self, pos: std::io::SeekFrom) -> Result { + Ok(self.0.read().unwrap().seek(pos)?) } - async fn peek(&mut self, buf: &mut [u8]) -> Result { - let n = self.0.peek(buf)?; + async fn peek(&self, buf: &mut [u8]) -> Result { + let n = self.0.read().unwrap().peek(buf)?; Ok(n.try_into()?) } - async fn num_ready_bytes(&self) -> Result { - Ok(self.0.num_ready_bytes()?) + fn num_ready_bytes(&self) -> Result { + Ok(self.0.read().unwrap().num_ready_bytes()?) } - fn isatty(&mut self) -> bool { - self.0.is_terminal() + fn isatty(&self) -> bool { + self.0.read().unwrap().is_terminal() } } @@ -160,35 +207,6 @@ pub fn filetype_from(ft: &cap_std::fs::FileType) -> FileType { } } -#[cfg(windows)] -use io_lifetimes::{AsHandle, BorrowedHandle}; -#[cfg(windows)] -impl AsHandle for File { - fn as_handle(&self) -> BorrowedHandle<'_> { - self.0.as_handle() - } -} - -#[cfg(windows)] -use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket}; -#[cfg(windows)] -impl AsRawHandleOrSocket for File { - #[inline] - fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { - self.0.as_raw_handle_or_socket() - } -} - -#[cfg(unix)] -use io_lifetimes::{AsFd, BorrowedFd}; - -#[cfg(unix)] -impl AsFd for File { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} - pub(crate) fn convert_systimespec( t: Option, ) -> Option { diff --git a/crates/wasi-common/cap-std-sync/src/lib.rs b/crates/wasi-common/cap-std-sync/src/lib.rs index 12f27bcec885..fbaa7bbbd9d9 100644 --- a/crates/wasi-common/cap-std-sync/src/lib.rs +++ b/crates/wasi-common/cap-std-sync/src/lib.rs @@ -94,15 +94,15 @@ impl WasiCtxBuilder { } Ok(self) } - pub fn stdin(mut self, f: Box) -> Self { + pub fn stdin(self, f: Box) -> Self { self.0.set_stdin(f); self } - pub fn stdout(mut self, f: Box) -> Self { + pub fn stdout(self, f: Box) -> Self { self.0.set_stdout(f); self } - pub fn stderr(mut self, f: Box) -> Self { + pub fn stderr(self, f: Box) -> Self { self.0.set_stderr(f); self } @@ -118,12 +118,12 @@ impl WasiCtxBuilder { pub fn inherit_stdio(self) -> Self { self.inherit_stdin().inherit_stdout().inherit_stderr() } - pub fn preopened_dir(mut self, dir: Dir, guest_path: impl AsRef) -> Result { + pub fn preopened_dir(self, dir: Dir, guest_path: impl AsRef) -> Result { let dir = Box::new(crate::dir::Dir::from_cap_std(dir)); self.0.push_preopened_dir(dir, guest_path)?; Ok(self) } - pub fn preopened_socket(mut self, fd: u32, socket: impl Into) -> Result { + pub fn preopened_socket(self, fd: u32, socket: impl Into) -> Result { let socket: Socket = socket.into(); let file: Box = socket.into(); diff --git a/crates/wasi-common/cap-std-sync/src/net.rs b/crates/wasi-common/cap-std-sync/src/net.rs index bdbf507fe48a..b46d8d7dafaf 100644 --- a/crates/wasi-common/cap-std-sync/src/net.rs +++ b/crates/wasi-common/cap-std-sync/src/net.rs @@ -8,6 +8,7 @@ use io_lifetimes::{AsSocket, BorrowedSocket}; use std::any::Any; use std::convert::TryInto; use std::io; +use std::sync::Arc; #[cfg(unix)] use system_interface::fs::GetSetFdFlags; use system_interface::io::IoExt; @@ -18,6 +19,11 @@ use wasi_common::{ Error, ErrorExt, }; +#[cfg(unix)] +use wasi_common::file::BorrowedAsFd; +#[cfg(windows)] +use wasi_common::file::BorrowedAsRawHandleOrSocket; + pub enum Socket { TcpListener(cap_std::net::TcpListener), TcpStream(cap_std::net::TcpStream), @@ -83,29 +89,28 @@ macro_rules! wasi_listen_write_impl { self } #[cfg(unix)] - fn pollable(&self) -> Option { - Some(self.0.as_fd()) + fn pollable(&self) -> Option> { + Some(Arc::new(BorrowedAsFd::new(&self.0))) } - #[cfg(windows)] - fn pollable(&self) -> Option { - Some(self.0.as_raw_handle_or_socket()) + fn pollable(&self) -> Option> { + Some(Arc::new(BorrowedAsRawHandleOrSocket::new(&self.0))) } - async fn sock_accept(&mut self, fdflags: FdFlags) -> Result, Error> { + async fn sock_accept(&self, fdflags: FdFlags) -> Result, Error> { let (stream, _) = self.0.accept()?; - let mut stream = <$stream>::from_cap_std(stream); + let stream = <$stream>::from_cap_std(stream); stream.set_fdflags(fdflags).await?; Ok(Box::new(stream)) } - async fn get_filetype(&mut self) -> Result { + async fn get_filetype(&self) -> Result { Ok(FileType::SocketStream) } #[cfg(unix)] - async fn get_fdflags(&mut self) -> Result { + async fn get_fdflags(&self) -> Result { let fdflags = get_fd_flags(&self.0)?; Ok(fdflags) } - async fn set_fdflags(&mut self, fdflags: FdFlags) -> Result<(), Error> { + async fn set_fdflags(&self, fdflags: FdFlags) -> Result<(), Error> { if fdflags == wasi_common::file::FdFlags::NONBLOCK { self.0.set_nonblocking(true)?; } else if fdflags.is_empty() { @@ -117,7 +122,7 @@ macro_rules! wasi_listen_write_impl { } Ok(()) } - async fn num_ready_bytes(&self) -> Result { + fn num_ready_bytes(&self) -> Result { Ok(1) } } @@ -177,23 +182,22 @@ macro_rules! wasi_stream_write_impl { self } #[cfg(unix)] - fn pollable(&self) -> Option { - Some(self.0.as_fd()) + fn pollable(&self) -> Option> { + Some(Arc::new(BorrowedAsFd::new(&self.0))) } - #[cfg(windows)] - fn pollable(&self) -> Option { - Some(self.0.as_raw_handle_or_socket()) + fn pollable(&self) -> Option> { + Some(Arc::new(BorrowedAsRawHandleOrSocket::new(&self.0))) } - async fn get_filetype(&mut self) -> Result { + async fn get_filetype(&self) -> Result { Ok(FileType::SocketStream) } #[cfg(unix)] - async fn get_fdflags(&mut self) -> Result { + async fn get_fdflags(&self) -> Result { let fdflags = get_fd_flags(&self.0)?; Ok(fdflags) } - async fn set_fdflags(&mut self, fdflags: FdFlags) -> Result<(), Error> { + async fn set_fdflags(&self, fdflags: FdFlags) -> Result<(), Error> { if fdflags == wasi_common::file::FdFlags::NONBLOCK { self.0.set_nonblocking(true)?; } else if fdflags.is_empty() { @@ -206,23 +210,23 @@ macro_rules! wasi_stream_write_impl { Ok(()) } async fn read_vectored<'a>( - &mut self, + &self, bufs: &mut [io::IoSliceMut<'a>], ) -> Result { use std::io::Read; let n = Read::read_vectored(&mut &*self.as_socketlike_view::<$std_ty>(), bufs)?; Ok(n.try_into()?) } - async fn write_vectored<'a>(&mut self, bufs: &[io::IoSlice<'a>]) -> Result { + async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result { use std::io::Write; let n = Write::write_vectored(&mut &*self.as_socketlike_view::<$std_ty>(), bufs)?; Ok(n.try_into()?) } - async fn peek(&mut self, buf: &mut [u8]) -> Result { + async fn peek(&self, buf: &mut [u8]) -> Result { let n = self.0.peek(buf)?; Ok(n.try_into()?) } - async fn num_ready_bytes(&self) -> Result { + fn num_ready_bytes(&self) -> Result { let val = self.as_socketlike_view::<$std_ty>().num_ready_bytes()?; Ok(val) } @@ -244,7 +248,7 @@ macro_rules! wasi_stream_write_impl { } async fn sock_recv<'a>( - &mut self, + &self, ri_data: &mut [std::io::IoSliceMut<'a>], ri_flags: RiFlags, ) -> Result<(u64, RoFlags), Error> { @@ -272,7 +276,7 @@ macro_rules! wasi_stream_write_impl { } async fn sock_send<'a>( - &mut self, + &self, si_data: &[std::io::IoSlice<'a>], si_flags: SiFlags, ) -> Result { @@ -284,7 +288,7 @@ macro_rules! wasi_stream_write_impl { Ok(n as u64) } - async fn sock_shutdown(&mut self, how: SdFlags) -> Result<(), Error> { + async fn sock_shutdown(&self, how: SdFlags) -> Result<(), Error> { let how = if how == SdFlags::RD | SdFlags::WR { cap_std::net::Shutdown::Both } else if how == SdFlags::RD { diff --git a/crates/wasi-common/cap-std-sync/src/sched/unix.rs b/crates/wasi-common/cap-std-sync/src/sched/unix.rs index c53acf1a29f8..000299e2721b 100644 --- a/crates/wasi-common/cap-std-sync/src/sched/unix.rs +++ b/crates/wasi-common/cap-std-sync/src/sched/unix.rs @@ -8,7 +8,7 @@ pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> { if poll.is_empty() { return Ok(()); } - let mut pollfds = Vec::new(); + let mut poll_as_fds = Vec::new(); for s in poll.rw_subscriptions() { match s { Subscription::Read(f) => { @@ -16,7 +16,7 @@ pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> { .file .pollable() .ok_or(Error::invalid_argument().context("file is not pollable"))?; - pollfds.push(PollFd::from_borrowed_fd(fd, PollFlags::IN)); + poll_as_fds.push((fd, PollFlags::IN)); } Subscription::Write(f) => { @@ -24,12 +24,17 @@ pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> { .file .pollable() .ok_or(Error::invalid_argument().context("file is not pollable"))?; - pollfds.push(PollFd::from_borrowed_fd(fd, PollFlags::OUT)); + poll_as_fds.push((fd, PollFlags::OUT)); } Subscription::MonotonicClock { .. } => unreachable!(), } } + let mut pollfds = poll_as_fds + .iter() + .map(|(fd, events)| PollFd::from_borrowed_fd(fd.as_fd(), events.clone())) + .collect::>(); + let ready = loop { let poll_timeout = if let Some(t) = poll.earliest_clock_deadline() { let duration = t.duration_until().unwrap_or(Duration::from_secs(0)); @@ -55,7 +60,7 @@ pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> { let revents = pollfd.revents(); let (nbytes, rwsub) = match rwsub { Subscription::Read(sub) => { - let ready = sub.file.num_ready_bytes().await?; + let ready = sub.file.num_ready_bytes()?; (std::cmp::max(ready, 1), sub) } Subscription::Write(sub) => (0, sub), diff --git a/crates/wasi-common/cap-std-sync/src/sched/windows.rs b/crates/wasi-common/cap-std-sync/src/sched/windows.rs index c4ad559cc344..e3eeb930523e 100644 --- a/crates/wasi-common/cap-std-sync/src/sched/windows.rs +++ b/crates/wasi-common/cap-std-sync/src/sched/windows.rs @@ -96,7 +96,7 @@ pub async fn poll_oneoff_<'a>( } } for r in immediate_reads { - match r.file.num_ready_bytes().await { + match r.file.num_ready_bytes() { Ok(ready_bytes) => { r.complete(ready_bytes, RwEventFlags::empty()); ready = true; diff --git a/crates/wasi-common/cap-std-sync/src/stdio.rs b/crates/wasi-common/cap-std-sync/src/stdio.rs index 9d82348af15d..dd6f2344faf4 100644 --- a/crates/wasi-common/cap-std-sync/src/stdio.rs +++ b/crates/wasi-common/cap-std-sync/src/stdio.rs @@ -7,8 +7,14 @@ use std::convert::TryInto; use std::fs::File; use std::io; use std::io::{Read, Write}; +use std::sync::Arc; use system_interface::io::ReadReady; +#[cfg(unix)] +use wasi_common::file::BorrowedAsFd; +#[cfg(windows)] +use wasi_common::file::BorrowedAsRawHandleOrSocket; + #[cfg(windows)] use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket}; #[cfg(unix)] @@ -31,41 +37,43 @@ impl WasiFile for Stdin { fn as_any(&self) -> &dyn Any { self } + #[cfg(unix)] - fn pollable(&self) -> Option { - Some(self.0.as_fd()) + fn pollable(&self) -> Option> { + Some(Arc::new(BorrowedAsFd::new(&self.0))) } #[cfg(windows)] - fn pollable(&self) -> Option { - Some(self.0.as_raw_handle_or_socket()) + fn pollable(&self) -> Option> { + Some(Arc::new(BorrowedAsRawHandleOrSocket::new(&self.0))) } - async fn get_filetype(&mut self) -> Result { + + async fn get_filetype(&self) -> Result { if self.isatty() { Ok(FileType::CharacterDevice) } else { Ok(FileType::Unknown) } } - async fn read_vectored<'a>(&mut self, bufs: &mut [io::IoSliceMut<'a>]) -> Result { + async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result { let n = (&*self.0.as_filelike_view::()).read_vectored(bufs)?; Ok(n.try_into().map_err(|_| Error::range())?) } async fn read_vectored_at<'a>( - &mut self, + &self, _bufs: &mut [io::IoSliceMut<'a>], _offset: u64, ) -> Result { Err(Error::seek_pipe()) } - async fn seek(&mut self, _pos: std::io::SeekFrom) -> Result { + async fn seek(&self, _pos: std::io::SeekFrom) -> Result { Err(Error::seek_pipe()) } - async fn peek(&mut self, _buf: &mut [u8]) -> Result { + async fn peek(&self, _buf: &mut [u8]) -> Result { Err(Error::seek_pipe()) } async fn set_times( - &mut self, + &self, atime: Option, mtime: Option, ) -> Result<(), Error> { @@ -73,10 +81,10 @@ impl WasiFile for Stdin { .set_times(convert_systimespec(atime), convert_systimespec(mtime))?; Ok(()) } - async fn num_ready_bytes(&self) -> Result { + fn num_ready_bytes(&self) -> Result { Ok(self.0.num_ready_bytes()?) } - fn isatty(&mut self) -> bool { + fn isatty(&self) -> bool { self.0.is_terminal() } } @@ -108,42 +116,41 @@ macro_rules! wasi_file_write_impl { self } #[cfg(unix)] - fn pollable(&self) -> Option { - Some(self.0.as_fd()) + fn pollable(&self) -> Option> { + Some(Arc::new(BorrowedAsFd::new(&self.0))) } - #[cfg(windows)] - fn pollable(&self) -> Option { - Some(self.0.as_raw_handle_or_socket()) + fn pollable(&self) -> Option> { + Some(Arc::new(BorrowedAsRawHandleOrSocket::new(&self.0))) } - async fn get_filetype(&mut self) -> Result { + async fn get_filetype(&self) -> Result { if self.isatty() { Ok(FileType::CharacterDevice) } else { Ok(FileType::Unknown) } } - async fn get_fdflags(&mut self) -> Result { + async fn get_fdflags(&self) -> Result { Ok(FdFlags::APPEND) } - async fn write_vectored<'a>(&mut self, bufs: &[io::IoSlice<'a>]) -> Result { + async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result { let n = (&*self.0.as_filelike_view::()).write_vectored(bufs)?; Ok(n.try_into().map_err(|_| { Error::range().context("converting write_vectored total length") })?) } async fn write_vectored_at<'a>( - &mut self, + &self, _bufs: &[io::IoSlice<'a>], _offset: u64, ) -> Result { Err(Error::seek_pipe()) } - async fn seek(&mut self, _pos: std::io::SeekFrom) -> Result { + async fn seek(&self, _pos: std::io::SeekFrom) -> Result { Err(Error::seek_pipe()) } async fn set_times( - &mut self, + &self, atime: Option, mtime: Option, ) -> Result<(), Error> { @@ -151,7 +158,7 @@ macro_rules! wasi_file_write_impl { .set_times(convert_systimespec(atime), convert_systimespec(mtime))?; Ok(()) } - fn isatty(&mut self) -> bool { + fn isatty(&self) -> bool { self.0.is_terminal() } } diff --git a/crates/wasi-common/src/ctx.rs b/crates/wasi-common/src/ctx.rs index b4b3a55324a7..1a115e0d8d43 100644 --- a/crates/wasi-common/src/ctx.rs +++ b/crates/wasi-common/src/ctx.rs @@ -7,6 +7,7 @@ use crate::table::Table; use crate::Error; use cap_rand::RngCore; use std::path::{Path, PathBuf}; +use std::sync::Arc; pub struct WasiCtx { pub args: StringArray, @@ -24,7 +25,7 @@ impl WasiCtx { sched: Box, table: Table, ) -> Self { - let mut s = WasiCtx { + let s = WasiCtx { args: StringArray::new(), env: StringArray::new(), random, @@ -38,17 +39,17 @@ impl WasiCtx { s } - pub fn insert_file(&mut self, fd: u32, file: Box, caps: FileCaps) { + pub fn insert_file(&self, fd: u32, file: Box, caps: FileCaps) { self.table() - .insert_at(fd, Box::new(FileEntry::new(caps, file))); + .insert_at(fd, Arc::new(FileEntry::new(caps, file))); } - pub fn push_file(&mut self, file: Box, caps: FileCaps) -> Result { - self.table().push(Box::new(FileEntry::new(caps, file))) + pub fn push_file(&self, file: Box, caps: FileCaps) -> Result { + self.table().push(Arc::new(FileEntry::new(caps, file))) } pub fn insert_dir( - &mut self, + &self, fd: u32, dir: Box, caps: DirCaps, @@ -57,23 +58,23 @@ impl WasiCtx { ) { self.table().insert_at( fd, - Box::new(DirEntry::new(caps, file_caps, Some(path), dir)), + Arc::new(DirEntry::new(caps, file_caps, Some(path), dir)), ); } pub fn push_dir( - &mut self, + &self, dir: Box, caps: DirCaps, file_caps: FileCaps, path: PathBuf, ) -> Result { self.table() - .push(Box::new(DirEntry::new(caps, file_caps, Some(path), dir))) + .push(Arc::new(DirEntry::new(caps, file_caps, Some(path), dir))) } - pub fn table(&mut self) -> &mut Table { - &mut self.table + pub fn table(&self) -> &Table { + &self.table } pub fn push_arg(&mut self, arg: &str) -> Result<(), StringArrayError> { @@ -85,17 +86,17 @@ impl WasiCtx { Ok(()) } - pub fn set_stdin(&mut self, mut f: Box) { + pub fn set_stdin(&self, mut f: Box) { let rights = Self::stdio_rights(&mut *f); self.insert_file(0, f, rights); } - pub fn set_stdout(&mut self, mut f: Box) { + pub fn set_stdout(&self, mut f: Box) { let rights = Self::stdio_rights(&mut *f); self.insert_file(1, f, rights); } - pub fn set_stderr(&mut self, mut f: Box) { + pub fn set_stderr(&self, mut f: Box) { let rights = Self::stdio_rights(&mut *f); self.insert_file(2, f, rights); } @@ -114,13 +115,13 @@ impl WasiCtx { } pub fn push_preopened_dir( - &mut self, + &self, dir: Box, path: impl AsRef, ) -> Result<(), Error> { let caps = DirCaps::all(); let file_caps = FileCaps::all(); - self.table().push(Box::new(DirEntry::new( + self.table().push(Arc::new(DirEntry::new( caps, file_caps, Some(path.as_ref().to_owned()), diff --git a/crates/wasi-common/src/dir.rs b/crates/wasi-common/src/dir.rs index 56a8849db468..48cc10d2f604 100644 --- a/crates/wasi-common/src/dir.rs +++ b/crates/wasi-common/src/dir.rs @@ -3,6 +3,7 @@ use crate::{Error, ErrorExt, SystemTimeSpec}; use bitflags::bitflags; use std::any::Any; use std::path::PathBuf; +use std::sync::{Arc, RwLock}; #[wiggle::async_trait] pub trait WasiDir: Send + Sync { @@ -98,67 +99,50 @@ pub trait WasiDir: Send + Sync { } pub(crate) struct DirEntry { - caps: DirCaps, - file_caps: FileCaps, + caps: RwLock, preopen_path: Option, // precondition: PathBuf is valid unicode dir: Box, } impl DirEntry { pub fn new( - caps: DirCaps, + dir_caps: DirCaps, file_caps: FileCaps, preopen_path: Option, dir: Box, ) -> Self { DirEntry { - caps, - file_caps, + caps: RwLock::new(DirFdStat { + dir_caps, + file_caps, + }), preopen_path, dir, } } pub fn capable_of_dir(&self, caps: DirCaps) -> Result<(), Error> { - if self.caps.contains(caps) { - Ok(()) - } else { - let missing = caps & !self.caps; - let err = if missing.intersects(DirCaps::READDIR) { - Error::not_dir() - } else { - Error::perm() - }; - Err(err.context(format!("desired rights {:?}, has {:?}", caps, self.caps))) - } - } - pub fn capable_of_file(&self, caps: FileCaps) -> Result<(), Error> { - if self.file_caps.contains(caps) { - Ok(()) - } else { - Err(Error::perm().context(format!( - "desired rights {:?}, has {:?}", - caps, self.file_caps - ))) - } + let fdstat = self.caps.read().unwrap(); + fdstat.capable_of_dir(caps) } - pub fn drop_caps_to(&mut self, caps: DirCaps, file_caps: FileCaps) -> Result<(), Error> { - self.capable_of_dir(caps)?; - self.capable_of_file(file_caps)?; - self.caps = caps; - self.file_caps = file_caps; + + pub fn drop_caps_to(&self, dir_caps: DirCaps, file_caps: FileCaps) -> Result<(), Error> { + let mut fdstat = self.caps.write().unwrap(); + fdstat.capable_of_dir(dir_caps)?; + fdstat.capable_of_file(file_caps)?; + *fdstat = DirFdStat { + dir_caps, + file_caps, + }; Ok(()) } pub fn child_dir_caps(&self, desired_caps: DirCaps) -> DirCaps { - self.caps & desired_caps + self.caps.read().unwrap().dir_caps & desired_caps } pub fn child_file_caps(&self, desired_caps: FileCaps) -> FileCaps { - self.file_caps & desired_caps + self.caps.read().unwrap().file_caps & desired_caps } pub fn get_dir_fdstat(&self) -> DirFdStat { - DirFdStat { - dir_caps: self.caps, - file_caps: self.file_caps, - } + self.caps.read().unwrap().clone() } pub fn preopen_path(&self) -> &Option { &self.preopen_path @@ -203,18 +187,47 @@ pub struct DirFdStat { pub dir_caps: DirCaps, } +impl DirFdStat { + pub fn capable_of_dir(&self, caps: DirCaps) -> Result<(), Error> { + if self.dir_caps.contains(caps) { + Ok(()) + } else { + let missing = caps & !self.dir_caps; + let err = if missing.intersects(DirCaps::READDIR) { + Error::not_dir() + } else { + Error::perm() + }; + Err(err.context(format!( + "desired rights {:?}, has {:?}", + caps, self.dir_caps + ))) + } + } + pub fn capable_of_file(&self, caps: FileCaps) -> Result<(), Error> { + if self.file_caps.contains(caps) { + Ok(()) + } else { + Err(Error::perm().context(format!( + "desired rights {:?}, has {:?}", + caps, self.file_caps + ))) + } + } +} + pub(crate) trait TableDirExt { - fn get_dir(&self, fd: u32) -> Result<&DirEntry, Error>; + fn get_dir(&self, fd: u32) -> Result, Error>; fn is_preopen(&self, fd: u32) -> bool; } impl TableDirExt for crate::table::Table { - fn get_dir(&self, fd: u32) -> Result<&DirEntry, Error> { + fn get_dir(&self, fd: u32) -> Result, Error> { self.get(fd) } fn is_preopen(&self, fd: u32) -> bool { if self.is::(fd) { - let dir_entry: &DirEntry = self.get(fd).unwrap(); + let dir_entry: Arc = self.get(fd).unwrap(); dir_entry.preopen_path.is_some() } else { false diff --git a/crates/wasi-common/src/file.rs b/crates/wasi-common/src/file.rs index 8d4bf6a45a61..b76278373a65 100644 --- a/crates/wasi-common/src/file.rs +++ b/crates/wasi-common/src/file.rs @@ -1,32 +1,39 @@ use crate::{Error, ErrorExt, SystemTimeSpec}; use bitflags::bitflags; use std::any::Any; +use std::sync::{Arc, RwLock}; + +#[cfg(unix)] +use cap_std::io_lifetimes::{AsFd, BorrowedFd}; + +#[cfg(windows)] +use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket}; #[wiggle::async_trait] pub trait WasiFile: Send + Sync { fn as_any(&self) -> &dyn Any; - async fn get_filetype(&mut self) -> Result; + async fn get_filetype(&self) -> Result; #[cfg(unix)] - fn pollable(&self) -> Option { + fn pollable(&self) -> Option> { None } #[cfg(windows)] - fn pollable(&self) -> Option { + fn pollable(&self) -> Option> { None } - fn isatty(&mut self) -> bool { + fn isatty(&self) -> bool { false } - async fn sock_accept(&mut self, _fdflags: FdFlags) -> Result, Error> { + async fn sock_accept(&self, _fdflags: FdFlags) -> Result, Error> { Err(Error::badf()) } async fn sock_recv<'a>( - &mut self, + &self, _ri_data: &mut [std::io::IoSliceMut<'a>], _ri_flags: RiFlags, ) -> Result<(u64, RoFlags), Error> { @@ -34,34 +41,34 @@ pub trait WasiFile: Send + Sync { } async fn sock_send<'a>( - &mut self, + &self, _si_data: &[std::io::IoSlice<'a>], _si_flags: SiFlags, ) -> Result { Err(Error::badf()) } - async fn sock_shutdown(&mut self, _how: SdFlags) -> Result<(), Error> { + async fn sock_shutdown(&self, _how: SdFlags) -> Result<(), Error> { Err(Error::badf()) } - async fn datasync(&mut self) -> Result<(), Error> { + async fn datasync(&self) -> Result<(), Error> { Ok(()) } - async fn sync(&mut self) -> Result<(), Error> { + async fn sync(&self) -> Result<(), Error> { Ok(()) } - async fn get_fdflags(&mut self) -> Result { + async fn get_fdflags(&self) -> Result { Ok(FdFlags::empty()) } - async fn set_fdflags(&mut self, _flags: FdFlags) -> Result<(), Error> { + async fn set_fdflags(&self, _flags: FdFlags) -> Result<(), Error> { Err(Error::badf()) } - async fn get_filestat(&mut self) -> Result { + async fn get_filestat(&self) -> Result { Ok(Filestat { device_id: 0, inode: 0, @@ -74,62 +81,59 @@ pub trait WasiFile: Send + Sync { }) } - async fn set_filestat_size(&mut self, _size: u64) -> Result<(), Error> { + async fn set_filestat_size(&self, _size: u64) -> Result<(), Error> { Err(Error::badf()) } - async fn advise(&mut self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> { + async fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> { Err(Error::badf()) } - async fn allocate(&mut self, _offset: u64, _len: u64) -> Result<(), Error> { + async fn allocate(&self, _offset: u64, _len: u64) -> Result<(), Error> { Err(Error::badf()) } async fn set_times( - &mut self, + &self, _atime: Option, _mtime: Option, ) -> Result<(), Error> { Err(Error::badf()) } - async fn read_vectored<'a>( - &mut self, - _bufs: &mut [std::io::IoSliceMut<'a>], - ) -> Result { + async fn read_vectored<'a>(&self, _bufs: &mut [std::io::IoSliceMut<'a>]) -> Result { Err(Error::badf()) } async fn read_vectored_at<'a>( - &mut self, + &self, _bufs: &mut [std::io::IoSliceMut<'a>], _offset: u64, ) -> Result { Err(Error::badf()) } - async fn write_vectored<'a>(&mut self, _bufs: &[std::io::IoSlice<'a>]) -> Result { + async fn write_vectored<'a>(&self, _bufs: &[std::io::IoSlice<'a>]) -> Result { Err(Error::badf()) } async fn write_vectored_at<'a>( - &mut self, + &self, _bufs: &[std::io::IoSlice<'a>], _offset: u64, ) -> Result { Err(Error::badf()) } - async fn seek(&mut self, _pos: std::io::SeekFrom) -> Result { + async fn seek(&self, _pos: std::io::SeekFrom) -> Result { Err(Error::badf()) } - async fn peek(&mut self, _buf: &mut [u8]) -> Result { + async fn peek(&self, _buf: &mut [u8]) -> Result { Err(Error::badf()) } - async fn num_ready_bytes(&self) -> Result { + fn num_ready_bytes(&self) -> Result { Ok(0) } @@ -212,33 +216,32 @@ pub struct Filestat { } pub(crate) trait TableFileExt { - fn get_file(&self, fd: u32) -> Result<&FileEntry, Error>; - fn get_file_mut(&mut self, fd: u32) -> Result<&mut FileEntry, Error>; + fn get_file(&self, fd: u32) -> Result, Error>; } impl TableFileExt for crate::table::Table { - fn get_file(&self, fd: u32) -> Result<&FileEntry, Error> { + fn get_file(&self, fd: u32) -> Result, Error> { self.get(fd) } - fn get_file_mut(&mut self, fd: u32) -> Result<&mut FileEntry, Error> { - self.get_mut(fd) - } } pub(crate) struct FileEntry { - caps: FileCaps, + caps: RwLock, file: Box, } impl FileEntry { pub fn new(caps: FileCaps, file: Box) -> Self { - FileEntry { caps, file } + FileEntry { + caps: RwLock::new(caps), + file, + } } pub fn capable_of(&self, caps: FileCaps) -> Result<(), Error> { - if self.caps.contains(caps) { + if self.caps.read().unwrap().contains(caps) { Ok(()) } else { - let missing = caps & !self.caps; + let missing = caps & !(*self.caps.read().unwrap()); let err = if missing.intersects(FileCaps::READ | FileCaps::WRITE) { // `EBADF` is a little surprising here because it's also used // for unknown-file-descriptor errors, but it's what POSIX uses @@ -251,16 +254,17 @@ impl FileEntry { } } - pub fn drop_caps_to(&mut self, caps: FileCaps) -> Result<(), Error> { + pub fn drop_caps_to(&self, caps: FileCaps) -> Result<(), Error> { self.capable_of(caps)?; - self.caps = caps; + *self.caps.write().unwrap() = caps; Ok(()) } - pub async fn get_fdstat(&mut self) -> Result { + pub async fn get_fdstat(&self) -> Result { + let caps = self.caps.read().unwrap().clone(); Ok(FdStat { filetype: self.file.get_filetype().await?, - caps: self.caps, + caps, flags: self.file.get_fdflags().await?, }) } @@ -268,7 +272,6 @@ impl FileEntry { pub trait FileEntryExt { fn get_cap(&self, caps: FileCaps) -> Result<&dyn WasiFile, Error>; - fn get_cap_mut(&mut self, caps: FileCaps) -> Result<&mut dyn WasiFile, Error>; } impl FileEntryExt for FileEntry { @@ -276,11 +279,6 @@ impl FileEntryExt for FileEntry { self.capable_of(caps)?; Ok(&*self.file) } - - fn get_cap_mut(&mut self, caps: FileCaps) -> Result<&mut dyn WasiFile, Error> { - self.capable_of(caps)?; - Ok(&mut *self.file) - } } bitflags! { @@ -317,3 +315,39 @@ pub enum Advice { DontNeed, NoReuse, } + +#[cfg(unix)] +pub struct BorrowedAsFd<'a, T: AsFd>(&'a T); + +#[cfg(unix)] +impl<'a, T: AsFd> BorrowedAsFd<'a, T> { + pub fn new(t: &'a T) -> Self { + BorrowedAsFd(t) + } +} + +#[cfg(unix)] +impl AsFd for BorrowedAsFd<'_, T> { + #[inline] + fn as_fd(&self) -> BorrowedFd { + self.0.as_fd() + } +} + +#[cfg(windows)] +pub struct BorrowedAsRawHandleOrSocket<'a, T: AsRawHandleOrSocket>(&'a T); + +#[cfg(windows)] +impl<'a, T: AsRawHandleOrSocket> BorrowedAsRawHandleOrSocket<'a, T> { + pub fn new(t: &'a T) -> Self { + BorrowedAsRawHandleOrSocket(t) + } +} + +#[cfg(windows)] +impl AsRawHandleOrSocket for BorrowedAsRawHandleOrSocket<'_, T> { + #[inline] + fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { + self.0.as_raw_handle_or_socket() + } +} diff --git a/crates/wasi-common/src/pipe.rs b/crates/wasi-common/src/pipe.rs index a5fceb80a1b1..1700131bd6cc 100644 --- a/crates/wasi-common/src/pipe.rs +++ b/crates/wasi-common/src/pipe.rs @@ -105,10 +105,10 @@ impl WasiFile for ReadPipe { fn as_any(&self) -> &dyn Any { self } - async fn get_filetype(&mut self) -> Result { + async fn get_filetype(&self) -> Result { Ok(FileType::Pipe) } - async fn read_vectored<'a>(&mut self, bufs: &mut [io::IoSliceMut<'a>]) -> Result { + async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result { let n = self.borrow().read_vectored(bufs)?; Ok(n.try_into()?) } @@ -189,13 +189,13 @@ impl WasiFile for WritePipe { fn as_any(&self) -> &dyn Any { self } - async fn get_filetype(&mut self) -> Result { + async fn get_filetype(&self) -> Result { Ok(FileType::Pipe) } - async fn get_fdflags(&mut self) -> Result { + async fn get_fdflags(&self) -> Result { Ok(FdFlags::APPEND) } - async fn write_vectored<'a>(&mut self, bufs: &[io::IoSlice<'a>]) -> Result { + async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result { let n = self.borrow().write_vectored(bufs)?; Ok(n.try_into()?) } diff --git a/crates/wasi-common/src/snapshots/preview_0.rs b/crates/wasi-common/src/snapshots/preview_0.rs index a155bad766e0..2404dabd4e39 100644 --- a/crates/wasi-common/src/snapshots/preview_0.rs +++ b/crates/wasi-common/src/snapshots/preview_0.rs @@ -527,10 +527,8 @@ impl wasi_unstable::WasiUnstable for WasiCtx { fd: types::Fd, iovs: &types::IovecArray<'a>, ) -> Result { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::READ)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::READ)?; let mut guest_slices: Vec> = iovs.iter() @@ -558,10 +556,8 @@ impl wasi_unstable::WasiUnstable for WasiCtx { iovs: &types::IovecArray<'a>, offset: types::Filesize, ) -> Result { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::READ | FileCaps::SEEK)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::READ | FileCaps::SEEK)?; let mut guest_slices: Vec> = iovs.iter() @@ -588,10 +584,8 @@ impl wasi_unstable::WasiUnstable for WasiCtx { fd: types::Fd, ciovs: &types::CiovecArray<'a>, ) -> Result { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::WRITE)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::WRITE)?; let guest_slices: Vec> = ciovs .iter() @@ -621,10 +615,8 @@ impl wasi_unstable::WasiUnstable for WasiCtx { ciovs: &types::CiovecArray<'a>, offset: types::Filesize, ) -> Result { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::WRITE | FileCaps::SEEK)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::WRITE | FileCaps::SEEK)?; let guest_slices: Vec> = ciovs .iter() @@ -874,7 +866,7 @@ impl wasi_unstable::WasiUnstable for WasiCtx { } } - let table = &mut self.table; + let table = &self.table; let mut sub_fds: HashSet = HashSet::new(); // We need these refmuts to outlive Poll, which will hold the &mut dyn WasiFile inside let mut reads: Vec<(u32, Userdata)> = Vec::new(); @@ -924,8 +916,8 @@ impl wasi_unstable::WasiUnstable for WasiCtx { sub_fds.insert(fd); } table - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::POLL_READWRITE)?; + .get_file(u32::from(fd))? + .get_cap(FileCaps::POLL_READWRITE)?; reads.push((u32::from(fd), sub.userdata.into())); } types::SubscriptionU::FdWrite(writesub) => { @@ -937,8 +929,8 @@ impl wasi_unstable::WasiUnstable for WasiCtx { sub_fds.insert(fd); } table - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::POLL_READWRITE)?; + .get_file(u32::from(fd))? + .get_cap(FileCaps::POLL_READWRITE)?; writes.push((u32::from(fd), sub.userdata.into())); } } diff --git a/crates/wasi-common/src/snapshots/preview_1.rs b/crates/wasi-common/src/snapshots/preview_1.rs index 37abf1f6f86c..4776cb10c268 100644 --- a/crates/wasi-common/src/snapshots/preview_1.rs +++ b/crates/wasi-common/src/snapshots/preview_1.rs @@ -14,6 +14,7 @@ use cap_std::time::{Duration, SystemClock}; use std::convert::{TryFrom, TryInto}; use std::io::{IoSlice, IoSliceMut}; use std::ops::{Deref, DerefMut}; +use std::sync::Arc; use wiggle::GuestPtr; pub mod error; @@ -107,8 +108,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { advice: types::Advice, ) -> Result<(), Error> { self.table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::ADVISE)? + .get_file(u32::from(fd))? + .get_cap(FileCaps::ADVISE)? .advise(offset, len, advice.into()) .await?; Ok(()) @@ -121,8 +122,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { len: types::Filesize, ) -> Result<(), Error> { self.table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::ALLOCATE)? + .get_file(u32::from(fd))? + .get_cap(FileCaps::ALLOCATE)? .allocate(offset, len) .await?; Ok(()) @@ -138,15 +139,15 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { } // fd_close must close either a File or a Dir handle if table.is::(fd) { - let _ = table.delete(fd); + let _ = table.delete::(fd); } else if table.is::(fd) { // We cannot close preopened directories - let dir_entry: &DirEntry = table.get(fd).unwrap(); + let dir_entry: Arc = table.get(fd).unwrap(); if dir_entry.preopen_path().is_some() { return Err(Error::not_supported().context("cannot close propened directory")); } drop(dir_entry); - let _ = table.delete(fd); + let _ = table.delete::(fd); } else { return Err(Error::badf().context("key does not refer to file or directory")); } @@ -156,8 +157,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { async fn fd_datasync(&mut self, fd: types::Fd) -> Result<(), Error> { self.table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::DATASYNC)? + .get_file(u32::from(fd))? + .get_cap(FileCaps::DATASYNC)? .datasync() .await?; Ok(()) @@ -167,11 +168,11 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { let table = self.table(); let fd = u32::from(fd); if table.is::(fd) { - let file_entry: &mut FileEntry = table.get_mut(fd)?; + let file_entry: Arc = table.get(fd)?; let fdstat = file_entry.get_fdstat().await?; Ok(types::Fdstat::from(&fdstat)) } else if table.is::(fd) { - let dir_entry: &DirEntry = table.get(fd)?; + let dir_entry: Arc = table.get(fd)?; let dir_fdstat = dir_entry.get_dir_fdstat(); Ok(types::Fdstat::from(&dir_fdstat)) } else { @@ -185,8 +186,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { flags: types::Fdflags, ) -> Result<(), Error> { self.table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::FDSTAT_SET_FLAGS)? + .get_file(u32::from(fd))? + .get_cap(FileCaps::FDSTAT_SET_FLAGS)? .set_fdflags(FdFlags::from(flags)) .await } @@ -200,11 +201,11 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { let table = self.table(); let fd = u32::from(fd); if table.is::(fd) { - let file_entry: &mut FileEntry = table.get_mut(fd)?; + let file_entry: Arc = table.get(fd)?; let file_caps = FileCaps::from(&fs_rights_base); file_entry.drop_caps_to(file_caps) } else if table.is::(fd) { - let dir_entry: &mut DirEntry = table.get_mut(fd)?; + let dir_entry: Arc = table.get(fd)?; let dir_caps = DirCaps::from(&fs_rights_base); let file_caps = FileCaps::from(&fs_rights_inheriting); dir_entry.drop_caps_to(dir_caps, file_caps) @@ -218,8 +219,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { let fd = u32::from(fd); if table.is::(fd) { let filestat = table - .get_file_mut(fd)? - .get_cap_mut(FileCaps::FILESTAT_GET)? + .get_file(fd)? + .get_cap(FileCaps::FILESTAT_GET)? .get_filestat() .await?; Ok(filestat.into()) @@ -241,8 +242,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { size: types::Filesize, ) -> Result<(), Error> { self.table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::FILESTAT_SET_SIZE)? + .get_file(u32::from(fd))? + .get_cap(FileCaps::FILESTAT_SET_SIZE)? .set_filestat_size(size) .await?; Ok(()) @@ -268,9 +269,9 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { if table.is::(fd) { table - .get_file_mut(fd) + .get_file(fd) .expect("checked that entry is file") - .get_cap_mut(FileCaps::FILESTAT_SET_TIMES)? + .get_cap(FileCaps::FILESTAT_SET_TIMES)? .set_times(atim, mtim) .await } else if table.is::(fd) { @@ -290,10 +291,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fd: types::Fd, iovs: &types::IovecArray<'a>, ) -> Result { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::READ)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::READ)?; let mut guest_slices: Vec> = iovs.iter() @@ -321,10 +320,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { iovs: &types::IovecArray<'a>, offset: types::Filesize, ) -> Result { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::READ | FileCaps::SEEK)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::READ | FileCaps::SEEK)?; let mut guest_slices: Vec> = iovs.iter() @@ -351,10 +348,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fd: types::Fd, ciovs: &types::CiovecArray<'a>, ) -> Result { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::WRITE)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::WRITE)?; let guest_slices: Vec> = ciovs .iter() @@ -384,10 +379,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { ciovs: &types::CiovecArray<'a>, offset: types::Filesize, ) -> Result { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::WRITE | FileCaps::SEEK)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::WRITE | FileCaps::SEEK)?; let guest_slices: Vec> = ciovs .iter() @@ -413,7 +406,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { async fn fd_prestat_get(&mut self, fd: types::Fd) -> Result { let table = self.table(); - let dir_entry: &DirEntry = table.get(u32::from(fd)).map_err(|_| Error::badf())?; + let dir_entry: Arc = table.get(u32::from(fd)).map_err(|_| Error::badf())?; if let Some(ref preopen) = dir_entry.preopen_path() { let path_str = preopen.to_str().ok_or_else(|| Error::not_supported())?; let pr_name_len = u32::try_from(path_str.as_bytes().len())?; @@ -430,7 +423,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { path_max_len: types::Size, ) -> Result<(), Error> { let table = self.table(); - let dir_entry: &DirEntry = table.get(u32::from(fd)).map_err(|_| Error::not_dir())?; + let dir_entry: Arc = table.get(u32::from(fd)).map_err(|_| Error::not_dir())?; if let Some(ref preopen) = dir_entry.preopen_path() { let path_bytes = preopen .to_str() @@ -460,11 +453,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { if table.is_preopen(from) || table.is_preopen(to) { return Err(Error::not_supported().context("cannot renumber a preopen")); } - let from_entry = table - .delete(from) - .expect("we checked that table contains from"); - table.insert_at(to, from_entry); - Ok(()) + table.renumber(from, to) } async fn fd_seek( @@ -488,8 +477,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { }; let newoffset = self .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(required_caps)? + .get_file(u32::from(fd))? + .get_cap(required_caps)? .seek(whence) .await?; Ok(newoffset) @@ -497,8 +486,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { async fn fd_sync(&mut self, fd: types::Fd) -> Result<(), Error> { self.table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::SYNC)? + .get_file(u32::from(fd))? + .get_cap(FileCaps::SYNC)? .sync() .await?; Ok(()) @@ -508,8 +497,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { // XXX should this be stream_position? let offset = self .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::TELL)? + .get_file(u32::from(fd))? + .get_cap(FileCaps::TELL)? .seek(std::io::SeekFrom::Current(0)) .await?; Ok(offset) @@ -636,12 +625,10 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { target_path: &GuestPtr<'a, str>, ) -> Result<(), Error> { let table = self.table(); - let src_dir = table - .get_dir(u32::from(src_fd))? - .get_cap(DirCaps::LINK_SOURCE)?; - let target_dir = table - .get_dir(u32::from(target_fd))? - .get_cap(DirCaps::LINK_TARGET)?; + let src_dir = table.get_dir(u32::from(src_fd))?; + let src_dir = src_dir.get_cap(DirCaps::LINK_SOURCE)?; + let target_dir = table.get_dir(u32::from(target_fd))?; + let target_dir = target_dir.get_cap(DirCaps::LINK_TARGET)?; let symlink_follow = src_flags.contains(types::Lookupflags::SYMLINK_FOLLOW); if symlink_follow { return Err(Error::invalid_argument() @@ -691,7 +678,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { let dir = dir_entry.get_cap(DirCaps::OPEN)?; let child_dir = dir.open_dir(symlink_follow, path.deref()).await?; drop(dir); - let fd = table.push(Box::new(DirEntry::new( + let fd = table.push(Arc::new(DirEntry::new( dir_caps, file_caps, None, child_dir, )))?; Ok(types::Fd::from(fd)) @@ -711,7 +698,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { .open_file(symlink_follow, path.deref(), oflags, read, write, fdflags) .await?; drop(dir); - let fd = table.push(Box::new(FileEntry::new(file_caps, file)))?; + let fd = table.push(Arc::new(FileEntry::new(file_caps, file)))?; Ok(types::Fd::from(fd)) } } @@ -765,12 +752,10 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { dest_path: &GuestPtr<'a, str>, ) -> Result<(), Error> { let table = self.table(); - let src_dir = table - .get_dir(u32::from(src_fd))? - .get_cap(DirCaps::RENAME_SOURCE)?; - let dest_dir = table - .get_dir(u32::from(dest_fd))? - .get_cap(DirCaps::RENAME_TARGET)?; + let src_dir = table.get_dir(u32::from(src_fd))?; + let src_dir = src_dir.get_cap(DirCaps::RENAME_SOURCE)?; + let dest_dir = table.get_dir(u32::from(dest_fd))?; + let dest_dir = dest_dir.get_cap(DirCaps::RENAME_TARGET)?; src_dir .rename( src_path.as_str()?.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)").deref(), @@ -841,10 +826,11 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { } } - let table = &mut self.table; + let table = &self.table; // We need these refmuts to outlive Poll, which will hold the &mut dyn WasiFile inside - let mut read_refs: Vec<(&dyn WasiFile, Userdata)> = Vec::new(); - let mut write_refs: Vec<(&dyn WasiFile, Userdata)> = Vec::new(); + let mut read_refs: Vec<(Arc, Option)> = Vec::new(); + let mut write_refs: Vec<(Arc, Option)> = Vec::new(); + let mut poll = Poll::new(); let subs = subs.as_array(nsubscriptions); @@ -910,25 +896,37 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { }, types::SubscriptionU::FdRead(readsub) => { let fd = readsub.file_descriptor; - let file_ref = table - .get_file(u32::from(fd))? - .get_cap(FileCaps::POLL_READWRITE)?; - read_refs.push((file_ref, sub.userdata.into())); + let file_ref = table.get_file(u32::from(fd))?; + let _file = file_ref.get_cap(FileCaps::POLL_READWRITE)?; + + read_refs.push((file_ref, Some(sub.userdata.into()))); } types::SubscriptionU::FdWrite(writesub) => { let fd = writesub.file_descriptor; - let file_ref = table - .get_file(u32::from(fd))? - .get_cap(FileCaps::POLL_READWRITE)?; - write_refs.push((file_ref, sub.userdata.into())); + let file_ref = table.get_file(u32::from(fd))?; + let _file = file_ref.get_cap(FileCaps::POLL_READWRITE)?; + write_refs.push((file_ref, Some(sub.userdata.into()))); } } } - for (f, ud) in read_refs.iter_mut() { + let mut read_mut_refs: Vec<(&dyn WasiFile, Userdata)> = Vec::new(); + for (file_lock, userdata) in read_refs.iter_mut() { + let file = file_lock.get_cap(FileCaps::POLL_READWRITE)?; + read_mut_refs.push((file, userdata.take().unwrap())); + } + + for (f, ud) in read_mut_refs.iter_mut() { poll.subscribe_read(*f, *ud); } - for (f, ud) in write_refs.iter_mut() { + + let mut write_mut_refs: Vec<(&dyn WasiFile, Userdata)> = Vec::new(); + for (file_lock, userdata) in write_refs.iter_mut() { + let file = file_lock.get_cap(FileCaps::POLL_READWRITE)?; + write_mut_refs.push((file, userdata.take().unwrap())); + } + + for (f, ud) in write_mut_refs.iter_mut() { poll.subscribe_write(*f, *ud); } @@ -1043,9 +1041,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { flags: types::Fdflags, ) -> Result { let table = self.table(); - let f = table - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::READ)?; + let f = table.get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::READ)?; let file = f.sock_accept(FdFlags::from(flags)).await?; let file_caps = FileCaps::READ @@ -1054,7 +1051,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { | FileCaps::POLL_READWRITE | FileCaps::FILESTAT_GET; - let fd = table.push(Box::new(FileEntry::new(file_caps, file)))?; + let fd = table.push(Arc::new(FileEntry::new(file_caps, file)))?; Ok(types::Fd::from(fd)) } @@ -1064,10 +1061,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { ri_data: &types::IovecArray<'a>, ri_flags: types::Riflags, ) -> Result<(types::Size, types::Roflags), Error> { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::READ)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::READ)?; let mut guest_slices: Vec> = ri_data @@ -1096,10 +1091,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { si_data: &types::CiovecArray<'a>, _si_flags: types::Siflags, ) -> Result { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::WRITE)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::WRITE)?; let guest_slices: Vec> = si_data .iter() @@ -1124,10 +1117,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { } async fn sock_shutdown(&mut self, fd: types::Fd, how: types::Sdflags) -> Result<(), Error> { - let f = self - .table() - .get_file_mut(u32::from(fd))? - .get_cap_mut(FileCaps::FDSTAT_SET_FLAGS)?; + let f = self.table().get_file(u32::from(fd))?; + let f = f.get_cap(FileCaps::FDSTAT_SET_FLAGS)?; f.sock_shutdown(SdFlags::from(how)).await } diff --git a/crates/wasi-common/src/table.rs b/crates/wasi-common/src/table.rs index 195d8babb677..a92fefff6a2a 100644 --- a/crates/wasi-common/src/table.rs +++ b/crates/wasi-common/src/table.rs @@ -1,6 +1,7 @@ use crate::{Error, ErrorExt}; use std::any::Any; use std::collections::HashMap; +use std::sync::{Arc, RwLock}; /// The `Table` type is designed to map u32 handles to resources. The table is now part of the /// public interface to a `WasiCtx` - it is reference counted so that it can be shared beyond a @@ -9,84 +10,89 @@ use std::collections::HashMap; /// /// The `Table` type is intended to model how the Interface Types concept of Resources is shaping /// up. Right now it is just an approximation. -pub struct Table { - map: HashMap>, +pub struct Table(RwLock); + +struct Inner { + map: HashMap>, next_key: u32, } impl Table { /// Create an empty table. New insertions will begin at 3, above stdio. pub fn new() -> Self { - Table { + Table(RwLock::new(Inner { map: HashMap::new(), next_key: 3, // 0, 1 and 2 are reserved for stdio - } + })) } /// Insert a resource at a certain index. - pub fn insert_at(&mut self, key: u32, a: Box) { - self.map.insert(key, a); + pub fn insert_at(&self, key: u32, a: Arc) { + self.0.write().unwrap().map.insert(key, a); } /// Insert a resource at the next available index. - pub fn push(&mut self, a: Box) -> Result { + pub fn push(&self, a: Arc) -> Result { + let mut inner = self.0.write().unwrap(); // NOTE: The performance of this new key calculation could be very bad once keys wrap // around. - if self.map.len() == u32::MAX as usize { + if inner.map.len() == u32::MAX as usize { return Err(Error::trap(anyhow::Error::msg("table has no free keys"))); } loop { - let key = self.next_key; - self.next_key = self.next_key.wrapping_add(1); - if self.map.contains_key(&key) { + let key = inner.next_key; + inner.next_key += 1; + if inner.map.contains_key(&key) { continue; } - self.map.insert(key, a); + inner.map.insert(key, a); return Ok(key); } } /// Check if the table has a resource at the given index. pub fn contains_key(&self, key: u32) -> bool { - self.map.contains_key(&key) + self.0.read().unwrap().map.contains_key(&key) } /// Check if the resource at a given index can be downcast to a given type. /// Note: this will always fail if the resource is already borrowed. pub fn is(&self, key: u32) -> bool { - if let Some(r) = self.map.get(&key) { + if let Some(r) = self.0.read().unwrap().map.get(&key) { r.is::() } else { false } } - /// Get an immutable reference to a resource of a given type at a given index. Multiple - /// immutable references can be borrowed at any given time. Borrow failure - /// results in a trapping error. - pub fn get(&self, key: u32) -> Result<&T, Error> { - if let Some(r) = self.map.get(&key) { - r.downcast_ref::() - .ok_or_else(|| Error::badf().context("element is a different type")) + /// Get an Arc reference to a resource of a given type at a given index. Multiple + /// immutable references can be borrowed at any given time. + pub fn get(&self, key: u32) -> Result, Error> { + if let Some(r) = self.0.read().unwrap().map.get(&key).cloned() { + r.downcast::() + .map_err(|_| Error::badf().context("element is a different type")) } else { Err(Error::badf().context("key not in table")) } } - /// Get a mutable reference to a resource of a given type at a given index. Only one mutable - /// reference can be borrowed at any given time. Borrow failure results in a trapping error. - pub fn get_mut(&mut self, key: u32) -> Result<&mut T, Error> { - if let Some(r) = self.map.get_mut(&key) { - r.downcast_mut::() - .ok_or_else(|| Error::badf().context("element is a different type")) - } else { - Err(Error::badf().context("key not in table")) - } + /// Remove a resource at a given index from the table. Returns the resource + /// if it was present. + pub fn delete(&self, key: u32) -> Option> { + self.0 + .write() + .unwrap() + .map + .remove(&key) + .map(|r| r.downcast::().unwrap()) } /// Remove a resource at a given index from the table. Returns the resource /// if it was present. - pub fn delete(&mut self, key: u32) -> Option> { - self.map.remove(&key) + pub fn renumber(&self, from: u32, to: u32) -> Result<(), Error> { + let map = &mut self.0.write().unwrap().map; + let from_entry = map.remove(&from).ok_or(Error::badf())?; + map.insert(to, from_entry); + Ok(()) } } diff --git a/crates/wasi-common/tokio/src/file.rs b/crates/wasi-common/tokio/src/file.rs index 030e60e5119c..91e70aa58397 100644 --- a/crates/wasi-common/tokio/src/file.rs +++ b/crates/wasi-common/tokio/src/file.rs @@ -4,7 +4,9 @@ use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket}; #[cfg(not(windows))] use io_lifetimes::AsFd; use std::any::Any; +use std::borrow::Borrow; use std::io; +use std::sync::Arc; use wasi_common::{ file::{Advice, FdFlags, FileType, Filestat, WasiFile}, Error, @@ -95,81 +97,80 @@ macro_rules! wasi_file_impl { self } #[cfg(unix)] - fn pollable(&self) -> Option { - Some(self.0.as_fd()) + fn pollable(&self) -> Option> { + self.0.pollable() } - #[cfg(windows)] - fn pollable(&self) -> Option { - Some(self.0.as_raw_handle_or_socket()) + fn pollable(&self) -> Option> { + self.0.pollable() } - async fn datasync(&mut self) -> Result<(), Error> { + async fn datasync(&self) -> Result<(), Error> { block_on_dummy_executor(|| self.0.datasync()) } - async fn sync(&mut self) -> Result<(), Error> { + async fn sync(&self) -> Result<(), Error> { block_on_dummy_executor(|| self.0.sync()) } - async fn get_filetype(&mut self) -> Result { + async fn get_filetype(&self) -> Result { block_on_dummy_executor(|| self.0.get_filetype()) } - async fn get_fdflags(&mut self) -> Result { + async fn get_fdflags(&self) -> Result { block_on_dummy_executor(|| self.0.get_fdflags()) } - async fn set_fdflags(&mut self, fdflags: FdFlags) -> Result<(), Error> { + async fn set_fdflags(&self, fdflags: FdFlags) -> Result<(), Error> { block_on_dummy_executor(|| self.0.set_fdflags(fdflags)) } - async fn get_filestat(&mut self) -> Result { + async fn get_filestat(&self) -> Result { block_on_dummy_executor(|| self.0.get_filestat()) } - async fn set_filestat_size(&mut self, size: u64) -> Result<(), Error> { + async fn set_filestat_size(&self, size: u64) -> Result<(), Error> { block_on_dummy_executor(move || self.0.set_filestat_size(size)) } - async fn advise(&mut self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> { + async fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> { block_on_dummy_executor(move || self.0.advise(offset, len, advice)) } - async fn allocate(&mut self, offset: u64, len: u64) -> Result<(), Error> { + async fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> { block_on_dummy_executor(move || self.0.allocate(offset, len)) } async fn read_vectored<'a>( - &mut self, + &self, bufs: &mut [io::IoSliceMut<'a>], ) -> Result { block_on_dummy_executor(move || self.0.read_vectored(bufs)) } async fn read_vectored_at<'a>( - &mut self, + &self, bufs: &mut [io::IoSliceMut<'a>], offset: u64, ) -> Result { block_on_dummy_executor(move || self.0.read_vectored_at(bufs, offset)) } - async fn write_vectored<'a>(&mut self, bufs: &[io::IoSlice<'a>]) -> Result { + async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result { block_on_dummy_executor(move || self.0.write_vectored(bufs)) } async fn write_vectored_at<'a>( - &mut self, + &self, bufs: &[io::IoSlice<'a>], offset: u64, ) -> Result { block_on_dummy_executor(move || self.0.write_vectored_at(bufs, offset)) } - async fn seek(&mut self, pos: std::io::SeekFrom) -> Result { + async fn seek(&self, pos: std::io::SeekFrom) -> Result { block_on_dummy_executor(move || self.0.seek(pos)) } - async fn peek(&mut self, buf: &mut [u8]) -> Result { + async fn peek(&self, buf: &mut [u8]) -> Result { block_on_dummy_executor(move || self.0.peek(buf)) } async fn set_times( - &mut self, + &self, atime: Option, mtime: Option, ) -> Result<(), Error> { block_on_dummy_executor(move || self.0.set_times(atime, mtime)) } - async fn num_ready_bytes(&self) -> Result { - block_on_dummy_executor(|| self.0.num_ready_bytes()) + fn num_ready_bytes(&self) -> Result { + self.0.num_ready_bytes() } - fn isatty(&mut self) -> bool { + fn isatty(&self) -> bool { self.0.isatty() } @@ -182,7 +183,7 @@ macro_rules! wasi_file_impl { // lifetime of the AsyncFd. use std::os::unix::io::AsRawFd; use tokio::io::{unix::AsyncFd, Interest}; - let rawfd = self.0.as_fd().as_raw_fd(); + let rawfd = self.0.borrow().as_fd().as_raw_fd(); match AsyncFd::with_interest(rawfd, Interest::READABLE) { Ok(asyncfd) => { let _ = asyncfd.readable().await?; @@ -206,7 +207,7 @@ macro_rules! wasi_file_impl { // lifetime of the AsyncFd. use std::os::unix::io::AsRawFd; use tokio::io::{unix::AsyncFd, Interest}; - let rawfd = self.0.as_fd().as_raw_fd(); + let rawfd = self.0.borrow().as_fd().as_raw_fd(); match AsyncFd::with_interest(rawfd, Interest::WRITABLE) { Ok(asyncfd) => { let _ = asyncfd.writable().await?; @@ -221,7 +222,7 @@ macro_rules! wasi_file_impl { } } - async fn sock_accept(&mut self, fdflags: FdFlags) -> Result, Error> { + async fn sock_accept(&self, fdflags: FdFlags) -> Result, Error> { block_on_dummy_executor(|| self.0.sock_accept(fdflags)) } } @@ -229,7 +230,7 @@ macro_rules! wasi_file_impl { impl AsRawHandleOrSocket for $ty { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { - self.0.as_raw_handle_or_socket() + self.0.borrow().as_raw_handle_or_socket() } } }; diff --git a/crates/wasi-common/tokio/src/lib.rs b/crates/wasi-common/tokio/src/lib.rs index 577c6e2e1e38..1c7a1decb300 100644 --- a/crates/wasi-common/tokio/src/lib.rs +++ b/crates/wasi-common/tokio/src/lib.rs @@ -62,15 +62,15 @@ impl WasiCtxBuilder { } Ok(self) } - pub fn stdin(mut self, f: Box) -> Self { + pub fn stdin(self, f: Box) -> Self { self.0.set_stdin(f); self } - pub fn stdout(mut self, f: Box) -> Self { + pub fn stdout(self, f: Box) -> Self { self.0.set_stdout(f); self } - pub fn stderr(mut self, f: Box) -> Self { + pub fn stderr(self, f: Box) -> Self { self.0.set_stderr(f); self } @@ -87,7 +87,7 @@ impl WasiCtxBuilder { self.inherit_stdin().inherit_stdout().inherit_stderr() } pub fn preopened_dir( - mut self, + self, dir: cap_std::fs::Dir, guest_path: impl AsRef, ) -> Result { @@ -95,7 +95,7 @@ impl WasiCtxBuilder { self.0.push_preopened_dir(dir, guest_path)?; Ok(self) } - pub fn preopened_socket(mut self, fd: u32, socket: impl Into) -> Result { + pub fn preopened_socket(self, fd: u32, socket: impl Into) -> Result { let socket: Socket = socket.into(); let file: Box = socket.into(); diff --git a/crates/wasi-common/tokio/src/sched/unix.rs b/crates/wasi-common/tokio/src/sched/unix.rs index 5ca3b1200d09..4fd47d1cb248 100644 --- a/crates/wasi-common/tokio/src/sched/unix.rs +++ b/crates/wasi-common/tokio/src/sched/unix.rs @@ -63,7 +63,6 @@ pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> { f.complete( f.file .num_ready_bytes() - .await .map_err(|e| e.context("read num_ready_bytes"))?, RwEventFlags::empty(), ); diff --git a/crates/wasi-common/tokio/tests/poll_oneoff.rs b/crates/wasi-common/tokio/tests/poll_oneoff.rs index abaacef891fc..9ba85f6deeb5 100644 --- a/crates/wasi-common/tokio/tests/poll_oneoff.rs +++ b/crates/wasi-common/tokio/tests/poll_oneoff.rs @@ -20,7 +20,7 @@ async fn empty_file_readable() -> Result<(), Error> { let d = workspace.open_dir("d").context("open dir")?; let d = Dir::from_cap_std(d); - let mut f = d + let f = d .open_file(false, "f", OFlags::CREATE, false, true, FdFlags::empty()) .await .context("create writable file f")?;