aboutsummaryrefslogtreecommitdiff
path: root/embassy-time-driver/src/lib.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-08-13 17:45:48 +0200
committerDario Nieuwenhuis <[email protected]>2024-09-11 01:36:11 +0200
commitd193c9ef44a61c9de381044fd2968a95ce2ffc75 (patch)
treed48f5532cf44e86f9d8c4ee236a6fbc7a179aa3b /embassy-time-driver/src/lib.rs
parent1ea29f1d2e94e85d87bbe45598a096d1f8da0f34 (diff)
time-driver: clarify docs for set_alarm.
Diffstat (limited to 'embassy-time-driver/src/lib.rs')
-rw-r--r--embassy-time-driver/src/lib.rs52
1 files changed, 40 insertions, 12 deletions
diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs
index aab2f626e..8000a9dcb 100644
--- a/embassy-time-driver/src/lib.rs
+++ b/embassy-time-driver/src/lib.rs
@@ -113,24 +113,52 @@ pub trait Driver: Send + Sync + 'static {
113 /// It is UB to make the alarm fire before setting a callback. 113 /// It is UB to make the alarm fire before setting a callback.
114 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>; 114 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>;
115 115
116 /// Sets the callback function to be called when the alarm triggers. 116 /// Set the callback function to be called when the alarm triggers.
117 /// The callback may be called from any context (interrupt or thread mode). 117 /// The callback may be called from any context (interrupt or thread mode).
118 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); 118 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
119 119
120 /// Sets an alarm at the given timestamp. When the current timestamp reaches the alarm 120 /// Set an alarm at the given timestamp.
121 /// timestamp, the provided callback function will be called.
122 /// 121 ///
123 /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`. 122 /// ## Behavior
124 /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set,
125 /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously.
126 /// There is a rare third possibility that the alarm was barely in the future, and by the time it was enabled, it had slipped into the
127 /// past. This is can be detected by double-checking that the alarm is still in the future after enabling it; if it isn't, `false`
128 /// should also be returned to indicate that the callback may have been called already by the alarm, but it is not guaranteed, so the
129 /// caller should also call the callback, just like in the more common `false` case. (Note: This requires idempotency of the callback.)
130 /// 123 ///
131 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. 124 /// If `timestamp` is in the future, `set_alarm` schedules calling the callback function
125 /// at that time, and returns `true`.
132 /// 126 ///
133 /// Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any. 127 /// If `timestamp` is in the past, `set_alarm` has two allowed behaviors. Implementations can pick whether to:
128 ///
129 /// - Schedule calling the callback function "immediately", as if the requested timestamp was "now+epsilon" and return `true`, or
130 /// - Not schedule the callback, and return `false`.
131 ///
132 /// Callers must ensure to behave correctly with either behavior.
133 ///
134 /// When callback is called, it is guaranteed that `now()` will return a value greater than or equal to `timestamp`.
135 ///
136 /// ## Reentrancy
137 ///
138 /// Calling the callback from `set_alarm` synchronously is not allowed. If the implementation chooses the first option above,
139 /// it must still call the callback from another context (i.e. an interrupt handler or background thread), it's not allowed
140 /// to call it synchronously in the context `set_alarm` is running.
141 ///
142 /// The reason for the above is callers are explicitly permitted to do both of:
143 /// - Lock a mutex in the alarm callback.
144 /// - Call `set_alarm` while having that mutex locked.
145 ///
146 /// If `set_alarm` called the callback synchronously, it'd cause a deadlock or panic because it'd cause the
147 /// mutex to be locked twice reentrantly in the same context.
148 ///
149 /// ## Overwriting alarms
150 ///
151 /// Only one alarm can be active at a time for each `AlarmHandle`. This overwrites any previously-set alarm if any.
152 ///
153 /// ## Unsetting the alarm
154 ///
155 /// There is no `unset_alarm` API. Instead, callers can call `set_alarm` with `timestamp` set to `u64::MAX`.
156 ///
157 /// This allows for more efficient implementations, since they don't need to distinguish between the "alarm set" and
158 /// "alarm not set" cases, thanks to the fact "Alarm set for u64::MAX" is effectively equivalent for "alarm not set".
159 ///
160 /// This means implementations need to be careful to avoid timestamp overflows. The recommendation is to make `timestamp`
161 /// be in the same units as hardware ticks to avoid any conversions, which makes avoiding overflow easier.
134 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool; 162 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool;
135} 163}
136 164