UXTimerScheduler
UXTimerScheduler holds UXTimers.
tick fires every timer that is due; nextFireTime
returns when the next one is.
#use <UXKit> // or #import "UXTimer.xc"Overview
Section titled “Overview”UXTimerScheduler* s = new UXTimerScheduler();s.schedule(UXTimer.oneShot(100, &h.onOnce));s.schedule(UXTimer.every(100, 50, &h.onEvery));
s.nextFireTime(); // 100s.tick(50); // 0 fires — nothing is dues.tick(100); // 2 firesIt has no clock
Section titled “It has no clock”The time is passed in, and the rest of the design follows from that.
A scheduler that read the clock itself could only be tested by waiting. This one
is a pure function of (timers, now), so all of the firing logic (catch-up,
rescheduling, pruning) runs headless in microseconds against synthetic time.
The driver supplies the real clock at the one call site that needs it. A backend with an unusual source of time changes that one line, not the scheduler.
Backlogged repeaters catch up
Section titled “Backlogged repeaters catch up”tick(100) -> repeater firestick(260) -> fires THREE times: it owed 150, 200 and 250A repeating timer that fell behind fires once for every interval it missed.
tick loops while the timer is still due.
This is correct for anything that counts, such as an animation frame counter or
a timeout accumulating elapsed time: the number of fires equals the number of
intervals that passed, regardless of when tick was called.
Calling invalidate inside a
handler stops the catch-up immediately. The loop tests validity on each pass, so
the timer stops at once instead of after the backlog drains.
One-shots prune themselves
Section titled “One-shots prune themselves”A one-shot invalidates when it fires, and tick removes every invalid timer
after the pass. A scheduler therefore does not accumulate spent timers, and
activeCount drops without any cleanup code.
Pruning happens after the firing loop, so invalidating during a handler is safe: nothing is removed from the array while it is being walked.
nextFireTime is how the run loop sleeps
Section titled “nextFireTime is how the run loop sleeps”i32 next = s.nextFireTime(); // -1 when nothing is scheduled-1 means nothing pending, so the run loop may block indefinitely waiting for
input instead of spinning. Any other value is an absolute time, and the sleep is
next - now clamped at zero.
This lets an idle application use no CPU instead of waking many times a second to find nothing to do.
Topics
Section titled “Topics”schedule · tick · nextFireTime · activeCount
schedule
Section titled “schedule”void schedule(UXTimer* t)Adds a timer. The scheduler holds it strongly until it is invalidated and pruned, so the caller does not need to keep a one-shot alive.
A timer whose fire time has already passed can be scheduled; it fires on the
next tick.
i32 tick(i32 nowMs)Fires every timer that is due, reschedules repeaters, invalidates one-shots, and prunes invalid timers. Returns the number of fires, which exceeds the number of timers when repeaters caught up.
Time is in milliseconds, absolute rather than a delta. The scheduler compares times instead of accumulating them, so an occasional missed tick does not make timers drift.
nextFireTime
Section titled “nextFireTime”i32 nextFireTime(void)The earliest pending fire time, or -1.
activeCount
Section titled “activeCount”i32 activeCount(void)The number of valid timers. Invalid timers are pruned on the next tick, so
between a manual invalidate and that tick the array holds more entries than
this count.
Example
Section titled “Example”active: 2 next fire at: 100tick(50) -> nothing is due yet fires: 0tick(100) -> both are due fires: 2 active now: 1 (the one-shot pruned itself)tick(260) -> the repeater catches up fires: 3The three fires at tick(260) are the intervals at 150, 200 and 250. The
program is website/site/examples/uxkit/timers.xc. The doc-examples gate
compiles it, and the output above is what it prints.
Conforms to
Section titled “Conforms to”- A plain class (not an
Objectsubclass)
See also
Section titled “See also”UXTimer: one scheduled callbackUXOperationQueue: the other deterministic scheduler, ordered by dependency rather than timeUXDate: wall-clock time, where this is elapsed milliseconds