poll now handles monotonic clocks, not system clocks

I initially had it backwards. It is not sensible to poll on a system
clock timeout because the system clock is not necessarily monotonic!
only a monotonic clock makes sense for a timeout.
This commit is contained in:
Pat Hickey
2021-01-19 15:11:54 -08:00
parent 21713d3468
commit 016ed8966a
4 changed files with 36 additions and 30 deletions

View File

@@ -1,14 +1,14 @@
use crate::clocks::WasiSystemClock; use crate::clocks::WasiMonotonicClock;
use crate::file::WasiFile; use crate::file::WasiFile;
use crate::Error; use crate::Error;
use cap_std::time::{Duration, SystemTime}; use cap_std::time::{Duration, Instant};
use std::cell::Ref; use std::cell::Ref;
pub mod subscription; pub mod subscription;
mod sync; mod sync;
pub use sync::SyncSched; pub use sync::SyncSched;
use subscription::{RwSubscription, Subscription, SubscriptionResult, SystemTimerSubscription}; use subscription::{MonotonicClockSubscription, RwSubscription, Subscription, SubscriptionResult};
pub trait WasiSched { pub trait WasiSched {
fn poll_oneoff(&self, poll: &Poll) -> Result<(), Error>; fn poll_oneoff(&self, poll: &Poll) -> Result<(), Error>;
@@ -36,15 +36,15 @@ impl<'a> Poll<'a> {
pub fn new() -> Self { pub fn new() -> Self {
Self { subs: Vec::new() } Self { subs: Vec::new() }
} }
pub fn subscribe_system_timer( pub fn subscribe_monotonic_clock(
&mut self, &mut self,
clock: &'a dyn WasiSystemClock, clock: &'a dyn WasiMonotonicClock,
deadline: SystemTime, deadline: Instant,
precision: Duration, precision: Duration,
ud: Userdata, ud: Userdata,
) { ) {
self.subs.push(( self.subs.push((
Subscription::SystemTimer(SystemTimerSubscription { Subscription::MonotonicClock(MonotonicClockSubscription {
clock, clock,
deadline, deadline,
precision, precision,
@@ -69,15 +69,15 @@ impl<'a> Poll<'a> {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.subs.is_empty() self.subs.is_empty()
} }
pub fn earliest_system_timer(&'a self) -> Option<&SystemTimerSubscription<'a>> { pub fn earliest_clock_deadline(&'a self) -> Option<&MonotonicClockSubscription<'a>> {
let mut subs = self let mut subs = self
.subs .subs
.iter() .iter()
.filter_map(|(s, _ud)| match s { .filter_map(|(s, _ud)| match s {
Subscription::SystemTimer(t) => Some(t), Subscription::MonotonicClock(t) => Some(t),
_ => None, _ => None,
}) })
.collect::<Vec<&SystemTimerSubscription<'a>>>(); .collect::<Vec<&MonotonicClockSubscription<'a>>>();
subs.sort_by(|a, b| a.deadline.cmp(&b.deadline)); subs.sort_by(|a, b| a.deadline.cmp(&b.deadline));
subs.into_iter().next() // First element is earliest subs.into_iter().next() // First element is earliest
} }

View File

@@ -1,8 +1,8 @@
use crate::clocks::WasiSystemClock; use crate::clocks::WasiMonotonicClock;
use crate::file::WasiFile; use crate::file::WasiFile;
use crate::Error; use crate::Error;
use bitflags::bitflags; use bitflags::bitflags;
use cap_std::time::{Duration, SystemTime}; use cap_std::time::{Duration, Instant};
use std::cell::{Cell, Ref}; use std::cell::{Cell, Ref};
bitflags! { bitflags! {
@@ -34,18 +34,18 @@ impl<'a> RwSubscription<'a> {
} }
} }
pub struct SystemTimerSubscription<'a> { pub struct MonotonicClockSubscription<'a> {
pub clock: &'a dyn WasiSystemClock, pub clock: &'a dyn WasiMonotonicClock,
pub deadline: SystemTime, pub deadline: Instant,
pub precision: Duration, pub precision: Duration,
} }
impl<'a> SystemTimerSubscription<'a> { impl<'a> MonotonicClockSubscription<'a> {
pub fn now(&self) -> SystemTime { pub fn now(&self) -> Instant {
self.clock.now(self.precision) self.clock.now(self.precision)
} }
pub fn result(&self) -> Option<Result<(), Error>> { pub fn result(&self) -> Option<Result<(), Error>> {
if self.now().duration_since(self.deadline).is_ok() { if self.now().checked_duration_since(self.deadline).is_some() {
Some(Ok(())) Some(Ok(()))
} else { } else {
None None
@@ -56,13 +56,13 @@ impl<'a> SystemTimerSubscription<'a> {
pub enum Subscription<'a> { pub enum Subscription<'a> {
Read(RwSubscription<'a>), Read(RwSubscription<'a>),
Write(RwSubscription<'a>), Write(RwSubscription<'a>),
SystemTimer(SystemTimerSubscription<'a>), MonotonicClock(MonotonicClockSubscription<'a>),
} }
pub enum SubscriptionResult { pub enum SubscriptionResult {
Read(Result<(u64, RwEventFlags), Error>), Read(Result<(u64, RwEventFlags), Error>),
Write(Result<(u64, RwEventFlags), Error>), Write(Result<(u64, RwEventFlags), Error>),
SystemTimer(Result<(), Error>), MonotonicClock(Result<(), Error>),
} }
impl SubscriptionResult { impl SubscriptionResult {
@@ -70,7 +70,7 @@ impl SubscriptionResult {
match s { match s {
Subscription::Read(s) => s.result().map(SubscriptionResult::Read), Subscription::Read(s) => s.result().map(SubscriptionResult::Read),
Subscription::Write(s) => s.result().map(SubscriptionResult::Write), Subscription::Write(s) => s.result().map(SubscriptionResult::Write),
Subscription::SystemTimer(s) => s.result().map(SubscriptionResult::SystemTimer), Subscription::MonotonicClock(s) => s.result().map(SubscriptionResult::MonotonicClock),
} }
} }
} }

View File

@@ -22,7 +22,7 @@ mod unix {
return Ok(()); return Ok(());
} }
let mut pollfds = Vec::new(); let mut pollfds = Vec::new();
let timeout = poll.earliest_system_timer(); let timeout = poll.earliest_clock_deadline();
for s in poll.rw_subscriptions() { for s in poll.rw_subscriptions() {
match s { match s {
Subscription::Read(f) => { Subscription::Read(f) => {
@@ -34,7 +34,7 @@ mod unix {
let raw_fd = wasi_file_raw_fd(f.file.deref()).ok_or(Error::Inval)?; let raw_fd = wasi_file_raw_fd(f.file.deref()).ok_or(Error::Inval)?;
pollfds.push(unsafe { PollFd::new(raw_fd, PollFlags::POLLOUT) }); pollfds.push(unsafe { PollFd::new(raw_fd, PollFlags::POLLOUT) });
} }
Subscription::SystemTimer { .. } => unreachable!(), Subscription::MonotonicClock { .. } => unreachable!(),
} }
} }
@@ -42,7 +42,7 @@ mod unix {
let poll_timeout = if let Some(t) = timeout { let poll_timeout = if let Some(t) = timeout {
let duration = t let duration = t
.deadline .deadline
.duration_since(t.clock.now(t.precision)) .checked_duration_since(t.clock.now(t.precision))
.unwrap_or(Duration::from_secs(0)); .unwrap_or(Duration::from_secs(0));
(duration.as_millis() + 1) // XXX try always rounding up? (duration.as_millis() + 1) // XXX try always rounding up?
.try_into() .try_into()

View File

@@ -895,7 +895,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
return Err(Error::Inval); return Err(Error::Inval);
} }
use cap_std::time::{Duration, SystemClock}; use cap_std::time::Duration;
let table = self.table(); let table = self.table();
let mut poll = Poll::new(); let mut poll = Poll::new();
@@ -905,15 +905,16 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
let sub = sub_ptr.read()?; let sub = sub_ptr.read()?;
match sub.u { match sub.u {
types::SubscriptionU::Clock(clocksub) => match clocksub.id { types::SubscriptionU::Clock(clocksub) => match clocksub.id {
types::Clockid::Realtime => { types::Clockid::Monotonic => {
let clock = self.clocks.system.deref(); let clock = self.clocks.monotonic.deref();
let precision = Duration::from_micros(clocksub.precision); let precision = Duration::from_micros(clocksub.precision);
let duration = Duration::from_micros(clocksub.timeout); let duration = Duration::from_micros(clocksub.timeout);
let deadline = if clocksub let deadline = if clocksub
.flags .flags
.contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME) .contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
{ {
SystemClock::UNIX_EPOCH self.clocks
.creation_time
.checked_add(duration) .checked_add(duration)
.ok_or(Error::Overflow)? .ok_or(Error::Overflow)?
} else { } else {
@@ -922,7 +923,12 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
.checked_add(duration) .checked_add(duration)
.ok_or(Error::Overflow)? .ok_or(Error::Overflow)?
}; };
poll.subscribe_system_timer(clock, deadline, precision, sub.userdata.into()) poll.subscribe_monotonic_clock(
clock,
deadline,
precision,
sub.userdata.into(),
)
} }
_ => Err(Error::Inval)?, _ => Err(Error::Inval)?,
}, },
@@ -1000,7 +1006,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
}, },
} }
} }
SubscriptionResult::SystemTimer(r) => { SubscriptionResult::MonotonicClock(r) => {
let type_ = types::Eventtype::Clock; let type_ = types::Eventtype::Clock;
types::Event { types::Event {
userdata, userdata,