Skip to main content

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}