tokio/runtime/time/wheel/
mod.rs1use crate::runtime::time::{TimerHandle, TimerShared};
2use crate::time::error::InsertError;
3use crate::util::linked_list::LinkedList;
4
5mod level;
6pub(crate) use self::level::Expiration;
7use self::level::Level;
8
9use std::ptr::NonNull;
10
11use super::entry::STATE_DEREGISTERED;
12
13#[derive(Debug)]
22pub(crate) struct Wheel {
23 elapsed: u64,
25
26 levels: Box<[Level; NUM_LEVELS]>,
37
38 pending: LinkedList<TimerShared>,
40}
41
42const NUM_LEVELS: usize = 6;
46
47const BITS_PER_LEVEL: usize = 6;
48
49const MAX_DURATION: u64 = 1 << (BITS_PER_LEVEL * NUM_LEVELS);
51
52impl Wheel {
53 pub(crate) fn new() -> Wheel {
55 let levels = (0..NUM_LEVELS).map(Level::new).collect::<Box<_>>();
56 Wheel {
57 elapsed: 0,
58 levels: levels.try_into().unwrap(),
59 pending: LinkedList::new(),
60 }
61 }
62
63 pub(crate) fn elapsed(&self) -> u64 {
66 self.elapsed
67 }
68
69 pub(crate) unsafe fn insert(
89 &mut self,
90 item: TimerHandle,
91 ) -> Result<u64, (TimerHandle, InsertError)> {
92 let when = unsafe { item.sync_when() };
93
94 if when <= self.elapsed {
95 return Err((item, InsertError::Elapsed));
96 }
97
98 let level = self.level_for(when);
100
101 unsafe {
102 self.levels[level].add_entry(item);
103 }
104
105 debug_assert!({
106 self.levels[level]
107 .next_expiration(self.elapsed)
108 .is_none_or(|e| e.deadline >= self.elapsed)
109 });
110
111 Ok(when)
112 }
113
114 pub(crate) unsafe fn remove(&mut self, item: NonNull<TimerShared>) {
116 unsafe {
117 let when = item.as_ref().registered_when();
118 if when == STATE_DEREGISTERED {
119 self.pending.remove(item);
120 } else {
121 debug_assert!(
122 self.elapsed <= when,
123 "elapsed={}; when={}",
124 self.elapsed,
125 when
126 );
127
128 let level = self.level_for(when);
129 self.levels[level].remove_entry(item);
130 }
131 }
132 }
133
134 pub(crate) fn poll_at(&self) -> Option<u64> {
136 self.next_expiration().map(|expiration| expiration.deadline)
137 }
138
139 pub(crate) fn poll(&mut self, now: u64) -> Option<TimerHandle> {
141 loop {
142 if let Some(handle) = self.pending.pop_back() {
143 return Some(handle);
144 }
145
146 match self.next_expiration() {
147 Some(ref expiration) if expiration.deadline <= now => {
148 self.process_expiration(expiration, now);
149
150 if now != u64::MAX {
156 self.set_elapsed(expiration.deadline);
157 }
158 }
159 _ => {
160 self.set_elapsed(now);
165 break;
166 }
167 }
168 }
169
170 self.pending.pop_back()
171 }
172
173 fn next_expiration(&self) -> Option<Expiration> {
175 if !self.pending.is_empty() {
176 return Some(Expiration {
178 level: 0,
179 slot: 0,
180 deadline: self.elapsed,
181 });
182 }
183
184 for (level_num, level) in self.levels.iter().enumerate() {
186 if let Some(expiration) = level.next_expiration(self.elapsed) {
187 debug_assert!(self.no_expirations_before(level_num + 1, expiration.deadline));
190
191 return Some(expiration);
192 }
193 }
194
195 None
196 }
197
198 pub(super) fn next_expiration_time(&self) -> Option<u64> {
201 self.next_expiration().map(|ex| ex.deadline)
202 }
203
204 fn no_expirations_before(&self, start_level: usize, before: u64) -> bool {
206 let mut res = true;
207
208 for level in &self.levels[start_level..] {
209 if let Some(e2) = level.next_expiration(self.elapsed) {
210 if e2.deadline < before {
211 res = false;
212 }
213 }
214 }
215
216 res
217 }
218
219 pub(crate) fn process_expiration(&mut self, expiration: &Expiration, now: u64) {
224 let mut entries = self.take_entries(expiration);
235 let deadline = if now == u64::MAX {
236 now
237 } else {
238 expiration.deadline
239 };
240
241 while let Some(item) = entries.pop_back() {
242 if expiration.level == 0 && now != u64::MAX {
243 debug_assert_eq!(unsafe { item.registered_when() }, expiration.deadline);
244 }
245
246 match unsafe { item.mark_pending(deadline) } {
249 Ok(()) => {
250 self.pending.push_front(item);
252 }
253 Err(expiration_tick) => {
254 let level = level_for(expiration.deadline, expiration_tick);
255 unsafe {
256 self.levels[level].add_entry(item);
257 }
258 }
259 }
260 }
261 }
262
263 fn set_elapsed(&mut self, when: u64) {
264 assert!(
265 self.elapsed <= when,
266 "elapsed={:?}; when={:?}",
267 self.elapsed,
268 when
269 );
270
271 if when > self.elapsed {
272 self.elapsed = when;
273 }
274 }
275
276 fn take_entries(&mut self, expiration: &Expiration) -> LinkedList<TimerShared> {
278 self.levels[expiration.level].take_slot(expiration.slot)
279 }
280
281 fn level_for(&self, when: u64) -> usize {
282 level_for(self.elapsed, when)
283 }
284}
285
286fn level_for(elapsed: u64, when: u64) -> usize {
287 const SLOT_MASK: u64 = (1 << BITS_PER_LEVEL) - 1;
288
289 let masked = elapsed ^ when | SLOT_MASK;
292
293 if masked >= MAX_DURATION {
294 return NUM_LEVELS - 1;
296 }
297
298 masked.ilog2() as usize / BITS_PER_LEVEL
299}
300
301#[cfg(all(test, not(loom)))]
302mod test {
303 use std::pin::Pin;
304
305 use super::*;
306
307 #[test]
308 fn test_level_for() {
309 for pos in 0..64 {
310 assert_eq!(0, level_for(0, pos), "level_for({pos}) -- binary = {pos:b}");
311 }
312
313 for level in 1..5 {
314 for pos in level..64 {
315 let a = pos * 64_usize.pow(level as u32);
316 assert_eq!(
317 level,
318 level_for(0, a as u64),
319 "level_for({a}) -- binary = {a:b}"
320 );
321
322 if pos > level {
323 let a = a - 1;
324 assert_eq!(
325 level,
326 level_for(0, a as u64),
327 "level_for({a}) -- binary = {a:b}"
328 );
329 }
330
331 if pos < 64 {
332 let a = a + 1;
333 assert_eq!(
334 level,
335 level_for(0, a as u64),
336 "level_for({a}) -- binary = {a:b}"
337 );
338 }
339 }
340 }
341 }
342
343 #[must_use]
344 fn insert_entry(wheel: &mut Wheel, when: u64) -> Pin<Box<TimerShared>> {
345 let entry = Box::pin(TimerShared::new());
346
347 unsafe { entry.set_expiration(when) };
348
349 unsafe { wheel.insert(entry.as_ref().handle()).unwrap() };
350
351 entry
352 }
353
354 #[test]
355 fn test_next_expiration_to_level_4() {
356 let wheel = &mut Wheel::new();
357
358 let when = (1 << 24) + 10;
360
361 let _entry = insert_entry(wheel, when);
362
363 let expiration = wheel.next_expiration_time();
364 assert_eq!(expiration, Some(1 << 24));
366
367 wheel.poll(1 << 24);
369
370 let expiration = wheel.next_expiration_time();
371 assert_eq!(expiration, Some(when));
373
374 wheel.poll(when);
375
376 assert!(wheel.next_expiration().is_none());
377 }
378
379 #[test]
380 fn test_next_expiration_to_level_5() {
381 let wheel = &mut Wheel::new();
382
383 let when = (1 << 30) + 10;
385 let _entry = insert_entry(wheel, when);
386
387 let expiration = wheel.next_expiration_time();
388
389 assert_eq!(expiration, Some(1 << 30));
390
391 wheel.poll(1 << 30);
393
394 let expiration = wheel.next_expiration_time();
395
396 assert_eq!(expiration, Some((1 << 30) + 10));
397
398 wheel.poll(when);
399
400 assert!(wheel.next_expiration().is_none());
401 }
402
403 #[test]
404 fn test_next_expiration_after_level_5() {
405 let wheel = &mut Wheel::new();
406
407 let when = (1 << 36) + 5;
409 let _entry = insert_entry(wheel, when);
410
411 let expiration = wheel.next_expiration_time();
412
413 assert_eq!(expiration, Some(1 << 36));
415
416 wheel.poll(1 << 36);
418
419 let expiration = wheel.next_expiration_time();
420
421 assert_eq!(expiration, Some(when));
422
423 wheel.poll(when);
424
425 assert!(wheel.next_expiration_time().is_none());
426 }
427
428 #[test]
429 fn test_next_expiration_after_level_5_twice() {
430 let wheel = &mut Wheel::new();
431
432 let when = (1 << 37) + 5;
434 let _entry = insert_entry(wheel, when);
435
436 let expiration = wheel.next_expiration_time();
437
438 assert_eq!(expiration, Some(1 << 36));
440
441 wheel.poll(1 << 36);
443
444 let expiration = wheel.next_expiration_time();
445
446 assert_eq!(expiration, Some(1 << 37));
447
448 wheel.poll(1 << 37);
449
450 let expiration = wheel.next_expiration_time();
451
452 assert_eq!(expiration, Some(when));
453
454 wheel.poll(when);
455
456 assert!(wheel.next_expiration_time().is_none());
457 }
458
459 #[test]
460 fn test_next_expiration_to_level_5_and_after_level_5() {
461 let wheel = &mut Wheel::new();
462
463 let when = (1 << 36) + 1;
465 let _entry = insert_entry(wheel, when);
466
467 let when = (1 << 30) + 10;
469 let _entry = insert_entry(wheel, when);
470
471 let expiration = wheel.next_expiration_time();
472
473 assert_eq!(expiration, Some(1 << 30));
476
477 wheel.poll(1 << 30);
479
480 let expiration = wheel.next_expiration_time();
481
482 assert_eq!(expiration, Some((1 << 30) + 10));
483
484 wheel.poll(when);
485
486 let expiration = wheel.next_expiration_time();
487
488 assert_eq!(expiration, Some(1 << 36));
490 }
491
492 #[test]
493 fn test_next_expiration_at_slot_5_of_the_top_level() {
494 let wheel = &mut Wheel::new();
495
496 wheel.poll(5 << 30);
498
499 let when = (1 << 36) + (5 << 30) + 1;
503 let _entry = insert_entry(wheel, when);
504
505 let when = (20 << 30) + 10;
508 let _entry = insert_entry(wheel, when);
509
510 let expiration = wheel.next_expiration_time();
511
512 assert_eq!(expiration, Some(20 << 30));
515 }
516}