mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-01 00:00:10 +02:00
Remove timers from Tokio.
In accordance with tokio-rs/tokio-rfcs#3, timers are being extracted from Tokio and moved to a separate crate (probably futures-timer). This PR removes timers from the code base.
This commit is contained in:
committed by
Alex Crichton
parent
b23a997cb8
commit
697851210c
@@ -1,200 +0,0 @@
|
||||
//! Support for creating futures that represent intervals.
|
||||
//!
|
||||
//! This module contains the `Interval` type which is a stream that will
|
||||
//! resolve at a fixed intervals in future
|
||||
|
||||
use std::io;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use futures::{Poll, Async};
|
||||
use futures::stream::{Stream};
|
||||
|
||||
use reactor::{Remote, Handle};
|
||||
use reactor::timeout_token::TimeoutToken;
|
||||
|
||||
/// A stream representing notifications at fixed interval
|
||||
///
|
||||
/// Intervals are created through the `Interval::new` or
|
||||
/// `Interval::new_at` methods indicating when a first notification
|
||||
/// should be triggered and when it will be repeated.
|
||||
///
|
||||
/// Note that timeouts are not intended for high resolution timers, but rather
|
||||
/// they will likely fire some granularity after the exact instant that they're
|
||||
/// otherwise indicated to fire at.
|
||||
#[must_use = "streams do nothing unless polled"]
|
||||
pub struct Interval {
|
||||
token: TimeoutToken,
|
||||
next: Instant,
|
||||
interval: Duration,
|
||||
handle: Remote,
|
||||
}
|
||||
|
||||
impl Interval {
|
||||
/// Creates a new interval which will fire at `dur` time into the future,
|
||||
/// and will repeat every `dur` interval after
|
||||
///
|
||||
/// This function will return a future that will resolve to the actual
|
||||
/// interval object. The interval object itself is then a stream which will
|
||||
/// be set to fire at the specified intervals
|
||||
pub fn new(dur: Duration, handle: &Handle) -> io::Result<Interval> {
|
||||
Interval::new_at(Instant::now() + dur, dur, handle)
|
||||
}
|
||||
|
||||
/// Creates a new interval which will fire at the time specified by `at`,
|
||||
/// and then will repeat every `dur` interval after
|
||||
///
|
||||
/// This function will return a future that will resolve to the actual
|
||||
/// timeout object. The timeout object itself is then a future which will be
|
||||
/// set to fire at the specified point in the future.
|
||||
pub fn new_at(at: Instant, dur: Duration, handle: &Handle)
|
||||
-> io::Result<Interval>
|
||||
{
|
||||
Ok(Interval {
|
||||
token: try!(TimeoutToken::new(at, &handle)),
|
||||
next: at,
|
||||
interval: dur,
|
||||
handle: handle.remote().clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// 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.
|
||||
fn poll_at(&mut self, now: Instant) -> Poll<Option<()>, io::Error> {
|
||||
if self.next <= now {
|
||||
self.next = next_interval(self.next, now, self.interval);
|
||||
self.token.reset_timeout(self.next, &self.handle);
|
||||
Ok(Async::Ready(Some(())))
|
||||
} else {
|
||||
self.token.update_timeout(&self.handle);
|
||||
Ok(Async::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for Interval {
|
||||
type Item = ();
|
||||
type Error = io::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<()>, 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Duration object to raw nanoseconds if possible
|
||||
///
|
||||
/// This is useful to divide intervals.
|
||||
///
|
||||
/// While technically for large duration it's impossible to represent any
|
||||
/// duration as nanoseconds, the largest duration we can represent is about
|
||||
/// 427_000 years. Large enough for any interval we would use or calculate in
|
||||
/// tokio.
|
||||
fn duration_to_nanos(dur: Duration) -> Option<u64> {
|
||||
dur.as_secs()
|
||||
.checked_mul(1_000_000_000)
|
||||
.and_then(|v| v.checked_add(dur.subsec_nanos() as u64))
|
||||
}
|
||||
|
||||
fn next_interval(prev: Instant, now: Instant, interval: Duration) -> Instant {
|
||||
let new = prev + interval;
|
||||
if new > now {
|
||||
return new;
|
||||
} else {
|
||||
let spent_ns = duration_to_nanos(now.duration_since(prev))
|
||||
.expect("interval should be expired");
|
||||
let interval_ns = duration_to_nanos(interval)
|
||||
.expect("interval is less that 427 thousand years");
|
||||
let mult = spent_ns/interval_ns + 1;
|
||||
assert!(mult < (1 << 32),
|
||||
"can't skip more than 4 billion intervals of {:?} \
|
||||
(trying to skip {})", interval, mult);
|
||||
return prev + interval * (mult as u32);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::time::{Instant, Duration};
|
||||
use super::next_interval;
|
||||
|
||||
struct Timeline(Instant);
|
||||
|
||||
impl Timeline {
|
||||
fn new() -> Timeline {
|
||||
Timeline(Instant::now())
|
||||
}
|
||||
fn at(&self, millis: u64) -> Instant {
|
||||
self.0 + Duration::from_millis(millis)
|
||||
}
|
||||
fn at_ns(&self, sec: u64, nanos: u32) -> Instant {
|
||||
self.0 + Duration::new(sec, nanos)
|
||||
}
|
||||
}
|
||||
|
||||
fn dur(millis: u64) -> Duration {
|
||||
Duration::from_millis(millis)
|
||||
}
|
||||
|
||||
// The math around Instant/Duration isn't 100% precise due to rounding
|
||||
// errors, see #249 for more info
|
||||
fn almost_eq(a: Instant, b: Instant) -> bool {
|
||||
if a == b {
|
||||
true
|
||||
} else if a > b {
|
||||
a - b < Duration::from_millis(1)
|
||||
} else {
|
||||
b - a < Duration::from_millis(1)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn norm_next() {
|
||||
let tm = Timeline::new();
|
||||
assert!(almost_eq(next_interval(tm.at(1), tm.at(2), dur(10)),
|
||||
tm.at(11)));
|
||||
assert!(almost_eq(next_interval(tm.at(7777), tm.at(7788), dur(100)),
|
||||
tm.at(7877)));
|
||||
assert!(almost_eq(next_interval(tm.at(1), tm.at(1000), dur(2100)),
|
||||
tm.at(2101)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fast_forward() {
|
||||
let tm = Timeline::new();
|
||||
assert!(almost_eq(next_interval(tm.at(1), tm.at(1000), dur(10)),
|
||||
tm.at(1001)));
|
||||
assert!(almost_eq(next_interval(tm.at(7777), tm.at(8888), dur(100)),
|
||||
tm.at(8977)));
|
||||
assert!(almost_eq(next_interval(tm.at(1), tm.at(10000), dur(2100)),
|
||||
tm.at(10501)));
|
||||
}
|
||||
|
||||
/// TODO: this test actually should be successful, but since we can't
|
||||
/// multiply Duration on anything larger than u32 easily we decided
|
||||
/// to allow it to fail for now
|
||||
#[test]
|
||||
#[should_panic(expected = "can't skip more than 4 billion intervals")]
|
||||
fn large_skip() {
|
||||
let tm = Timeline::new();
|
||||
assert_eq!(next_interval(
|
||||
tm.at_ns(0, 1), tm.at_ns(25, 0), Duration::new(0, 2)),
|
||||
tm.at_ns(25, 1));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ use mio::event::Evented;
|
||||
|
||||
use reactor::{Message, Remote, Handle, Direction};
|
||||
|
||||
/// A token that identifies an active timeout.
|
||||
/// A token that identifies an active I/O resource.
|
||||
pub struct IoToken {
|
||||
token: usize,
|
||||
// TODO: can we avoid this allocation? It's kind of a bummer...
|
||||
|
||||
+3
-140
@@ -1,14 +1,12 @@
|
||||
//! The core reactor driving all I/O
|
||||
//!
|
||||
//! This module contains the `Core` type which is the reactor for all I/O
|
||||
//! happening in `tokio-core`. This reactor (or event loop) is used to run
|
||||
//! futures, schedule tasks, issue I/O requests, etc.
|
||||
//! happening in `tokio-core`. This reactor (or event loop) is used to drive I/O
|
||||
//! resources.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::mem;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
@@ -23,17 +21,10 @@ use mio;
|
||||
use mio::event::Evented;
|
||||
use slab::Slab;
|
||||
|
||||
use heap::{Heap, Slot};
|
||||
|
||||
mod io_token;
|
||||
mod timeout_token;
|
||||
|
||||
mod poll_evented;
|
||||
mod timeout;
|
||||
mod interval;
|
||||
pub use self::poll_evented::PollEvented;
|
||||
pub use self::timeout::Timeout;
|
||||
pub use self::interval::Interval;
|
||||
|
||||
static NEXT_LOOP_ID: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
scoped_thread_local!(static CURRENT_LOOP: Core);
|
||||
@@ -68,15 +59,6 @@ struct Inner {
|
||||
// Dispatch slabs for I/O and futures events
|
||||
io_dispatch: Slab<ScheduledIo>,
|
||||
task_dispatch: Slab<ScheduledTask>,
|
||||
|
||||
// Timer wheel keeping track of all timeouts. The `usize` stored in the
|
||||
// timer wheel is an index into the slab below.
|
||||
//
|
||||
// The slab below keeps track of the timeouts themselves as well as the
|
||||
// state of the timeout itself. The `TimeoutToken` type is an index into the
|
||||
// `timeouts` slab.
|
||||
timer_heap: Heap<(Instant, usize)>,
|
||||
timeouts: Slab<(Option<Slot>, TimeoutState)>,
|
||||
}
|
||||
|
||||
/// An unique ID for a Core
|
||||
@@ -119,12 +101,6 @@ struct ScheduledTask {
|
||||
wake: Option<Arc<MySetReadiness>>,
|
||||
}
|
||||
|
||||
enum TimeoutState {
|
||||
NotFired,
|
||||
Fired,
|
||||
Waiting(Task),
|
||||
}
|
||||
|
||||
enum Direction {
|
||||
Read,
|
||||
Write,
|
||||
@@ -133,9 +109,6 @@ enum Direction {
|
||||
enum Message {
|
||||
DropSource(usize),
|
||||
Schedule(usize, Task, Direction),
|
||||
UpdateTimeout(usize, Task),
|
||||
ResetTimeout(usize, Instant),
|
||||
CancelTimeout(usize),
|
||||
Run(Box<FnBox>),
|
||||
}
|
||||
|
||||
@@ -177,8 +150,6 @@ impl Core {
|
||||
io: io,
|
||||
io_dispatch: Slab::with_capacity(1),
|
||||
task_dispatch: Slab::with_capacity(1),
|
||||
timeouts: Slab::with_capacity(1),
|
||||
timer_heap: Heap::new(),
|
||||
})),
|
||||
})
|
||||
}
|
||||
@@ -255,25 +226,11 @@ impl Core {
|
||||
}
|
||||
|
||||
fn poll(&mut self, max_wait: Option<Duration>) -> bool {
|
||||
// Given the `max_wait` variable specified, figure out the actual
|
||||
// timeout that we're going to pass to `poll`. This involves taking a
|
||||
// look at active timers on our heap as well.
|
||||
let start = Instant::now();
|
||||
let timeout = self.inner.borrow_mut().timer_heap.peek().map(|t| {
|
||||
if t.0 < start {
|
||||
Duration::new(0, 0)
|
||||
} else {
|
||||
t.0 - start
|
||||
}
|
||||
});
|
||||
let timeout = match (max_wait, timeout) {
|
||||
(Some(d1), Some(d2)) => Some(cmp::min(d1, d2)),
|
||||
(max_wait, timeout) => max_wait.or(timeout),
|
||||
};
|
||||
|
||||
// Block waiting for an event to happen, peeling out how many events
|
||||
// happened.
|
||||
let amt = match self.inner.borrow_mut().io.poll(&mut self.events, timeout) {
|
||||
let amt = match self.inner.borrow_mut().io.poll(&mut self.events, max_wait) {
|
||||
Ok(a) => a,
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => return false,
|
||||
Err(e) => panic!("error in poll: {}", e),
|
||||
@@ -283,10 +240,6 @@ impl Core {
|
||||
debug!("loop poll - {:?}", after_poll - start);
|
||||
debug!("loop time - {:?}", after_poll);
|
||||
|
||||
// Process all timeouts that may have just occurred, updating the
|
||||
// current time since
|
||||
self.consume_timeouts(after_poll);
|
||||
|
||||
// Process all the events that came in, dispatching appropriately
|
||||
let mut fired = false;
|
||||
for i in 0..self.events.len() {
|
||||
@@ -371,26 +324,6 @@ impl Core {
|
||||
drop(inner);
|
||||
}
|
||||
|
||||
fn consume_timeouts(&mut self, now: Instant) {
|
||||
loop {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
match inner.timer_heap.peek() {
|
||||
Some(head) if head.0 <= now => {}
|
||||
Some(_) => break,
|
||||
None => break,
|
||||
};
|
||||
let (_, slab_idx) = inner.timer_heap.pop().unwrap();
|
||||
|
||||
trace!("firing timeout: {}", slab_idx);
|
||||
inner.timeouts[slab_idx].0.take().unwrap();
|
||||
let handle = inner.timeouts[slab_idx].1.fire();
|
||||
drop(inner);
|
||||
if let Some(handle) = handle {
|
||||
self.notify_handle(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Method used to notify a task handle.
|
||||
///
|
||||
/// Note that this should be used instead of `handle.notify()` to ensure
|
||||
@@ -422,18 +355,6 @@ impl Core {
|
||||
self.notify_handle(task);
|
||||
}
|
||||
}
|
||||
Message::UpdateTimeout(t, handle) => {
|
||||
let task = self.inner.borrow_mut().update_timeout(t, handle);
|
||||
if let Some(task) = task {
|
||||
self.notify_handle(task);
|
||||
}
|
||||
}
|
||||
Message::ResetTimeout(t, at) => {
|
||||
self.inner.borrow_mut().reset_timeout(t, at);
|
||||
}
|
||||
Message::CancelTimeout(t) => {
|
||||
self.inner.borrow_mut().cancel_timeout(t)
|
||||
}
|
||||
Message::Run(r) => r.call_box(self),
|
||||
}
|
||||
}
|
||||
@@ -513,45 +434,6 @@ impl Inner {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_timeout(&mut self, at: Instant) -> usize {
|
||||
if self.timeouts.len() == self.timeouts.capacity() {
|
||||
let len = self.timeouts.len();
|
||||
self.timeouts.reserve_exact(len);
|
||||
}
|
||||
let entry = self.timeouts.vacant_entry();
|
||||
let key = entry.key();
|
||||
let slot = self.timer_heap.push((at, key));
|
||||
entry.insert((Some(slot), TimeoutState::NotFired));
|
||||
debug!("added a timeout: {}", key);
|
||||
return key;
|
||||
}
|
||||
|
||||
fn update_timeout(&mut self, token: usize, handle: Task) -> Option<Task> {
|
||||
debug!("updating a timeout: {}", token);
|
||||
self.timeouts[token].1.block(handle)
|
||||
}
|
||||
|
||||
fn reset_timeout(&mut self, token: usize, at: Instant) {
|
||||
let pair = &mut self.timeouts[token];
|
||||
// TODO: avoid remove + push and instead just do one sift of the heap?
|
||||
// In theory we could update it in place and then do the percolation
|
||||
// as necessary
|
||||
if let Some(slot) = pair.0.take() {
|
||||
self.timer_heap.remove(slot);
|
||||
}
|
||||
let slot = self.timer_heap.push((at, token));
|
||||
*pair = (Some(slot), TimeoutState::NotFired);
|
||||
debug!("set a timeout: {}", token);
|
||||
}
|
||||
|
||||
fn cancel_timeout(&mut self, token: usize) {
|
||||
debug!("cancel a timeout: {}", token);
|
||||
let pair = self.timeouts.remove(token);
|
||||
if let (Some(slot), _state) = pair {
|
||||
self.timer_heap.remove(slot);
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn(&mut self, future: Box<Future<Item=(), Error=()>>) {
|
||||
if self.task_dispatch.len() == self.task_dispatch.capacity() {
|
||||
let len = self.task_dispatch.len();
|
||||
@@ -769,25 +651,6 @@ impl fmt::Debug for Handle {
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeoutState {
|
||||
fn block(&mut self, handle: Task) -> Option<Task> {
|
||||
match *self {
|
||||
TimeoutState::Fired => return Some(handle),
|
||||
_ => {}
|
||||
}
|
||||
*self = TimeoutState::Waiting(handle);
|
||||
None
|
||||
}
|
||||
|
||||
fn fire(&mut self) -> Option<Task> {
|
||||
match mem::replace(self, TimeoutState::Fired) {
|
||||
TimeoutState::NotFired => None,
|
||||
TimeoutState::Fired => panic!("fired twice?"),
|
||||
TimeoutState::Waiting(handle) => Some(handle),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MySetReadiness(mio::SetReadiness);
|
||||
|
||||
impl Notify for MySetReadiness {
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
//! Support for creating futures that represent timeouts.
|
||||
//!
|
||||
//! This module contains the `Timeout` type which is a future that will resolve
|
||||
//! at a particular point in the future.
|
||||
|
||||
use std::io;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use futures::{Future, Poll, Async};
|
||||
|
||||
use reactor::{Remote, Handle};
|
||||
use reactor::timeout_token::TimeoutToken;
|
||||
|
||||
/// A future representing the notification that a timeout has occurred.
|
||||
///
|
||||
/// Timeouts are created through the `Timeout::new` or
|
||||
/// `Timeout::new_at` methods indicating when a timeout should fire at.
|
||||
/// Note that timeouts are not intended for high resolution timers, but rather
|
||||
/// they will likely fire some granularity after the exact instant that they're
|
||||
/// otherwise indicated to fire at.
|
||||
#[must_use = "futures do nothing unless polled"]
|
||||
#[derive(Debug)]
|
||||
pub struct Timeout {
|
||||
token: TimeoutToken,
|
||||
when: Instant,
|
||||
handle: Remote,
|
||||
}
|
||||
|
||||
impl Timeout {
|
||||
/// Creates a new timeout which will fire at `dur` time into the future.
|
||||
///
|
||||
/// This function will return a Result with the actual timeout object or an
|
||||
/// error. The timeout object itself is then a future which will be
|
||||
/// set to fire at the specified point in the future.
|
||||
pub fn new(dur: Duration, handle: &Handle) -> io::Result<Timeout> {
|
||||
Timeout::new_at(Instant::now() + dur, handle)
|
||||
}
|
||||
|
||||
/// Creates a new timeout which will fire at the time specified by `at`.
|
||||
///
|
||||
/// This function will return a Result with the actual timeout object or an
|
||||
/// error. The timeout object itself is then a future which will be
|
||||
/// set to fire at the specified point in the future.
|
||||
pub fn new_at(at: Instant, handle: &Handle) -> io::Result<Timeout> {
|
||||
Ok(Timeout {
|
||||
token: try!(TimeoutToken::new(at, &handle)),
|
||||
when: at,
|
||||
handle: handle.remote().clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Resets this timeout to an new timeout which will fire at the time
|
||||
/// specified by `at`.
|
||||
///
|
||||
/// This method is usable even of this instance of `Timeout` has "already
|
||||
/// fired". That is, if this future has resolved, calling this method means
|
||||
/// that the future will still re-resolve at the specified instant.
|
||||
///
|
||||
/// If `at` is in the past then this future will immediately be resolved
|
||||
/// (when `poll` is called).
|
||||
///
|
||||
/// Note that if any task is currently blocked on this future then that task
|
||||
/// will be dropped. It is required to call `poll` again after this method
|
||||
/// has been called to ensure that a task is blocked on this future.
|
||||
pub fn reset(&mut self, at: Instant) {
|
||||
self.when = at;
|
||||
self.token.reset_timeout(self.when, &self.handle);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
fn poll_at(&mut self, now: Instant) -> Poll<(), io::Error> {
|
||||
if self.when <= now {
|
||||
Ok(Async::Ready(()))
|
||||
} else {
|
||||
self.token.update_timeout(&self.handle);
|
||||
Ok(Async::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
use std::io;
|
||||
use std::time::Instant;
|
||||
|
||||
use futures::task;
|
||||
|
||||
use reactor::{Message, Handle, Remote};
|
||||
|
||||
/// A token that identifies an active timeout.
|
||||
#[derive(Debug)]
|
||||
pub struct TimeoutToken {
|
||||
token: usize,
|
||||
}
|
||||
|
||||
impl TimeoutToken {
|
||||
/// Adds a new timeout to get fired at the specified instant, notifying the
|
||||
/// specified task.
|
||||
pub fn new(at: Instant, handle: &Handle) -> io::Result<TimeoutToken> {
|
||||
match handle.inner.upgrade() {
|
||||
Some(inner) => {
|
||||
let token = inner.borrow_mut().add_timeout(at);
|
||||
Ok(TimeoutToken { token: token })
|
||||
}
|
||||
None => Err(io::Error::new(io::ErrorKind::Other, "event loop gone")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates a previously added timeout to notify a new task instead.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method will panic if the timeout specified was not created by this
|
||||
/// loop handle's `add_timeout` method.
|
||||
pub fn update_timeout(&self, handle: &Remote) {
|
||||
handle.send(Message::UpdateTimeout(self.token, task::current()))
|
||||
}
|
||||
|
||||
/// Resets previously added (or fired) timeout to an new timeout
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method will panic if the timeout specified was not created by this
|
||||
/// loop handle's `add_timeout` method.
|
||||
pub fn reset_timeout(&mut self, at: Instant, handle: &Remote) {
|
||||
handle.send(Message::ResetTimeout(self.token, at));
|
||||
}
|
||||
|
||||
/// Cancel a previously added timeout.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method will panic if the timeout specified was not created by this
|
||||
/// loop handle's `add_timeout` method or if called multiple times.
|
||||
pub fn cancel_timeout(&self, handle: &Remote) {
|
||||
debug!("cancel timeout {}", self.token);
|
||||
handle.send(Message::CancelTimeout(self.token))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user