@@ -113,24 +113,52 @@ pub trait Driver: Send + Sync + 'static {
113
113
/// It is UB to make the alarm fire before setting a callback.
114
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
117
/// The callback may be called from any context (interrupt or thread mode).
118
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
121
- /// timestamp, the provided callback function will be called.
120
+ /// Set an alarm at the given timestamp.
122
121
///
123
- /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`.
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.)
122
+ /// ## Behavior
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
162
fn set_alarm ( & self , alarm : AlarmHandle , timestamp : u64 ) -> bool ;
135
163
}
136
164
0 commit comments