1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
//! Timer facilities for Tokio
//!
//! The default timer implementation is a hashed timing wheel. This structure
//! provides the best runtime characteristics for the majority of network
//! application patterns **as long as it is correctly configured**. A hashed
//! timing wheel's worst case is `O(n)` where `n` is the number of pending
//! timeouts.
//!
//! Most useful functions are on [`Timer`](struct.Timer.html).
//!
//! ## Example
//!
//! Here is a simple example of how to use the timer.
//!
//! ```rust
//! extern crate tokio_timer;
//! extern crate futures;
//!
//! use tokio_timer::*;
//! use futures::*;
//! use std::time::*;
//!
//! pub fn main() {
//! // Create a new timer with default settings. While this is the easiest way
//! // to get a timer, usually you will want to tune the config settings for
//! // your usage patterns.
//! let timer = Timer::default();
//!
//! // Set a timeout that expires in 500 milliseconds
//! let sleep = timer.sleep(Duration::from_millis(500));
//!
//! // Use the `Future::wait` to block the current thread until `Sleep`
//! // future completes.
//! //
//! sleep.wait();
//! }
//! ```
//!
//! ## Hashed Timing Wheel
//!
//! The hashed timing wheel timer is a coarse grained timer that is optimized
//! for cases where the timeout range is relatively uniform and high precision
//! is not needed. These requirements are very common with network related
//! applications as most timeouts tend to be a constant range (for example, 30
//! seconds) and timeouts are used more as a safe guard than for high
//! precision.
//!
//! The timer is inspired by the [paper by Varghese and
//! Lauck](http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf).
//!
//! A hashed wheel timer is implemented as a vector of "slots" that represent
//! time slices. The default slot size is 100ms. As time progresses, the timer
//! walks over each slot and looks in the slot to find all timers that are due
//! to expire. When the timer reaches the end of the vector, it starts back at
//! the beginning.
//!
//! Given the fact that the timer operates in ticks, a timeout can only be as
//! precise as the tick duration. If the tick size is 100ms, any timeout
//! request that falls within that 100ms slot will be triggered at the same
//! time.
//!
//! A timer is assigned to a slot by taking the expiration instant and
//! assigning it to a slot, factoring in wrapping. When there are more than one
//! timeouts assigned to a given slot, they are stored in a linked list.
//!
//! This structure allows constant time timer operations **as long as timeouts
//! don't collide**. In other words, if two timeouts are set to expire at
//! exactly `num-slots * tick-duration` time apart, they will be assigned to
//! the same bucket.
//!
//! The best way to avoid collisions is to ensure that no timeout is set that
//! is for greater than `num-slots * tick-duration` into the future.
//!
//! A timer can be configured with `Builder`.
//!
//! ## Runtime details
//!
//! When creating a timer, a thread is spawned. The timing details are managed
//! on this thread. When `Timer::set_timeout` is called, a request is sent to
//! the thread over a bounded channel.
//!
//! All storage needed to run the timer is pre-allocated, which means that the
//! timer system is able to run without any runtime allocations. The one
//! exception would be if the timer's `max_capacity` is larger than the
//! `initial_capacity`, in which case timeout storage is allocated in chunks as
//! needed. Timeout storage can grow but never shrink.
extern crate futures;
extern crate slab;
pub use Interval;
pub use ;
use cmp;
use Duration;
/// Configures and builds a `Timer`
///
/// A `Builder` is obtained by calling `wheel()`.
/// Configure and build a `Timer` backed by a hashed wheel.