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:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user