Skip to content

Commit

Permalink
implement wasi::poll_oneoff for write on Unix-like platforms
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark McCaskey committed Aug 15, 2019
1 parent d733989 commit 0c45707
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 68 deletions.
14 changes: 10 additions & 4 deletions lib/wasi-tests/tests/wasitests/poll_oneoff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ fn test_poll_oneoff() {
"../../wasitests/poll_oneoff.wasm",
"poll_oneoff",
vec![],
vec![(
"hamlet".to_string(),
::std::path::PathBuf::from("wasitests/test_fs/hamlet")
),],
vec![
(
"hamlet".to_string(),
::std::path::PathBuf::from("wasitests/test_fs/hamlet")
),
(
"temp".to_string(),
::std::path::PathBuf::from("wasitests/test_fs/temp")
),
],
vec![],
"../../wasitests/poll_oneoff.out"
);
Expand Down
1 change: 1 addition & 0 deletions lib/wasi-tests/wasitests/poll_oneoff.out
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
__wasi_event_t { userdata: 1193046, error: 0, type_: 1, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 2259, flags: 0 } } }
[__wasi_event_t { userdata: 1193046, error: 0, type_: 1, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 2259, flags: 0 } } }, __wasi_event_t { userdata: 1193046, error: 0, type_: 2, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 1234, flags: 0 } } }]
73 changes: 53 additions & 20 deletions lib/wasi-tests/wasitests/poll_oneoff.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Args:
// mapdir: hamlet:wasitests/test_fs/hamlet
// mapdir: temp:wasitests/test_fs/temp

use std::fs;
use std::io::{Read, Seek, SeekFrom};
Expand Down Expand Up @@ -95,15 +96,27 @@ pub struct __wasi_subscription_t {
}

#[cfg(target_os = "wasi")]
fn poll_read(fds: &[u32]) -> Result<Vec<__wasi_event_t>, u16> {
fn poll(fds: &[u32], read: &[bool], write: &[bool]) -> Result<Vec<__wasi_event_t>, u16> {
assert!(fds.len() == read.len() && read.len() == write.len());

let mut in_ = fds
.iter()
.map(|n| __wasi_subscription_t {
userdata: 0x123456,
type_: __WASI_EVENTTYPE_FD_READ,
u: __wasi_subscription_u {
fd_readwrite: __wasi_subscription_fs_readwrite_t { fd: *n as u32 },
},
.enumerate()
.map(|(i, n)| {
let mut type_ = 0;
if read[i] {
type_ |= __WASI_EVENTTYPE_FD_READ;
}
if write[i] {
type_ |= __WASI_EVENTTYPE_FD_WRITE;
}
__wasi_subscription_t {
userdata: 0x123456,
type_,
u: __wasi_subscription_u {
fd_readwrite: __wasi_subscription_fs_readwrite_t { fd: *n as u32 },
},
}
})
.collect::<Vec<_>>();
let mut out_ = vec![Default::default(); in_.len()];
Expand Down Expand Up @@ -131,20 +144,40 @@ fn main() {
let mut base = PathBuf::from("/");

let path = base.join("hamlet/act4/scene1.txt");
let mut file = fs::File::open(&path).expect("Could not open file");
let mut buffer = [0u8; 64];

#[cfg(target_os = "wasi")]
let path2 = base.join("temp/poll_oneoff_write.txt");
{
let fds = vec![file.as_raw_fd()];
let mut result = poll_read(fds.as_slice()).expect("First poll");
while result[0].error != 0 {
result = poll_read(fds.as_slice()).expect("subsequent polls");
let mut file = fs::File::open(&path).expect("Could not open file");
let mut file2 = fs::OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(&path2)
.expect("Could not open file");
file2.set_len(1234).unwrap();

#[cfg(target_os = "wasi")]
{
let fds = vec![file.as_raw_fd()];
let mut result = poll(fds.as_slice(), &[true], &[false]).expect("First poll");
while result[0].error != 0 {
result = poll(fds.as_slice(), &[true], &[false]).expect("subsequent polls");
}
println!("{:?}", result[0]);

let fds = vec![file.as_raw_fd(), file2.as_raw_fd()];
result = poll(fds.as_slice(), &[true, false], &[false, true]).expect("First poll");
while result[0].error != 0 {
result =
poll(fds.as_slice(), &[true, false], &[false, true]).expect("subsequent polls");
}
println!("{:?}", result);
}
#[cfg(not(target_os = "wasi"))]
{
println!("{}", "__wasi_event_t { userdata: 1193046, error: 0, type_: 1, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 2259, flags: 0 } } }");
println!("{}", "[__wasi_event_t { userdata: 1193046, error: 0, type_: 1, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 2259, flags: 0 } } }, __wasi_event_t { userdata: 1193046, error: 0, type_: 2, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 1234, flags: 0 } } }]");
}
println!("{:?}", result[0]);
}
#[cfg(not(target_os = "wasi"))]
{
println!("{}", "__wasi_event_t { userdata: 1193046, error: 0, type_: 1, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 2259, flags: 0 } } }");
}

std::fs::remove_file(path2).unwrap();
}
Binary file modified lib/wasi-tests/wasitests/poll_oneoff.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion lib/wasi/src/state/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ pub(crate) fn poll(
for (i, fd) in fds.into_iter().enumerate() {
seen_events[i] = platform_poll_events_to_pollevent_set(fd.revents);
}
// unwrap is safe because we check the error above
// unwrap is safe because we check for negative values above
Ok(result.try_into().unwrap())
}

Expand Down
85 changes: 43 additions & 42 deletions lib/wasi/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2312,51 +2312,52 @@ pub fn poll_oneoff(
} else {
unimplemented!("Clock events are not yet implemented!");
}
let mut seen_events = vec![Default::default(); in_events.len()];
wasi_try!(poll(
fds.as_slice(),
in_events.as_slice(),
seen_events.as_mut_slice()
)
.map_err(|e| e.into_wasi_err()));

for (i, seen_event) in seen_events.into_iter().enumerate() {
let mut flags = 0;
let mut error = __WASI_EAGAIN;
let mut bytes_available = 0;
let event_iter = iterate_poll_events(seen_event);
for event in event_iter {
match event {
PollEvent::PollError => error = __WASI_EIO,
PollEvent::PollHangUp => flags = __WASI_EVENT_FD_READWRITE_HANGUP,
PollEvent::PollInvalid => error = __WASI_EINVAL,
PollEvent::PollIn => {
bytes_available =
wasi_try!(fds[i].bytes_available().map_err(|e| e.into_wasi_err()));
error = __WASI_ESUCCESS;
}
PollEvent::PollOut => {
error = __WASI_ESUCCESS;
unimplemented!("Write in wasi::poll_oneoff not yet supported!")
}
}
let mut seen_events = vec![Default::default(); in_events.len()];
wasi_try!(poll(
fds.as_slice(),
in_events.as_slice(),
seen_events.as_mut_slice()
)
.map_err(|e| e.into_wasi_err()));

for (i, seen_event) in seen_events.into_iter().enumerate() {
let mut flags = 0;
let mut error = __WASI_EAGAIN;
let mut bytes_available = 0;
let event_iter = iterate_poll_events(seen_event);
for event in event_iter {
match event {
PollEvent::PollError => error = __WASI_EIO,
PollEvent::PollHangUp => flags = __WASI_EVENT_FD_READWRITE_HANGUP,
PollEvent::PollInvalid => error = __WASI_EINVAL,
PollEvent::PollIn => {
bytes_available =
wasi_try!(fds[i].bytes_available().map_err(|e| e.into_wasi_err()));
error = __WASI_ESUCCESS;
}
PollEvent::PollOut => {
bytes_available =
wasi_try!(fds[i].bytes_available().map_err(|e| e.into_wasi_err()));
error = __WASI_ESUCCESS;
}
}
let event = __wasi_event_t {
userdata: subscription_array[i].get().userdata,
error,
type_: subscription_array[i].get().type_,
u: unsafe {
__wasi_event_u {
fd_readwrite: __wasi_event_fd_readwrite_t {
nbytes: bytes_available as u64,
flags,
},
}
},
};
event_array[events_seen].set(event);
events_seen += 1;
}
let event = __wasi_event_t {
userdata: subscription_array[i].get().userdata,
error,
type_: subscription_array[i].get().type_,
u: unsafe {
__wasi_event_u {
fd_readwrite: __wasi_event_fd_readwrite_t {
nbytes: bytes_available as u64,
flags,
},
}
},
};
event_array[events_seen].set(event);
events_seen += 1;
}
out_ptr.set(events_seen as u32);
__WASI_ESUCCESS
Expand Down
11 changes: 10 additions & 1 deletion lib/wasi/src/syscalls/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,15 @@ pub union __wasi_event_u {
pub fd_readwrite: __wasi_event_fd_readwrite_t,
}

// TODO: remove this implementation of Debug when `__wasi_event_u` gets more than 1 variant
impl std::fmt::Debug for __wasi_event_u {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("__wasi_event_u")
.field("fd_readwrite", unsafe { &self.fd_readwrite })
.finish()
}
}

#[derive(Debug, Copy, Clone)]
pub enum EventEnum {
FdReadWrite {
Expand All @@ -178,7 +187,7 @@ impl EventEnum {
}
}

#[derive(Copy, Clone)]
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct __wasi_event_t {
pub userdata: __wasi_userdata_t,
Expand Down

0 comments on commit 0c45707

Please sign in to comment.