Skip to main content

Module timer_sleep

Module timer_sleep 

Source
Expand description

Timer-backed sleep / sleep_until futures — the RTEMS backend for crate::runtime::task::sleep / crate::runtime::task::sleep_until (decision A2, increment W3b item 4).

§Model

A hosted build sleeps via tokio::time::sleep, whose waker is driven by the tokio timer wheel. RTEMS has no such wheel, so a Sleep future arms a one-shot entry on the DelayedTimer: on its first poll it schedules a wakeup for its deadline; when that wakeup fires it wakes the future’s stored waker, and the next poll — now past the deadline — returns Ready. This is the same deadline-ordered timer thread that backs C callbackRequestDelayed (callback.c:410-419); a Sleep is just that facility with the “callback” being “wake this future”.

§Why the wakeup runs on the timer thread, not the callback pool

The wakeup is armed via TimerHandle::schedule_wake, so it runs inline on the timer thread rather than being dispatched to the callback pool. Waking is a non-blocking waker.wake() (an unpark for a park_on driver, a task re-enqueue for super::future_exec, or a tokio task-schedule) and needs no worker, so it does not take one. Routing the wake off the band keeps the band’s sole job “run futures” and makes the wake uniform for every sleeper — bare spawned tails and periodic-scan interval alike.

This is also what closed the sleep-wake self-deadlock (bug_pattern rtems-exec-sleep-wake-band-deadlock): back when future_exec parked a pool worker for a spawned future’s whole life, a wake dispatched to the same single-worker band sat behind the very worker it had to wake. That executor is cooperative now and releases its worker at every suspension, so the wake would no longer starve — but a wake that costs a worker is still the wrong shape, and Inline remains the rule.

§Lazy arming and drop-cancel

The deadline is fixed when the Sleep is constructed (now + dur for sleep, the given instant for sleep_until), matching tokio, but the timer entry is armed lazily on the first poll — a Sleep that is created and dropped without ever being awaited schedules nothing.

A Sleep owns the queue entry it arms: TimerHandle::schedule_wake hands back a WakeKey, and Sleep’s Drop both clears the stored waker and cancels that key. Clearing the waker is what makes the cancel clean — a wake that races the drop finds no waker and wakes nobody — and cancelling the key is what makes it free: the entry holds a clone of the shared Arc<Mutex<SleepState>>, so leaving it queued keeps that cell and the OS mutex inside it alive for the entire remaining delay.

That retention is not theoretical and not small. A select! arm holding a long-period interval tick re-arms a fresh Sleep on every loop iteration and drops it when another arm wins, so an uncancellable entry accumulates at the loop’s iteration rate for the whole period. Measured on VxWorks 7 against the PVA search engine’s 180 s BEACON_CLEAN_INTERVAL tick: ~124 live entries at ~184 B each, released in one batch every 180 s (doc/vxworks-dial-attempt-residue-on-target-measurement.md).

Cancellation is a property of the wake path only. TimerHandle::schedule — C callbackRequestDelayed (callback.c:410-419) — stays fire-and-forget, because there the caller keeps no handle and the queue is the only owner.

Structs§

Sleep
A future that completes at a fixed deadline, driven by the delayed-callback timer — the RTEMS-side mirror of tokio::time::Sleep.
TimerInterval
A periodic ticker over the delayed-callback timer — the RTEMS backend for crate::runtime::task::interval. Mirrors tokio::time::Interval with its default MissedTickBehavior::Burst: the first tick is immediate and tick deadlines are anchored at construction (start + period, start + 2·period, …), so an overdue tick fires immediately and successive overdue ticks burst back-to-back until the schedule is caught up.

Functions§

interval
Build a periodic ticker firing every period, backed by timer — the runtime-free mirror of tokio::time::interval.
sleep
A future completing dur from now — mirrors tokio::time::sleep. The deadline is fixed at construction; the timer entry arms on first poll.
sleep_until
A future completing at deadline — mirrors tokio::time::sleep_until. A deadline already in the past makes the future ready on its first poll without arming a timer entry.