#[repr(transparent)]pub struct Timer<System: NotSupportedYet>(_);
Expand description
Represents a single timer in a system.
This type is ABI-compatible with System::
RawTimerId
.
See TimerRef
for the borrowed counterpart.
See TimerMethods
for the operations provided by this handle
type.
Relation to Other Specifications: A similar concept exists in almost every operating system.
Timer States
A timer may be in one of the following states:
-
Dormant — The timer is not running and can be started.
-
Active — The timer is running and can be stopped.
Timer Scheduling
The scheduling of a timer is determined by two state variables:
-
The delay is an optional non-negative duration value (
Option<Duration>
) that specifies the minimum period of time before the callback function gets called.If the delay is
None
, it’s treated as infinity and the function will never execute.While a timer is active, this value decreases at a steady rate. If the system can’t process a timer for an extended period of time, this value might temporarily fall negative.
-
The period is an optional non-negative duration value. On expiration, the system adds this value to the timer’s delay.
Overdue Timers
When scheduling a next tick, the system takes the observed timer handling latency into account and makes the new delay shorter than the period as needed to ensure that the callback function is called in a steady rate. This behavior is illustrated by the above figure. This is accomplished by adding the specified period to the timer’s absolute arrival time instead of recalculating the arrival time based on the current system time. The delay is a difference between the current system time and the arrival time.
Note that the system does not impose any limit on the extent of this behavior. To put this simply, if one second elapses, the system makes one second worth of calls no matter what. If a periodic timer’s callback function couldn’t complete within the timer’s period, the timer latency would steadily increase until it reaches the point where various internal assumptions get broken. While the system is processing overdue calls, the timer interrupt handler might not return. Some kernel timer drivers (most notably the Arm-M tickful SysTick driver) have much lower tolerance for this. To avoid this catastrophic situation, an application should take the precautions shown below:
-
Don’t perform an operation that might take an unbounded time in a timer callback function.
-
Off-load time-consuming operations to a task, which is activated or unparked by a timer callback function.
-
Don’t specify zero as period unless you know what you are doing.
-
Keep your target platform’s performance characteristics in your mind.
Start/Stop
When a timer is stopped, the timer will not fire anymore and the delay remains stationary at the captured value. If the captured value is negative, it’s rounded to zero. This means that if there are more than one outstanding call at the moment of stopping, they will be dropped.
Another way to stop a timer is to set the delay or the period to None
(infinity).
Dynamic Period
The period can be changed anytime. The system reads it before calling a timer callback function and adds it to the timer’s current delay value.
It might be tricky to understand the outcome of changing the period when there are overdue calls. It could be explained in this way: If there are one second worth of calls pending, there will still be one second worth of calls pending after changing the period.
Infinite Delay and/or Period
If delay
is set to None
(infinity), the timer will stop firing. Note
that the timer is still in the Active state, and the correct way to restart
this timer is to reset the delay to a finite value.
If period
is set to None
instead, the timer will stop firing after the
next tick.
Examples
Periodic Timer
use r3_core::{kernel::{Cfg, StaticTimer, traits}, time::Duration};
const fn configure<C>(b: &mut Cfg<C>) -> StaticTimer<C::System>
where
C: ~const traits::CfgTimer,
{
StaticTimer::define()
.delay(Duration::from_millis(70))
.period(Duration::from_millis(40))
.active(true)
.start(|| dbg!())
.finish(b)
}
One-Shot Timer
use r3_core::{kernel::{Cfg, StaticTimer, traits, prelude::*}, time::Duration};
const fn configure<C>(b: &mut Cfg<C>) -> StaticTimer<C::System>
where
C: ~const traits::CfgTimer,
{
StaticTimer::define()
.active(true)
.start(|| dbg!())
.finish(b)
}
Reset the delay to schedule a call.
use r3_core::{kernel::{TimerRef, traits, prelude::*}, time::Duration};
fn sched<System: traits::KernelTimer>(timer: TimerRef<'_, System>) {
timer.set_delay(Some(Duration::from_millis(40))).unwrap();
}
Trait Implementations§
source§impl<System: NotSupportedYet> PartialEq<Timer<System>> for Timer<System>
impl<System: NotSupportedYet> PartialEq<Timer<System>> for Timer<System>
source§impl<System: NotSupportedYet> PartialEq<Timer<System>> for TimerRef<'_, System>
impl<System: NotSupportedYet> PartialEq<Timer<System>> for TimerRef<'_, System>
source§impl<System: NotSupportedYet> PartialEq<TimerRef<'_, System>> for Timer<System>
impl<System: NotSupportedYet> PartialEq<TimerRef<'_, System>> for Timer<System>
source§impl<System: NotSupportedYet> TimerHandle for Timer<System>
impl<System: NotSupportedYet> TimerHandle for Timer<System>
source§const unsafe fn from_id(id: <System as KernelTimer>::RawTimerId) -> Self
const unsafe fn from_id(id: <System as KernelTimer>::RawTimerId) -> Self
source§const fn id(&self) -> System::RawTimerId
const fn id(&self) -> System::RawTimerId
RawTimerId
value representing this object.