netstack3_base/time.rs
1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Common time abstractions.
6
7pub(crate) mod local_timer_heap;
8#[cfg(any(test, feature = "testutils"))]
9pub(crate) mod testutil;
10
11use core::fmt::Debug;
12use core::marker::PhantomData;
13use core::sync::atomic::Ordering;
14use core::time::Duration;
15
16use crate::inspect::InspectableValue;
17
18/// A type representing an instant in time.
19///
20/// `Instant` can be implemented by any type which represents an instant in
21/// time. This can include any sort of real-world clock time (e.g.,
22/// [`std::time::Instant`]) or fake time such as in testing.
23pub trait Instant:
24 Sized + Ord + Copy + Clone + Debug + Send + Sync + InspectableValue + 'static
25{
26 /// Returns the amount of time elapsed from another instant to this one.
27 ///
28 /// Returns `None` if `earlier` is not before `self`.
29 fn checked_duration_since(&self, earlier: Self) -> Option<Duration>;
30
31 /// Returns the amount of time elapsed from another instant to this one,
32 /// saturating at zero.
33 fn saturating_duration_since(&self, earlier: Self) -> Duration {
34 self.checked_duration_since(earlier).unwrap_or_default()
35 }
36
37 /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be
38 /// represented as `Instant` (which means it's inside the bounds of the
39 /// underlying data structure), `None` otherwise.
40 fn checked_add(&self, duration: Duration) -> Option<Self>;
41
42 /// Returns the instant at `self + duration` saturating to the maximum
43 /// representable instant value.
44 fn saturating_add(&self, duration: Duration) -> Self;
45
46 /// Unwraps the result from `checked_add`.
47 ///
48 /// # Panics
49 ///
50 /// This function will panic if the addition makes the clock wrap around.
51 fn panicking_add(&self, duration: Duration) -> Self {
52 self.checked_add(duration).unwrap_or_else(|| {
53 panic!("clock wraps around when adding {:?} to {:?}", duration, *self);
54 })
55 }
56
57 /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be
58 /// represented as `Instant` (which means it's inside the bounds of the
59 /// underlying data structure), `None` otherwise.
60 fn checked_sub(&self, duration: Duration) -> Option<Self>;
61}
62
63/// A type representing an instant in time that can be atomically updated.
64pub trait AtomicInstant<I: Instant>: Debug {
65 /// Instantiates [`Self`] from the given instant.
66 fn new(instant: I) -> Self;
67
68 /// Loads an [`Instant`], atomically.
69 fn load(&self, ordering: Ordering) -> I;
70
71 /// Stores an [`Instant`], atomically,
72 fn store(&self, instant: I, ordering: Ordering);
73
74 /// Store the maximum of the current value and the provided value.
75 fn store_max(&self, instant: I, ordering: Ordering);
76}
77
78/// Trait defining the `Instant` type provided by bindings' [`InstantContext`]
79/// implementation.
80///
81/// It is a separate trait from `InstantContext` so the type stands by itself to
82/// be stored at rest in core structures.
83pub trait InstantBindingsTypes {
84 /// The type of an instant in time.
85 ///
86 /// All time is measured using `Instant`s, including scheduling timers
87 /// through [`TimerContext`]. This type may represent some sort of
88 /// real-world time (e.g., [`std::time::Instant`]), or may be faked in
89 /// testing using a fake clock.
90 type Instant: Instant + 'static;
91
92 /// An atomic representation of [`Self::Instant`].
93 type AtomicInstant: AtomicInstant<Self::Instant>;
94}
95
96/// A context that provides access to a monotonic clock.
97pub trait InstantContext: InstantBindingsTypes {
98 /// Returns the current instant.
99 ///
100 /// `now` guarantees that two subsequent calls to `now` will return
101 /// monotonically non-decreasing values.
102 fn now(&self) -> Self::Instant;
103
104 /// Returns the current instant, as an [`Self::AtomicInstant`].
105 fn now_atomic(&self) -> Self::AtomicInstant {
106 Self::AtomicInstant::new(self.now())
107 }
108}
109
110/// Opaque types provided by bindings used by [`TimerContext`].
111pub trait TimerBindingsTypes {
112 /// State for a timer created through [`TimerContext`].
113 type Timer: Debug + Send + Sync;
114 /// The type used to dispatch fired timers from bindings to core.
115 type DispatchId: Clone;
116 /// A value that uniquely identifiers a `Timer`. It is given along with the
117 /// `DispatchId` whenever a timer is fired.
118 ///
119 /// See [`TimerContext::unique_timer_id`] for details.
120 type UniqueTimerId: PartialEq + Eq;
121}
122
123/// A context providing time scheduling to core.
124pub trait TimerContext: InstantContext + TimerBindingsTypes {
125 /// Creates a new timer that dispatches `id` back to core when fired.
126 ///
127 /// Creating a new timer is an expensive operation and should be used
128 /// sparingly. Modules should prefer to create a timer on creation and then
129 /// schedule/reschedule it as needed. For modules with very dynamic timers,
130 /// a [`LocalTimerHeap`] tied to a larger `Timer` might be a better
131 /// alternative than creating many timers.
132 fn new_timer(&mut self, id: Self::DispatchId) -> Self::Timer;
133
134 /// Schedule a timer to fire at some point in the future.
135 /// Returns the previously scheduled instant, if this timer was scheduled.
136 fn schedule_timer_instant(
137 &mut self,
138 time: Self::Instant,
139 timer: &mut Self::Timer,
140 ) -> Option<Self::Instant>;
141
142 /// Like [`schedule_timer_instant`] but schedules a time for `duration` in
143 /// the future.
144 fn schedule_timer(
145 &mut self,
146 duration: Duration,
147 timer: &mut Self::Timer,
148 ) -> Option<Self::Instant> {
149 self.schedule_timer_instant(self.now().checked_add(duration).unwrap(), timer)
150 }
151
152 /// Cancel a timer.
153 ///
154 /// Cancels `timer`, returning the instant it was scheduled for if it was
155 /// scheduled.
156 ///
157 /// Note that there's no guarantee that observing `None` means that the
158 /// dispatch procedure for a previously fired timer has already concluded.
159 /// It is possible to observe `None` here while the `DispatchId` `timer`
160 /// was created with is still making its way to the module that originally
161 /// scheduled this timer. If `Some` is observed, however, then the
162 /// `TimerContext` guarantees this `timer` will *not* fire until
163 ///[`schedule_timer_instant`] is called to reschedule it.
164 fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant>;
165
166 /// Get the instant a timer will fire, if one is scheduled.
167 fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant>;
168
169 /// Retrieves the timer id for `timer`.
170 ///
171 /// This can be used with [`TimerHandler::handle_timer`] to match a
172 /// [`Self::Timer`] instance with a firing event.
173 fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId;
174}
175
176/// A handler for timer firing events.
177///
178/// A `TimerHandler` is a type capable of handling the event of a timer firing.
179///
180/// `TimerHandler` is offered as a blanket implementation for all timers that
181/// implement [`HandleableTimer`]. `TimerHandler` is meant to be used as bounds
182/// on core context types. whereas `HandleableTimer` allows split-crate
183/// implementations sidestepping coherence issues.
184pub trait TimerHandler<BC: TimerBindingsTypes, Id> {
185 /// Handle a timer firing.
186 ///
187 /// `dispatch` is the firing timer's dispatch identifier, i.e., a
188 /// [`HandleableTimer`].
189 ///
190 /// `timer` is the unique timer identifier for the
191 /// [`TimerBindingsTypes::Timer`] that scheduled this operation.
192 fn handle_timer(&mut self, bindings_ctx: &mut BC, dispatch: Id, timer: BC::UniqueTimerId);
193}
194
195impl<Id, CC, BC> TimerHandler<BC, Id> for CC
196where
197 BC: TimerBindingsTypes,
198 Id: HandleableTimer<CC, BC>,
199{
200 fn handle_timer(&mut self, bindings_ctx: &mut BC, dispatch: Id, timer: BC::UniqueTimerId) {
201 dispatch.handle(self, bindings_ctx, timer)
202 }
203}
204
205/// A timer that can be handled by a pair of core context `CC` and bindings
206/// context `BC`.
207///
208/// This trait exists to sidestep coherence issues when dealing with timer
209/// layers, see [`TimerHandler`] for more.
210pub trait HandleableTimer<CC, BC: TimerBindingsTypes> {
211 /// Handles this timer firing.
212 ///
213 /// `timer` is the unique timer identifier for the
214 /// [`TimerBindingsTypes::Timer`] that scheduled this operation.
215 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId);
216}
217
218/// A core context providing timer type conversion.
219///
220/// This trait is used to convert from a core-internal timer type `T` to the
221/// timer dispatch ID supported by bindings in `BT::DispatchId`.
222pub trait CoreTimerContext<T, BT: TimerBindingsTypes> {
223 /// Converts an inner timer to the bindings timer type.
224 fn convert_timer(dispatch_id: T) -> BT::DispatchId;
225
226 /// A helper function to create a new timer with the provided dispatch id.
227 fn new_timer(bindings_ctx: &mut BT, dispatch_id: T) -> BT::Timer
228 where
229 BT: TimerContext,
230 {
231 bindings_ctx.new_timer(Self::convert_timer(dispatch_id))
232 }
233}
234
235/// An uninstantiable type that performs conversions based on `Into`
236/// implementations.
237pub enum IntoCoreTimerCtx {}
238
239impl<T, BT> CoreTimerContext<T, BT> for IntoCoreTimerCtx
240where
241 BT: TimerBindingsTypes,
242 T: Into<BT::DispatchId>,
243{
244 fn convert_timer(dispatch_id: T) -> BT::DispatchId {
245 dispatch_id.into()
246 }
247}
248
249/// An uninstantiable type that performs conversions based on `Into`
250/// implementations and an available outer [`CoreTimerContext`] `CC`.
251pub struct NestedIntoCoreTimerCtx<CC, N>(!, PhantomData<(CC, N)>);
252
253impl<CC, N, T, BT> CoreTimerContext<T, BT> for NestedIntoCoreTimerCtx<CC, N>
254where
255 BT: TimerBindingsTypes,
256 CC: CoreTimerContext<N, BT>,
257 T: Into<N>,
258{
259 fn convert_timer(dispatch_id: T) -> BT::DispatchId {
260 CC::convert_timer(dispatch_id.into())
261 }
262}