Files
wasmtime/crates/wasi-common/cap-std-sync/src/sched/unix.rs
Pat Hickey 56daa8a199 Use wiggle "trappable error" to implement wasi-common (#5279)
* convert wasi-common from defining its own error to using wiggle trappable error

* wasi-common impl crates: switch error strategy

* wasmtime-wasi: error is trappable, and no longer requires UserErrorConversion

* docs

* typo

* readdir: windows fixes

* fix windows scheduler errors

fun fact! the Send and Recv errors here that just had a `.context` on
them were previously not being captured in the downcasting either. They
need to be traps, and would have ended up that way by ommission, but
you'd never actually know that by reading the code!
2022-11-16 16:57:22 -08:00

83 lines
3.0 KiB
Rust

use cap_std::time::Duration;
use rustix::io::{PollFd, PollFlags};
use std::convert::TryInto;
use wasi_common::sched::subscription::{RwEventFlags, Subscription};
use wasi_common::{sched::Poll, Error, ErrorExt};
pub async fn poll_oneoff<'a>(poll: &mut Poll<'a>) -> Result<(), Error> {
if poll.is_empty() {
return Ok(());
}
let mut pollfds = Vec::new();
for s in poll.rw_subscriptions() {
match s {
Subscription::Read(f) => {
let fd = f
.file
.pollable()
.ok_or(Error::invalid_argument().context("file is not pollable"))?;
pollfds.push(PollFd::from_borrowed_fd(fd, PollFlags::IN));
}
Subscription::Write(f) => {
let fd = f
.file
.pollable()
.ok_or(Error::invalid_argument().context("file is not pollable"))?;
pollfds.push(PollFd::from_borrowed_fd(fd, PollFlags::OUT));
}
Subscription::MonotonicClock { .. } => unreachable!(),
}
}
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));
(duration.as_millis() + 1) // XXX try always rounding up?
.try_into()
.map_err(|_| Error::overflow().context("poll timeout"))?
} else {
std::os::raw::c_int::max_value()
};
tracing::debug!(
poll_timeout = tracing::field::debug(poll_timeout),
poll_fds = tracing::field::debug(&pollfds),
"poll"
);
match rustix::io::poll(&mut pollfds, poll_timeout) {
Ok(ready) => break ready,
Err(rustix::io::Errno::INTR) => continue,
Err(err) => return Err(std::io::Error::from(err).into()),
}
};
if ready > 0 {
for (rwsub, pollfd) in poll.rw_subscriptions().zip(pollfds.into_iter()) {
let revents = pollfd.revents();
let (nbytes, rwsub) = match rwsub {
Subscription::Read(sub) => {
let ready = sub.file.num_ready_bytes().await?;
(std::cmp::max(ready, 1), sub)
}
Subscription::Write(sub) => (0, sub),
_ => unreachable!(),
};
if revents.contains(PollFlags::NVAL) {
rwsub.error(Error::badf());
} else if revents.contains(PollFlags::ERR) {
rwsub.error(Error::io());
} else if revents.contains(PollFlags::HUP) {
rwsub.complete(nbytes, RwEventFlags::HANGUP);
} else {
rwsub.complete(nbytes, RwEventFlags::empty());
};
}
} else {
poll.earliest_clock_deadline()
.expect("timed out")
.result()
.expect("timer deadline is past")
.unwrap()
}
Ok(())
}