Module async::timer
async: timers (Sleep, Interval, a timer queue)
A TimerQueue is the clock-and-deadlines half of an executor: futures register "wake me at time T" there, and the executor advances it with the time its Park source reports (std/async/executor.h), which fires the due wakers. Every executor in std/async owns one and hands it to the futures it polls through Context::timers, so
struct Sleep s = Sleep::new(250LL); // ms; the deadline is fixed at first poll
AWAIT(1, self.s); // inside a coroutine (coro.h)
needs no handle to anything. Times are milliseconds on the executor's clock (a monotonic clock on a hosted target, whatever the Park source counts on bare metal). The queue only knows the time it was last advanced to, which keeps it deterministic: a test can drive it with a fake clock.
The queue is std/dsp/timer_wheel.h's TimerWheel with a 1 ms tick (WHEEL_TIMERS = 64 concurrent timers), advanced in jumps from one due timer to the next rather than tick by tick. A Sleep that finds the wheel full waits in the queue's overflow list (ASYNC_WAITERS more) and retries when a slot frees up or its deadline comes; past that it re-polls until its deadline (correct, but busy). All operations take the queue's spinlock, so a multi-threaded executor's workers share one queue.
Structs
| Sleep | Ready (with UNIT) once 'ms' milliseconds have passed since its first poll (Rust's tokio::time::sleep). Needs a context with timers. |
| Interval | A periodic timer (tokio::time::interval): every poll that returns Ready gives the number of the tick (1, 2, 3, ...), one per 'period_ms', the first one 'period_ms' after the first poll. Unlike a plain future it is polled again after Ready — it is a stream of ticks. Missed ticks (the task was busy) are delivered back to back, then the schedule continues (tokio's MissedTickBehavior::Burst). |