Provide a timer implementation (#249)

This patch adds a new crate: tokio-timer. This crate provides an
efficient timer implemeentation designed for use in Tokio based
applications.

The timer users a hierarchical hashed timer wheel algorithm with six
levels, each having 64 slots. This allows the timer to have a resolution
of 1ms while maintaining O(1) complexity for insert, removal, and firing
of timeouts.

There already exists a tokio-timer crate. This is a complete rewrite
which solves the outstanding problems with the existing tokio-timer
library.

Closes #146.
This commit is contained in:
Carl Lerche
2018-03-28 22:26:47 -07:00
committed by GitHub
parent ad189826f4
commit 19500f7df8
24 changed files with 3398 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
use Error;
use timer::{Handle, Entry};
use futures::Poll;
use std::sync::Arc;
use std::time::Instant;
/// Registration with a timer.
///
/// The association between a `Sleep` instance and a timer is done lazily in
/// `poll`
#[derive(Debug)]
pub(crate) struct Registration {
entry: Arc<Entry>,
}
impl Registration {
pub fn new(deadline: Instant) -> Registration {
fn is_send<T: Send + Sync>() {}
is_send::<Registration>();
match Handle::try_current() {
Ok(handle) => Registration::new_with_handle(deadline, handle),
Err(_) => Registration::new_error(),
}
}
pub fn new_with_handle(deadline: Instant, handle: Handle) -> Registration {
let inner = match handle.inner() {
Some(inner) => inner,
None => return Registration::new_error(),
};
// Increment the number of active timeouts
if inner.increment().is_err() {
return Registration::new_error();
}
let when = inner.normalize_deadline(deadline);
if when <= inner.elapsed() {
// The deadline has already elapsed, ther eis no point creating the
// structures.
return Registration {
entry: Arc::new(Entry::new_elapsed(handle)),
};
}
let entry = Arc::new(Entry::new(when, handle));
if inner.queue(&entry).is_err() {
// The timer has shutdown, transition the entry to the error state.
entry.error();
}
Registration { entry }
}
pub fn reset(&self, deadline: Instant) {
Entry::reset(&self.entry, deadline);
}
fn new_error() -> Registration {
let entry = Arc::new(Entry::new_error());
Registration { entry }
}
pub fn is_elapsed(&self) -> bool {
self.entry.is_elapsed()
}
pub fn poll_elapsed(&self) -> Poll<(), Error> {
self.entry.poll_elapsed()
}
}
impl Drop for Registration {
fn drop(&mut self) {
Entry::cancel(&self.entry);
}
}