Skip to content

Commit af02e20

Browse files
committed
feat: remove mutability from the WasiCtx Table
This patch adds interior mutability to the WasiCtx Table and the Table elements. Major pain points: * `File` only needs `RwLock<cap_std::fs::File>` to implement `File::set_fdflags()` on Windows, because of [1] * Because `File` needs a `RwLock` and `RwLock*Guard` cannot be hold across an `.await`, The `async` from `async fn num_ready_bytes(&self)` had to be removed * Because `File` needs a `RwLock` and `RwLock*Guard` cannot be dereferenced in `pollable`, the signature of `fn pollable(&self) -> Option<rustix::fd::BorrowedFd>` changed to `fn pollable(&self) -> Option<Arc<dyn AsFd + '_>>` [1] https://github.com/bytecodealliance/system-interface/blob/da238e324e752033f315f09c082ad9ce35d42696/src/fs/fd_flags.rs#L210-L217 Signed-off-by: Harald Hoyer <[email protected]>
1 parent 28cf995 commit af02e20

File tree

17 files changed

+490
-419
lines changed

17 files changed

+490
-419
lines changed

crates/wasi-common/cap-std-sync/src/file.rs

+89-71
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use is_terminal::IsTerminal;
55
use std::any::Any;
66
use std::convert::TryInto;
77
use std::io;
8+
use std::sync::{Arc, RwLock, RwLockReadGuard};
89
use system_interface::{
910
fs::{FileIoExt, GetSetFdFlags},
1011
io::{IoExt, ReadReady},
@@ -14,11 +15,48 @@ use wasi_common::{
1415
Error, ErrorExt,
1516
};
1617

17-
pub struct File(cap_std::fs::File);
18+
#[cfg(unix)]
19+
use io_lifetimes::{AsFd, BorrowedFd};
20+
21+
#[cfg(windows)]
22+
use io_lifetimes::{AsHandle, BorrowedHandle};
23+
24+
#[cfg(windows)]
25+
use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket};
26+
27+
pub struct BorrowedFile<'a>(RwLockReadGuard<'a, cap_std::fs::File>);
28+
29+
#[cfg(unix)]
30+
impl AsFd for BorrowedFile<'_> {
31+
fn as_fd(&self) -> BorrowedFd<'_> {
32+
self.0.as_fd()
33+
}
34+
}
35+
36+
#[cfg(windows)]
37+
impl AsHandle for BorrowedFile<'_> {
38+
fn as_handle(&self) -> BorrowedHandle<'_> {
39+
self.0.as_handle()
40+
}
41+
}
42+
43+
#[cfg(windows)]
44+
impl AsRawHandleOrSocket for BorrowedFile<'_> {
45+
#[inline]
46+
fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
47+
self.0.as_raw_handle_or_socket()
48+
}
49+
}
50+
51+
pub struct File(RwLock<cap_std::fs::File>);
1852

1953
impl File {
2054
pub fn from_cap_std(file: cap_std::fs::File) -> Self {
21-
File(file)
55+
File(RwLock::new(file))
56+
}
57+
58+
pub fn borrow(&self) -> BorrowedFile {
59+
BorrowedFile(self.0.read().unwrap())
2260
}
2361
}
2462

@@ -27,45 +65,49 @@ impl WasiFile for File {
2765
fn as_any(&self) -> &dyn Any {
2866
self
2967
}
68+
3069
#[cfg(unix)]
31-
fn pollable(&self) -> Option<rustix::fd::BorrowedFd> {
32-
Some(self.0.as_fd())
70+
fn pollable(&self) -> Option<Arc<dyn AsFd + '_>> {
71+
Some(Arc::new(self.borrow()))
3372
}
3473

3574
#[cfg(windows)]
36-
fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
37-
Some(self.0.as_raw_handle_or_socket())
75+
fn pollable(&self) -> Option<Arc<dyn AsRawHandleOrSocket + '_>> {
76+
Some(Arc::new(BorrowedFile(self.0.read().unwrap())))
3877
}
39-
async fn datasync(&mut self) -> Result<(), Error> {
40-
self.0.sync_data()?;
78+
79+
async fn datasync(&self) -> Result<(), Error> {
80+
self.0.read().unwrap().sync_data()?;
4181
Ok(())
4282
}
43-
async fn sync(&mut self) -> Result<(), Error> {
44-
self.0.sync_all()?;
83+
async fn sync(&self) -> Result<(), Error> {
84+
self.0.read().unwrap().sync_all()?;
4585
Ok(())
4686
}
47-
async fn get_filetype(&mut self) -> Result<FileType, Error> {
48-
let meta = self.0.metadata()?;
87+
async fn get_filetype(&self) -> Result<FileType, Error> {
88+
let meta = self.0.read().unwrap().metadata()?;
4989
Ok(filetype_from(&meta.file_type()))
5090
}
51-
async fn get_fdflags(&mut self) -> Result<FdFlags, Error> {
52-
let fdflags = get_fd_flags(&self.0)?;
91+
async fn get_fdflags(&self) -> Result<FdFlags, Error> {
92+
let file = self.0.read().unwrap();
93+
let fdflags = get_fd_flags(&*file)?;
5394
Ok(fdflags)
5495
}
55-
async fn set_fdflags(&mut self, fdflags: FdFlags) -> Result<(), Error> {
96+
async fn set_fdflags(&self, fdflags: FdFlags) -> Result<(), Error> {
5697
if fdflags.intersects(
5798
wasi_common::file::FdFlags::DSYNC
5899
| wasi_common::file::FdFlags::SYNC
59100
| wasi_common::file::FdFlags::RSYNC,
60101
) {
61102
return Err(Error::invalid_argument().context("cannot set DSYNC, SYNC, or RSYNC flag"));
62103
}
63-
let set_fd_flags = self.0.new_set_fd_flags(to_sysif_fdflags(fdflags))?;
64-
self.0.set_fd_flags(set_fd_flags)?;
104+
let mut file = self.0.write().unwrap();
105+
let set_fd_flags = (*file).new_set_fd_flags(to_sysif_fdflags(fdflags))?;
106+
(*file).set_fd_flags(set_fd_flags)?;
65107
Ok(())
66108
}
67-
async fn get_filestat(&mut self) -> Result<Filestat, Error> {
68-
let meta = self.0.metadata()?;
109+
async fn get_filestat(&self) -> Result<Filestat, Error> {
110+
let meta = self.0.read().unwrap().metadata()?;
69111
Ok(Filestat {
70112
device_id: meta.dev(),
71113
inode: meta.ino(),
@@ -77,63 +119,68 @@ impl WasiFile for File {
77119
ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None),
78120
})
79121
}
80-
async fn set_filestat_size(&mut self, size: u64) -> Result<(), Error> {
81-
self.0.set_len(size)?;
122+
async fn set_filestat_size(&self, size: u64) -> Result<(), Error> {
123+
self.0.read().unwrap().set_len(size)?;
82124
Ok(())
83125
}
84-
async fn advise(&mut self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
85-
self.0.advise(offset, len, convert_advice(advice))?;
126+
async fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error> {
127+
self.0
128+
.read()
129+
.unwrap()
130+
.advise(offset, len, convert_advice(advice))?;
86131
Ok(())
87132
}
88-
async fn allocate(&mut self, offset: u64, len: u64) -> Result<(), Error> {
89-
self.0.allocate(offset, len)?;
133+
async fn allocate(&self, offset: u64, len: u64) -> Result<(), Error> {
134+
self.0.read().unwrap().allocate(offset, len)?;
90135
Ok(())
91136
}
92137
async fn set_times(
93-
&mut self,
138+
&self,
94139
atime: Option<wasi_common::SystemTimeSpec>,
95140
mtime: Option<wasi_common::SystemTimeSpec>,
96141
) -> Result<(), Error> {
97142
self.0
143+
.read()
144+
.unwrap()
98145
.set_times(convert_systimespec(atime), convert_systimespec(mtime))?;
99146
Ok(())
100147
}
101-
async fn read_vectored<'a>(&mut self, bufs: &mut [io::IoSliceMut<'a>]) -> Result<u64, Error> {
102-
let n = self.0.read_vectored(bufs)?;
148+
async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result<u64, Error> {
149+
let n = self.0.read().unwrap().read_vectored(bufs)?;
103150
Ok(n.try_into()?)
104151
}
105152
async fn read_vectored_at<'a>(
106-
&mut self,
153+
&self,
107154
bufs: &mut [io::IoSliceMut<'a>],
108155
offset: u64,
109156
) -> Result<u64, Error> {
110-
let n = self.0.read_vectored_at(bufs, offset)?;
157+
let n = self.0.read().unwrap().read_vectored_at(bufs, offset)?;
111158
Ok(n.try_into()?)
112159
}
113-
async fn write_vectored<'a>(&mut self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
114-
let n = self.0.write_vectored(bufs)?;
160+
async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
161+
let n = self.0.read().unwrap().write_vectored(bufs)?;
115162
Ok(n.try_into()?)
116163
}
117164
async fn write_vectored_at<'a>(
118-
&mut self,
165+
&self,
119166
bufs: &[io::IoSlice<'a>],
120167
offset: u64,
121168
) -> Result<u64, Error> {
122-
let n = self.0.write_vectored_at(bufs, offset)?;
169+
let n = self.0.read().unwrap().write_vectored_at(bufs, offset)?;
123170
Ok(n.try_into()?)
124171
}
125-
async fn seek(&mut self, pos: std::io::SeekFrom) -> Result<u64, Error> {
126-
Ok(self.0.seek(pos)?)
172+
async fn seek(&self, pos: std::io::SeekFrom) -> Result<u64, Error> {
173+
Ok(self.0.read().unwrap().seek(pos)?)
127174
}
128-
async fn peek(&mut self, buf: &mut [u8]) -> Result<u64, Error> {
129-
let n = self.0.peek(buf)?;
175+
async fn peek(&self, buf: &mut [u8]) -> Result<u64, Error> {
176+
let n = self.0.read().unwrap().peek(buf)?;
130177
Ok(n.try_into()?)
131178
}
132-
async fn num_ready_bytes(&self) -> Result<u64, Error> {
133-
Ok(self.0.num_ready_bytes()?)
179+
fn num_ready_bytes(&self) -> Result<u64, Error> {
180+
Ok(self.0.read().unwrap().num_ready_bytes()?)
134181
}
135-
fn isatty(&mut self) -> bool {
136-
self.0.is_terminal()
182+
fn isatty(&self) -> bool {
183+
self.0.read().unwrap().is_terminal()
137184
}
138185
}
139186

@@ -160,35 +207,6 @@ pub fn filetype_from(ft: &cap_std::fs::FileType) -> FileType {
160207
}
161208
}
162209

163-
#[cfg(windows)]
164-
use io_lifetimes::{AsHandle, BorrowedHandle};
165-
#[cfg(windows)]
166-
impl AsHandle for File {
167-
fn as_handle(&self) -> BorrowedHandle<'_> {
168-
self.0.as_handle()
169-
}
170-
}
171-
172-
#[cfg(windows)]
173-
use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket};
174-
#[cfg(windows)]
175-
impl AsRawHandleOrSocket for File {
176-
#[inline]
177-
fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
178-
self.0.as_raw_handle_or_socket()
179-
}
180-
}
181-
182-
#[cfg(unix)]
183-
use io_lifetimes::{AsFd, BorrowedFd};
184-
185-
#[cfg(unix)]
186-
impl AsFd for File {
187-
fn as_fd(&self) -> BorrowedFd<'_> {
188-
self.0.as_fd()
189-
}
190-
}
191-
192210
pub(crate) fn convert_systimespec(
193211
t: Option<wasi_common::SystemTimeSpec>,
194212
) -> Option<SystemTimeSpec> {

crates/wasi-common/cap-std-sync/src/lib.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,15 @@ impl WasiCtxBuilder {
9494
}
9595
Ok(self)
9696
}
97-
pub fn stdin(mut self, f: Box<dyn WasiFile>) -> Self {
97+
pub fn stdin(self, f: Box<dyn WasiFile>) -> Self {
9898
self.0.set_stdin(f);
9999
self
100100
}
101-
pub fn stdout(mut self, f: Box<dyn WasiFile>) -> Self {
101+
pub fn stdout(self, f: Box<dyn WasiFile>) -> Self {
102102
self.0.set_stdout(f);
103103
self
104104
}
105-
pub fn stderr(mut self, f: Box<dyn WasiFile>) -> Self {
105+
pub fn stderr(self, f: Box<dyn WasiFile>) -> Self {
106106
self.0.set_stderr(f);
107107
self
108108
}
@@ -118,12 +118,12 @@ impl WasiCtxBuilder {
118118
pub fn inherit_stdio(self) -> Self {
119119
self.inherit_stdin().inherit_stdout().inherit_stderr()
120120
}
121-
pub fn preopened_dir(mut self, dir: Dir, guest_path: impl AsRef<Path>) -> Result<Self, Error> {
121+
pub fn preopened_dir(self, dir: Dir, guest_path: impl AsRef<Path>) -> Result<Self, Error> {
122122
let dir = Box::new(crate::dir::Dir::from_cap_std(dir));
123123
self.0.push_preopened_dir(dir, guest_path)?;
124124
Ok(self)
125125
}
126-
pub fn preopened_socket(mut self, fd: u32, socket: impl Into<Socket>) -> Result<Self, Error> {
126+
pub fn preopened_socket(self, fd: u32, socket: impl Into<Socket>) -> Result<Self, Error> {
127127
let socket: Socket = socket.into();
128128
let file: Box<dyn WasiFile> = socket.into();
129129

0 commit comments

Comments
 (0)