Skip to content

Commit

Permalink
WIP: use Arc<Self> in WasiFile and associated traits
Browse files Browse the repository at this point in the history
This is an attempt to apply @alexcrichton's comment
[here](bytecodealliance#5326 (comment))
which proposed using `self: &Arc<Self>` in the `WasiFile` trait. This
change, made as `self: Arc<Self>` here due to Rust method receiver
limitations, affects many locations. E.g., `WasiDir` also needs to start
using `Arc<Self>`, etc. This results in a slew of errors at all the use
locations. This commit fixes up many of these but is marked "WIP" since
not all are fixed; the latest challenge is deciding what the signature
of `WasiFile::pollable` should be when the switch to `Arc<Self>` is
made.
  • Loading branch information
abrown committed Dec 20, 2022
1 parent 09487b0 commit 0cb050f
Show file tree
Hide file tree
Showing 13 changed files with 273 additions and 265 deletions.
43 changes: 24 additions & 19 deletions crates/wasi-common/cap-std-sync/src/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::file::{filetype_from, File};
use cap_fs_ext::{DirEntryExt, DirExt, MetadataExt, SystemTimeSpec};
use std::any::Any;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use system_interface::fs::GetSetFdFlags;
use wasi_common::{
dir::{ReaddirCursor, ReaddirEntity, WasiDir},
Expand Down Expand Up @@ -109,33 +110,37 @@ impl Dir {

#[async_trait::async_trait]
impl WasiDir for Dir {
fn as_any(&self) -> &dyn Any {
fn as_any(self: Arc<Self>) -> Arc<dyn Any> {
self
}
async fn open_file(
&self,
self: Arc<Self>,
symlink_follow: bool,
path: &str,
oflags: OFlags,
read: bool,
write: bool,
fdflags: FdFlags,
) -> Result<Box<dyn WasiFile>, Error> {
) -> Result<Arc<dyn WasiFile>, Error> {
let f = self.open_file_(symlink_follow, path, oflags, read, write, fdflags)?;
Ok(Box::new(f))
Ok(Arc::new(f))
}

async fn open_dir(&self, symlink_follow: bool, path: &str) -> Result<Box<dyn WasiDir>, Error> {
async fn open_dir(
self: Arc<Self>,
symlink_follow: bool,
path: &str,
) -> Result<Arc<dyn WasiDir>, Error> {
let d = self.open_dir_(symlink_follow, path)?;
Ok(Box::new(d))
Ok(Arc::new(d))
}

async fn create_dir(&self, path: &str) -> Result<(), Error> {
async fn create_dir(self: Arc<Self>, path: &str) -> Result<(), Error> {
self.0.create_dir(Path::new(path))?;
Ok(())
}
async fn readdir(
&self,
self: Arc<Self>,
cursor: ReaddirCursor,
) -> Result<Box<dyn Iterator<Item = Result<ReaddirEntity, Error>> + Send>, Error> {
// We need to keep a full-fidelity io Error around to check for a special failure mode
Expand Down Expand Up @@ -216,24 +221,24 @@ impl WasiDir for Dir {
Ok(Box::new(rd))
}

async fn symlink(&self, src_path: &str, dest_path: &str) -> Result<(), Error> {
async fn symlink(self: Arc<Self>, src_path: &str, dest_path: &str) -> Result<(), Error> {
self.0.symlink(src_path, dest_path)?;
Ok(())
}
async fn remove_dir(&self, path: &str) -> Result<(), Error> {
async fn remove_dir(self: Arc<Self>, path: &str) -> Result<(), Error> {
self.0.remove_dir(Path::new(path))?;
Ok(())
}

async fn unlink_file(&self, path: &str) -> Result<(), Error> {
async fn unlink_file(self: Arc<Self>, path: &str) -> Result<(), Error> {
self.0.remove_file_or_symlink(Path::new(path))?;
Ok(())
}
async fn read_link(&self, path: &str) -> Result<PathBuf, Error> {
async fn read_link(self: Arc<Self>, path: &str) -> Result<PathBuf, Error> {
let link = self.0.read_link(Path::new(path))?;
Ok(link)
}
async fn get_filestat(&self) -> Result<Filestat, Error> {
async fn get_filestat(self: Arc<Self>) -> Result<Filestat, Error> {
let meta = self.0.dir_metadata()?;
Ok(Filestat {
device_id: meta.dev(),
Expand All @@ -247,7 +252,7 @@ impl WasiDir for Dir {
})
}
async fn get_path_filestat(
&self,
self: Arc<Self>,
path: &str,
follow_symlinks: bool,
) -> Result<Filestat, Error> {
Expand All @@ -268,9 +273,9 @@ impl WasiDir for Dir {
})
}
async fn rename(
&self,
self: Arc<Self>,
src_path: &str,
dest_dir: &dyn WasiDir,
dest_dir: Arc<dyn WasiDir>,
dest_path: &str,
) -> Result<(), Error> {
let dest_dir = dest_dir
Expand All @@ -280,9 +285,9 @@ impl WasiDir for Dir {
self.rename_(src_path, dest_dir, dest_path)
}
async fn hard_link(
&self,
self: Arc<Self>,
src_path: &str,
target_dir: &dyn WasiDir,
target_dir: Arc<dyn WasiDir>,
target_path: &str,
) -> Result<(), Error> {
let target_dir = target_dir
Expand All @@ -292,7 +297,7 @@ impl WasiDir for Dir {
self.hard_link_(src_path, target_dir, target_path)
}
async fn set_times(
&self,
self: Arc<Self>,
path: &str,
atime: Option<wasi_common::SystemTimeSpec>,
mtime: Option<wasi_common::SystemTimeSpec>,
Expand Down
127 changes: 49 additions & 78 deletions crates/wasi-common/cap-std-sync/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,90 +24,63 @@ 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<cap_std::fs::File>);
pub struct File(cap_std::fs::File);

impl File {
pub fn from_cap_std(file: cap_std::fs::File) -> Self {
File(RwLock::new(file))
}

pub fn borrow(&self) -> BorrowedFile {
BorrowedFile(self.0.read().unwrap())
File(file)
}
}

#[async_trait::async_trait]
impl WasiFile for File {
fn as_any(&self) -> &dyn Any {
fn as_any(self: Arc<Self>) -> Arc<dyn Any> {
self
}

#[cfg(unix)]
fn pollable(&self) -> Option<Arc<dyn AsFd + '_>> {
Some(Arc::new(self.borrow()))
fn pollable(self: Arc<Self>) -> Option<Arc<dyn AsFd>> {
Some(Arc::new(self.0.as_fd()))
}

#[cfg(windows)]
fn pollable(&self) -> Option<Arc<dyn AsRawHandleOrSocket + '_>> {
Some(Arc::new(BorrowedFile(self.0.read().unwrap())))
fn pollable(self: Arc<Self>) -> Option<Arc<dyn AsRawHandleOrSocket>> {
Some(Arc::new(BorrowedFile(self.0)))
}

async fn datasync(&self) -> Result<(), Error> {
self.0.read().unwrap().sync_data()?;
async fn datasync(self: Arc<Self>) -> Result<(), Error> {
self.0.sync_data()?;
Ok(())
}
async fn sync(&self) -> Result<(), Error> {
self.0.read().unwrap().sync_all()?;
async fn sync(self: Arc<Self>) -> Result<(), Error> {
self.0.sync_all()?;
Ok(())
}
async fn get_filetype(&self) -> Result<FileType, Error> {
let meta = self.0.read().unwrap().metadata()?;
async fn get_filetype(self: Arc<Self>) -> Result<FileType, Error> {
let meta = self.0.metadata()?;
Ok(filetype_from(&meta.file_type()))
}
async fn get_fdflags(&self) -> Result<FdFlags, Error> {
let file = self.0.read().unwrap();
let fdflags = get_fd_flags(&*file)?;
async fn get_fdflags(self: Arc<Self>) -> Result<FdFlags, Error> {
let fdflags = get_fd_flags(self.0)?;
Ok(fdflags)
}
async fn set_fdflags(&self, fdflags: FdFlags) -> Result<(), Error> {
async fn set_fdflags(mut self: Arc<Self>, fdflags: FdFlags) -> Result<(), Error> {
if fdflags.intersects(
wasi_common::file::FdFlags::DSYNC
| wasi_common::file::FdFlags::SYNC
| wasi_common::file::FdFlags::RSYNC,
) {
return Err(Error::invalid_argument().context("cannot set DSYNC, SYNC, or RSYNC flag"));
}
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)?;
let set_fd_flags = self.0.new_set_fd_flags(to_sysif_fdflags(fdflags))?;
Arc::get_mut(&mut self)
.unwrap()
.0
.set_fd_flags(set_fd_flags)?;
Ok(())
}
async fn get_filestat(&self) -> Result<Filestat, Error> {
let meta = self.0.read().unwrap().metadata()?;
async fn get_filestat(self: Arc<Self>) -> Result<Filestat, Error> {
let meta = self.0.metadata()?;
Ok(Filestat {
device_id: meta.dev(),
inode: meta.ino(),
Expand All @@ -119,68 +92,66 @@ impl WasiFile for File {
ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None),
})
}
async fn set_filestat_size(&self, size: u64) -> Result<(), Error> {
self.0.read().unwrap().set_len(size)?;
async fn set_filestat_size(self: Arc<Self>, size: u64) -> Result<(), Error> {
self.0.set_len(size)?;
Ok(())
}
async fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
self.0
.read()
.unwrap()
.advise(offset, len, convert_advice(advice))?;
async fn advise(self: Arc<Self>, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
self.0.advise(offset, len, convert_advice(advice))?;
Ok(())
}
async fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> {
self.0.read().unwrap().allocate(offset, len)?;
async fn allocate(self: Arc<Self>, offset: u64, len: u64) -> Result<(), Error> {
self.0.allocate(offset, len)?;
Ok(())
}
async fn set_times(
&self,
self: Arc<Self>,
atime: Option<wasi_common::SystemTimeSpec>,
mtime: Option<wasi_common::SystemTimeSpec>,
) -> Result<(), Error> {
self.0
.read()
.unwrap()
.set_times(convert_systimespec(atime), convert_systimespec(mtime))?;
Ok(())
}
async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result<u64, Error> {
let n = self.0.read().unwrap().read_vectored(bufs)?;
async fn read_vectored<'a>(
self: Arc<Self>,
bufs: &mut [io::IoSliceMut<'a>],
) -> Result<u64, Error> {
let n = self.0.read_vectored(bufs)?;
Ok(n.try_into()?)
}
async fn read_vectored_at<'a>(
&self,
self: Arc<Self>,
bufs: &mut [io::IoSliceMut<'a>],
offset: u64,
) -> Result<u64, Error> {
let n = self.0.read().unwrap().read_vectored_at(bufs, offset)?;
let n = self.0.read_vectored_at(bufs, offset)?;
Ok(n.try_into()?)
}
async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
let n = self.0.read().unwrap().write_vectored(bufs)?;
async fn write_vectored<'a>(self: Arc<Self>, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
let n = self.0.write_vectored(bufs)?;
Ok(n.try_into()?)
}
async fn write_vectored_at<'a>(
&self,
self: Arc<Self>,
bufs: &[io::IoSlice<'a>],
offset: u64,
) -> Result<u64, Error> {
let n = self.0.read().unwrap().write_vectored_at(bufs, offset)?;
let n = self.0.write_vectored_at(bufs, offset)?;
Ok(n.try_into()?)
}
async fn seek(&self, pos: std::io::SeekFrom) -> Result<u64, Error> {
Ok(self.0.read().unwrap().seek(pos)?)
async fn seek(self: Arc<Self>, pos: std::io::SeekFrom) -> Result<u64, Error> {
Ok(self.0.seek(pos)?)
}
async fn peek(&self, buf: &mut [u8]) -> Result<u64, Error> {
let n = self.0.read().unwrap().peek(buf)?;
async fn peek(self: Arc<Self>, buf: &mut [u8]) -> Result<u64, Error> {
let n = self.0.peek(buf)?;
Ok(n.try_into()?)
}
fn num_ready_bytes(&self) -> Result<u64, Error> {
Ok(self.0.read().unwrap().num_ready_bytes()?)
fn num_ready_bytes(self: Arc<Self>) -> Result<u64, Error> {
Ok(self.0.num_ready_bytes()?)
}
fn isatty(&self) -> bool {
self.0.read().unwrap().is_terminal()
fn isatty(self: Arc<Self>) -> bool {
self.0.is_terminal()
}
}

Expand Down
18 changes: 9 additions & 9 deletions crates/wasi-common/cap-std-sync/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub use sched::sched_ctx;

use crate::net::Socket;
use cap_rand::{Rng, RngCore, SeedableRng};
use std::path::Path;
use std::{path::Path, sync::Arc};
use wasi_common::{file::FileCaps, table::Table, Error, WasiCtx, WasiFile};

pub struct WasiCtxBuilder(WasiCtx);
Expand Down Expand Up @@ -94,38 +94,38 @@ impl WasiCtxBuilder {
}
Ok(self)
}
pub fn stdin(self, f: Box<dyn WasiFile>) -> Self {
pub fn stdin(self, f: Arc<dyn WasiFile>) -> Self {
self.0.set_stdin(f);
self
}
pub fn stdout(self, f: Box<dyn WasiFile>) -> Self {
pub fn stdout(self, f: Arc<dyn WasiFile>) -> Self {
self.0.set_stdout(f);
self
}
pub fn stderr(self, f: Box<dyn WasiFile>) -> Self {
pub fn stderr(self, f: Arc<dyn WasiFile>) -> Self {
self.0.set_stderr(f);
self
}
pub fn inherit_stdin(self) -> Self {
self.stdin(Box::new(crate::stdio::stdin()))
self.stdin(Arc::new(crate::stdio::stdin()))
}
pub fn inherit_stdout(self) -> Self {
self.stdout(Box::new(crate::stdio::stdout()))
self.stdout(Arc::new(crate::stdio::stdout()))
}
pub fn inherit_stderr(self) -> Self {
self.stderr(Box::new(crate::stdio::stderr()))
self.stderr(Arc::new(crate::stdio::stderr()))
}
pub fn inherit_stdio(self) -> Self {
self.inherit_stdin().inherit_stdout().inherit_stderr()
}
pub fn preopened_dir(self, dir: Dir, guest_path: impl AsRef<Path>) -> Result<Self, Error> {
let dir = Box::new(crate::dir::Dir::from_cap_std(dir));
let dir = Arc::new(crate::dir::Dir::from_cap_std(dir));
self.0.push_preopened_dir(dir, guest_path)?;
Ok(self)
}
pub fn preopened_socket(self, fd: u32, socket: impl Into<Socket>) -> Result<Self, Error> {
let socket: Socket = socket.into();
let file: Box<dyn WasiFile> = socket.into();
let file: Arc<dyn WasiFile> = socket.into();

let caps = FileCaps::FDSTAT_SET_FLAGS
| FileCaps::FILESTAT_GET
Expand Down
Loading

0 comments on commit 0cb050f

Please sign in to comment.