From 25dcb1fab5b18dbb9247a5424171bf45de1d1473 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Sep 2017 22:54:13 -0700 Subject: [PATCH] Add {Interval,Timeout}::poll_at Some contexts, like EC2, have `Instant::now` as a relatively expensive function to call. To help amortize the cost of this function this commit exposes a new function on `Interval` and `Timeout` to pass in the assumed current time. --- src/reactor/interval.rs | 31 +++++++++++++++++++++++-------- src/reactor/timeout.rs | 31 +++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/reactor/interval.rs b/src/reactor/interval.rs index 3859e4aed..bf766b9a7 100644 --- a/src/reactor/interval.rs +++ b/src/reactor/interval.rs @@ -55,15 +55,20 @@ impl Interval { handle: handle.remote().clone(), }) } -} -impl Stream for Interval { - type Item = (); - type Error = io::Error; - - fn poll(&mut self) -> Poll, io::Error> { - // TODO: is this fast enough? - let now = Instant::now(); + /// Polls this `Interval` instance to see if it's elapsed, assuming the + /// current time is specified by `now`. + /// + /// The `Future::poll` implementation for `Interval` will call `Instant::now` + /// each time it's invoked, but in some contexts this can be a costly + /// operation. This method is provided to amortize the cost by avoiding + /// usage of `Instant::now`, assuming that it's been called elsewhere. + /// + /// This function takes the assumed current time as the first parameter and + /// otherwise functions as this future's `poll` function. This will block a + /// task if one isn't already blocked or update a previous one if already + /// blocked. + pub fn poll_at(&mut self, now: Instant) -> Poll, io::Error> { if self.next <= now { self.next = next_interval(self.next, now, self.interval); self.token.reset_timeout(self.next, &self.handle); @@ -75,6 +80,16 @@ impl Stream for Interval { } } +impl Stream for Interval { + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll, io::Error> { + // TODO: is this fast enough? + self.poll_at(Instant::now()) + } +} + impl Drop for Interval { fn drop(&mut self) { self.token.cancel_timeout(&self.handle); diff --git a/src/reactor/timeout.rs b/src/reactor/timeout.rs index b67ab38ed..8f0b354c9 100644 --- a/src/reactor/timeout.rs +++ b/src/reactor/timeout.rs @@ -64,15 +64,20 @@ impl Timeout { self.when = at; self.token.reset_timeout(self.when, &self.handle); } -} -impl Future for Timeout { - type Item = (); - type Error = io::Error; - - fn poll(&mut self) -> Poll<(), io::Error> { - // TODO: is this fast enough? - let now = Instant::now(); + /// Polls this `Timeout` instance to see if it's elapsed, assuming the + /// current time is specified by `now`. + /// + /// The `Future::poll` implementation for `Timeout` will call `Instant::now` + /// each time it's invoked, but in some contexts this can be a costly + /// operation. This method is provided to amortize the cost by avoiding + /// usage of `Instant::now`, assuming that it's been called elsewhere. + /// + /// This function takes the assumed current time as the first parameter and + /// otherwise functions as this future's `poll` function. This will block a + /// task if one isn't already blocked or update a previous one if already + /// blocked. + pub fn poll_at(&mut self, now: Instant) -> Poll<(), io::Error> { if self.when <= now { Ok(Async::Ready(())) } else { @@ -82,6 +87,16 @@ impl Future for Timeout { } } +impl Future for Timeout { + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<(), io::Error> { + // TODO: is this fast enough? + self.poll_at(Instant::now()) + } +} + impl Drop for Timeout { fn drop(&mut self) { self.token.cancel_timeout(&self.handle);