diff --git a/crates/wasi-common/cap-std-sync/src/dir.rs b/crates/wasi-common/cap-std-sync/src/dir.rs index 2552787900..13e8391452 100644 --- a/crates/wasi-common/cap-std-sync/src/dir.rs +++ b/crates/wasi-common/cap-std-sync/src/dir.rs @@ -17,11 +17,12 @@ impl Dir { } } +#[wiggle::async_trait] impl WasiDir for Dir { fn as_any(&self) -> &dyn Any { self } - fn open_file( + async fn open_file( &self, symlink_follow: bool, path: &str, @@ -84,7 +85,7 @@ impl WasiDir for Dir { Ok(Box::new(File::from_cap_std(f))) } - fn open_dir(&self, symlink_follow: bool, path: &str) -> Result, Error> { + async fn open_dir(&self, symlink_follow: bool, path: &str) -> Result, Error> { let d = if symlink_follow { self.0.open_dir(Path::new(path))? } else { @@ -93,11 +94,11 @@ impl WasiDir for Dir { Ok(Box::new(Dir::from_cap_std(d))) } - fn create_dir(&self, path: &str) -> Result<(), Error> { + async fn create_dir(&self, path: &str) -> Result<(), Error> { self.0.create_dir(Path::new(path))?; Ok(()) } - fn readdir( + async fn readdir( &self, cursor: ReaddirCursor, ) -> Result>>, Error> { @@ -146,24 +147,24 @@ impl WasiDir for Dir { Ok(Box::new(rd)) } - fn symlink(&self, src_path: &str, dest_path: &str) -> Result<(), Error> { + async fn symlink(&self, src_path: &str, dest_path: &str) -> Result<(), Error> { self.0.symlink(src_path, dest_path)?; Ok(()) } - fn remove_dir(&self, path: &str) -> Result<(), Error> { + async fn remove_dir(&self, path: &str) -> Result<(), Error> { self.0.remove_dir(Path::new(path))?; Ok(()) } - fn unlink_file(&self, path: &str) -> Result<(), Error> { + async fn unlink_file(&self, path: &str) -> Result<(), Error> { self.0.remove_file_or_symlink(Path::new(path))?; Ok(()) } - fn read_link(&self, path: &str) -> Result { + async fn read_link(&self, path: &str) -> Result { let link = self.0.read_link(Path::new(path))?; Ok(link) } - fn get_filestat(&self) -> Result { + async fn get_filestat(&self) -> Result { let meta = self.0.dir_metadata()?; Ok(Filestat { device_id: meta.dev(), @@ -176,7 +177,11 @@ impl WasiDir for Dir { ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None), }) } - fn get_path_filestat(&self, path: &str, follow_symlinks: bool) -> Result { + async fn get_path_filestat( + &self, + path: &str, + follow_symlinks: bool, + ) -> Result { let meta = if follow_symlinks { self.0.metadata(Path::new(path))? } else { @@ -193,7 +198,12 @@ impl WasiDir for Dir { ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None), }) } - fn rename(&self, src_path: &str, dest_dir: &dyn WasiDir, dest_path: &str) -> Result<(), Error> { + async fn rename( + &self, + src_path: &str, + dest_dir: &dyn WasiDir, + dest_path: &str, + ) -> Result<(), Error> { let dest_dir = dest_dir .as_any() .downcast_ref::() @@ -202,7 +212,7 @@ impl WasiDir for Dir { .rename(Path::new(src_path), &dest_dir.0, Path::new(dest_path))?; Ok(()) } - fn hard_link( + async fn hard_link( &self, src_path: &str, target_dir: &dyn WasiDir, @@ -217,7 +227,7 @@ impl WasiDir for Dir { self.0.hard_link(src_path, &target_dir.0, target_path)?; Ok(()) } - fn set_times( + async fn set_times( &self, path: &str, atime: Option, @@ -261,7 +271,7 @@ mod test { let preopen_dir = unsafe { cap_std::fs::Dir::open_ambient_dir(tempdir.path()) } .expect("open ambient temporary dir"); let preopen_dir = Dir::from_cap_std(preopen_dir); - wasi_common::WasiDir::open_dir(&preopen_dir, false, ".") + run(wasi_common::WasiDir::open_dir(&preopen_dir, false, ".")) .expect("open the same directory via WasiDir abstraction"); } @@ -275,9 +285,8 @@ mod test { fn readdir_into_map(dir: &dyn WasiDir) -> HashMap { let mut out = HashMap::new(); - for readdir_result in dir - .readdir(ReaddirCursor::from(0)) - .expect("readdir succeeds") + for readdir_result in + run(dir.readdir(ReaddirCursor::from(0))).expect("readdir succeeds") { let entity = readdir_result.expect("readdir entry is valid"); out.insert(entity.name.clone(), entity); @@ -303,16 +312,15 @@ mod test { assert!(entities.get(".").is_some()); assert!(entities.get("..").is_some()); - preopen_dir - .open_file( - false, - "file1", - OFlags::CREATE, - true, - false, - FdFlags::empty(), - ) - .expect("create file1"); + run(preopen_dir.open_file( + false, + "file1", + OFlags::CREATE, + true, + false, + FdFlags::empty(), + )) + .expect("create file1"); let entities = readdir_into_map(&preopen_dir); assert_eq!(entities.len(), 3, "should be ., .., file1 {:?}", entities); @@ -329,4 +337,41 @@ mod test { FileType::RegularFile ); } + + fn run(future: F) -> F::Output { + use std::pin::Pin; + use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; + + let mut f = Pin::from(Box::new(future)); + let waker = dummy_waker(); + let mut cx = Context::from_waker(&waker); + match f.as_mut().poll(&mut cx) { + Poll::Ready(val) => return val, + Poll::Pending => { + panic!("Cannot wait on pending future: must enable wiggle \"async\" future and execute on an async Store") + } + } + + fn dummy_waker() -> Waker { + return unsafe { Waker::from_raw(clone(5 as *const _)) }; + + unsafe fn clone(ptr: *const ()) -> RawWaker { + assert_eq!(ptr as usize, 5); + const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); + RawWaker::new(ptr, &VTABLE) + } + + unsafe fn wake(ptr: *const ()) { + assert_eq!(ptr as usize, 5); + } + + unsafe fn wake_by_ref(ptr: *const ()) { + assert_eq!(ptr as usize, 5); + } + + unsafe fn drop(ptr: *const ()) { + assert_eq!(ptr as usize, 5); + } + } + } } diff --git a/crates/wasi-common/cap-std-sync/src/file.rs b/crates/wasi-common/cap-std-sync/src/file.rs index f89a090ea1..ba9ff2743a 100644 --- a/crates/wasi-common/cap-std-sync/src/file.rs +++ b/crates/wasi-common/cap-std-sync/src/file.rs @@ -20,27 +20,28 @@ impl File { } } +#[wiggle::async_trait] impl WasiFile for File { fn as_any(&self) -> &dyn Any { self } - fn datasync(&self) -> Result<(), Error> { + async fn datasync(&self) -> Result<(), Error> { self.0.sync_data()?; Ok(()) } - fn sync(&self) -> Result<(), Error> { + async fn sync(&self) -> Result<(), Error> { self.0.sync_all()?; Ok(()) } - fn get_filetype(&self) -> Result { + async fn get_filetype(&self) -> Result { let meta = self.0.metadata()?; Ok(filetype_from(&meta.file_type())) } - fn get_fdflags(&self) -> Result { + async fn get_fdflags(&self) -> Result { let fdflags = self.0.get_fd_flags()?; Ok(from_sysif_fdflags(fdflags)) } - fn set_fdflags(&mut self, fdflags: FdFlags) -> Result<(), Error> { + async fn set_fdflags(&mut self, fdflags: FdFlags) -> Result<(), Error> { if fdflags.intersects( wasi_common::file::FdFlags::DSYNC | wasi_common::file::FdFlags::SYNC @@ -50,7 +51,7 @@ impl WasiFile for File { } Ok(self.0.set_fd_flags(to_sysif_fdflags(fdflags))?) } - fn get_filestat(&self) -> Result { + async fn get_filestat(&self) -> Result { let meta = self.0.metadata()?; Ok(Filestat { device_id: meta.dev(), @@ -63,19 +64,19 @@ impl WasiFile for File { ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None), }) } - fn set_filestat_size(&self, size: u64) -> Result<(), Error> { + async fn set_filestat_size(&self, size: u64) -> Result<(), Error> { self.0.set_len(size)?; Ok(()) } - fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> { + async fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> { self.0.advise(offset, len, convert_advice(advice))?; Ok(()) } - fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> { + async fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> { self.0.allocate(offset, len)?; Ok(()) } - fn set_times( + async fn set_times( &self, atime: Option, mtime: Option, @@ -84,30 +85,38 @@ impl WasiFile for File { .set_times(convert_systimespec(atime), convert_systimespec(mtime))?; Ok(()) } - fn read_vectored(&self, bufs: &mut [io::IoSliceMut]) -> Result { + async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result { let n = self.0.read_vectored(bufs)?; Ok(n.try_into()?) } - fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut], offset: u64) -> Result { + async fn read_vectored_at<'a>( + &self, + bufs: &mut [io::IoSliceMut<'a>], + offset: u64, + ) -> Result { let n = self.0.read_vectored_at(bufs, offset)?; Ok(n.try_into()?) } - fn write_vectored(&self, bufs: &[io::IoSlice]) -> Result { + async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result { let n = self.0.write_vectored(bufs)?; Ok(n.try_into()?) } - fn write_vectored_at(&self, bufs: &[io::IoSlice], offset: u64) -> Result { + async fn write_vectored_at<'a>( + &self, + bufs: &[io::IoSlice<'a>], + offset: u64, + ) -> Result { let n = self.0.write_vectored_at(bufs, offset)?; Ok(n.try_into()?) } - fn seek(&self, pos: std::io::SeekFrom) -> Result { + async fn seek(&self, pos: std::io::SeekFrom) -> Result { Ok(self.0.seek(pos)?) } - fn peek(&self, buf: &mut [u8]) -> Result { + async fn peek(&self, buf: &mut [u8]) -> Result { let n = self.0.peek(buf)?; Ok(n.try_into()?) } - fn num_ready_bytes(&self) -> Result { + async fn num_ready_bytes(&self) -> Result { Ok(self.0.num_ready_bytes()?) } } 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 eeb9c9c0a7..37fbbc1c0f 100644 --- a/crates/wasi-common/cap-std-sync/src/sched/unix.rs +++ b/crates/wasi-common/cap-std-sync/src/sched/unix.rs @@ -79,7 +79,7 @@ impl WasiSched for SyncSched { if let Some(revents) = pollfd.revents() { let (nbytes, rwsub) = match rwsub { Subscription::Read(sub) => { - let ready = sub.file.num_ready_bytes()?; + let ready = sub.file.num_ready_bytes().await?; (std::cmp::max(ready, 1), sub) } Subscription::Write(sub) => (0, sub), diff --git a/crates/wasi-common/cap-std-sync/src/stdio.rs b/crates/wasi-common/cap-std-sync/src/stdio.rs index 92a76d47ff..d4d515cfeb 100644 --- a/crates/wasi-common/cap-std-sync/src/stdio.rs +++ b/crates/wasi-common/cap-std-sync/src/stdio.rs @@ -22,31 +22,32 @@ pub fn stdin() -> Stdin { Stdin(std::io::stdin()) } +#[wiggle::async_trait] impl WasiFile for Stdin { fn as_any(&self) -> &dyn Any { self } - fn datasync(&self) -> Result<(), Error> { + async fn datasync(&self) -> Result<(), Error> { Ok(()) } - fn sync(&self) -> Result<(), Error> { + async fn sync(&self) -> Result<(), Error> { Ok(()) } - fn get_filetype(&self) -> Result { + async fn get_filetype(&self) -> Result { Ok(FileType::Unknown) } - fn get_fdflags(&self) -> Result { + async fn get_fdflags(&self) -> Result { Ok(FdFlags::empty()) } - fn set_fdflags(&mut self, _fdflags: FdFlags) -> Result<(), Error> { + async fn set_fdflags(&mut self, _fdflags: FdFlags) -> Result<(), Error> { Err(Error::badf()) } - fn get_filestat(&self) -> Result { + async fn get_filestat(&self) -> Result { let meta = self.0.as_file_view().metadata()?; Ok(Filestat { device_id: 0, inode: 0, - filetype: self.get_filetype()?, + filetype: self.get_filetype().await?, nlink: 0, size: meta.len(), atim: meta.accessed().ok(), @@ -54,35 +55,43 @@ impl WasiFile for Stdin { ctim: meta.created().ok(), }) } - fn set_filestat_size(&self, _size: u64) -> Result<(), Error> { + async fn set_filestat_size(&self, _size: u64) -> Result<(), Error> { Err(Error::badf()) } - fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> { + async fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> { Err(Error::badf()) } - fn allocate(&self, _offset: u64, _len: u64) -> Result<(), Error> { + async fn allocate(&self, _offset: u64, _len: u64) -> Result<(), Error> { Err(Error::badf()) } - fn read_vectored(&self, bufs: &mut [io::IoSliceMut]) -> Result { + async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result { let n = self.0.as_file_view().read_vectored(bufs)?; Ok(n.try_into().map_err(|_| Error::range())?) } - fn read_vectored_at(&self, _bufs: &mut [io::IoSliceMut], _offset: u64) -> Result { + async fn read_vectored_at<'a>( + &self, + _bufs: &mut [io::IoSliceMut<'a>], + _offset: u64, + ) -> Result { Err(Error::seek_pipe()) } - fn write_vectored(&self, _bufs: &[io::IoSlice]) -> Result { + async fn write_vectored<'a>(&self, _bufs: &[io::IoSlice<'a>]) -> Result { Err(Error::badf()) } - fn write_vectored_at(&self, _bufs: &[io::IoSlice], _offset: u64) -> Result { + async fn write_vectored_at<'a>( + &self, + _bufs: &[io::IoSlice<'a>], + _offset: u64, + ) -> Result { Err(Error::badf()) } - fn seek(&self, _pos: std::io::SeekFrom) -> Result { + async fn seek(&self, _pos: std::io::SeekFrom) -> Result { Err(Error::seek_pipe()) } - fn peek(&self, _buf: &mut [u8]) -> Result { + async fn peek(&self, _buf: &mut [u8]) -> Result { Err(Error::seek_pipe()) } - fn set_times( + async fn set_times( &self, atime: Option, mtime: Option, @@ -91,7 +100,7 @@ impl WasiFile for Stdin { .set_times(convert_systimespec(atime), convert_systimespec(mtime))?; Ok(()) } - fn num_ready_bytes(&self) -> Result { + async fn num_ready_bytes(&self) -> Result { Ok(self.0.num_ready_bytes()?) } } @@ -110,31 +119,32 @@ impl AsRawFd for Stdin { macro_rules! wasi_file_write_impl { ($ty:ty) => { + #[wiggle::async_trait] impl WasiFile for $ty { fn as_any(&self) -> &dyn Any { self } - fn datasync(&self) -> Result<(), Error> { + async fn datasync(&self) -> Result<(), Error> { Ok(()) } - fn sync(&self) -> Result<(), Error> { + async fn sync(&self) -> Result<(), Error> { Ok(()) } - fn get_filetype(&self) -> Result { + async fn get_filetype(&self) -> Result { Ok(FileType::Unknown) } - fn get_fdflags(&self) -> Result { + async fn get_fdflags(&self) -> Result { Ok(FdFlags::APPEND) } - fn set_fdflags(&mut self, _fdflags: FdFlags) -> Result<(), Error> { + async fn set_fdflags(&mut self, _fdflags: FdFlags) -> Result<(), Error> { Err(Error::badf()) } - fn get_filestat(&self) -> Result { + async fn get_filestat(&self) -> Result { let meta = self.0.as_file_view().metadata()?; Ok(Filestat { device_id: 0, inode: 0, - filetype: self.get_filetype()?, + filetype: self.get_filetype().await?, nlink: 0, size: meta.len(), atim: meta.accessed().ok(), @@ -142,39 +152,46 @@ macro_rules! wasi_file_write_impl { ctim: meta.created().ok(), }) } - fn set_filestat_size(&self, _size: u64) -> Result<(), Error> { + async fn set_filestat_size(&self, _size: u64) -> Result<(), Error> { Err(Error::badf()) } - fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> { + async fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> { Err(Error::badf()) } - fn allocate(&self, _offset: u64, _len: u64) -> Result<(), Error> { + async fn allocate(&self, _offset: u64, _len: u64) -> Result<(), Error> { Err(Error::badf()) } - fn read_vectored(&self, _bufs: &mut [io::IoSliceMut]) -> Result { - Err(Error::badf()) - } - fn read_vectored_at( + async fn read_vectored<'a>( &self, - _bufs: &mut [io::IoSliceMut], + _bufs: &mut [io::IoSliceMut<'a>], + ) -> Result { + Err(Error::badf()) + } + async fn read_vectored_at<'a>( + &self, + _bufs: &mut [io::IoSliceMut<'a>], _offset: u64, ) -> Result { Err(Error::badf()) } - fn write_vectored(&self, bufs: &[io::IoSlice]) -> Result { + async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result { let n = self.0.as_file_view().write_vectored(bufs)?; Ok(n.try_into().map_err(|c| Error::range().context(c))?) } - fn write_vectored_at(&self, _bufs: &[io::IoSlice], _offset: u64) -> Result { + async fn write_vectored_at<'a>( + &self, + _bufs: &[io::IoSlice<'a>], + _offset: u64, + ) -> Result { Err(Error::seek_pipe()) } - fn seek(&self, _pos: std::io::SeekFrom) -> Result { + async fn seek(&self, _pos: std::io::SeekFrom) -> Result { Err(Error::seek_pipe()) } - fn peek(&self, _buf: &mut [u8]) -> Result { + async fn peek(&self, _buf: &mut [u8]) -> Result { Err(Error::badf()) } - fn set_times( + async fn set_times( &self, atime: Option, mtime: Option, @@ -183,7 +200,7 @@ macro_rules! wasi_file_write_impl { .set_times(convert_systimespec(atime), convert_systimespec(mtime))?; Ok(()) } - fn num_ready_bytes(&self) -> Result { + async fn num_ready_bytes(&self) -> Result { Ok(0) } }