pub trait Driver:
Send
+ Sync
+ 'static {
// Required methods
fn now(&self) -> u64;
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>;
fn set_alarm_callback(
&self,
alarm: AlarmHandle,
callback: fn(_: *mut ()),
ctx: *mut (),
);
fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool;
}
Expand description
Time driver
Required Methods§
sourcefn now(&self) -> u64
fn now(&self) -> u64
Return the current timestamp in ticks.
Implementations MUST ensure that:
- This is guaranteed to be monotonic, i.e. a call to now() will always return a greater or equal value than earlier calls. Time can’t “roll backwards”.
- It “never” overflows. It must not overflow in a sufficiently long time frame, say in 10_000 years (Human civilization is likely to already have self-destructed 10_000 years from now.). This means if your hardware only has 16bit/32bit timers you MUST extend them to 64-bit, for example by counting overflows in software, or chaining multiple timers together.
sourceunsafe fn allocate_alarm(&self) -> Option<AlarmHandle>
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>
Try allocating an alarm handle. Returns None if no alarms left.
Initially the alarm has no callback set, and a null ctx
pointer.
§Safety
It is UB to make the alarm fire before setting a callback.
sourcefn set_alarm_callback(
&self,
alarm: AlarmHandle,
callback: fn(_: *mut ()),
ctx: *mut (),
)
fn set_alarm_callback( &self, alarm: AlarmHandle, callback: fn(_: *mut ()), ctx: *mut (), )
Set the callback function to be called when the alarm triggers. The callback may be called from any context (interrupt or thread mode).
sourcefn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool
fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool
Set an alarm at the given timestamp.
§Behavior
If timestamp
is in the future, set_alarm
schedules calling the callback function
at that time, and returns true
.
If timestamp
is in the past, set_alarm
has two allowed behaviors. Implementations can pick whether to:
- Schedule calling the callback function “immediately”, as if the requested timestamp was “now+epsilon” and return
true
, or - Not schedule the callback, and return
false
.
Callers must ensure to behave correctly with either behavior.
When callback is called, it is guaranteed that now()
will return a value greater than or equal to timestamp
.
§Reentrancy
Calling the callback from set_alarm
synchronously is not allowed. If the implementation chooses the first option above,
it must still call the callback from another context (i.e. an interrupt handler or background thread), it’s not allowed
to call it synchronously in the context set_alarm
is running.
The reason for the above is callers are explicitly permitted to do both of:
- Lock a mutex in the alarm callback.
- Call
set_alarm
while having that mutex locked.
If set_alarm
called the callback synchronously, it’d cause a deadlock or panic because it’d cause the
mutex to be locked twice reentrantly in the same context.
§Overwriting alarms
Only one alarm can be active at a time for each AlarmHandle
. This overwrites any previously-set alarm if any.
§Unsetting the alarm
There is no unset_alarm
API. Instead, callers can call set_alarm
with timestamp
set to u64::MAX
.
This allows for more efficient implementations, since they don’t need to distinguish between the “alarm set” and “alarm not set” cases, thanks to the fact “Alarm set for u64::MAX” is effectively equivalent for “alarm not set”.
This means implementations need to be careful to avoid timestamp overflows. The recommendation is to make timestamp
be in the same units as hardware ticks to avoid any conversions, which makes avoiding overflow easier.