maitake/time/clock.rs
1//! [`Clock`]s provide a mechanism for tracking the current time.
2//!
3//! See the documentation for the [`Clock`] type for more details.
4use super::{
5 timer::{self, TimerError},
6 Duration,
7};
8use core::{
9 fmt,
10 ops::{Add, AddAssign, Sub, SubAssign},
11};
12
13/// A hardware clock definition.
14///
15/// A `Clock` consists of a function that returns the hardware clock's current
16/// timestamp in [`Ticks`] (`now()`), and a [`Duration`] that defines the amount
17/// of time represented by a single tick of the clock.
18///
19/// # Using `Clock`s
20///
21/// A `Clock` must be provided when [constructing a `Timer`](super::Timer::new).
22/// The `Clock` provided to [`Timer::new`](super::Timer::new) is used to
23/// determine the time to advance to when turning the timer wheel, and to
24/// determine the start time when adding a [`Sleep`](super::Sleep) future to the
25/// timer wheel.
26///
27/// In addition, once a global timer is set using the
28/// [`set_global_timer`](super::set_global_timer) function, the
29/// [`Instant::now()`] function may be used to produce [`Instant`]s representing
30/// the current timestamp according to that timer's [`Clock`]. The [`Instant`]
31/// type is analogous to the [`std::time::Instant`] type in the Rust standard
32/// library, and may be used to compare the time elapsed between two events, as
33/// a timestamp for logs and other diagnostics, and similar purposes.
34///
35/// # Implementing `now()`
36///
37/// Constructing a [new `Clock` definition](Self::new) takes a function, called
38/// `now()`, that returns the current hardware timestamp in a 64-bit number of,
39/// _ticks_. The period of time represented by a tick is indicated by the
40/// `tick_duration` argument to [`Clock::new`]. In order to define a `Clock`
41/// representing a particular hardware time source, a `now()` function must be
42/// implemented using that time source.
43///
44/// ## Monotonicity
45///
46/// Implementations of `now()` MUST ensure that timestamps returned by
47/// `now()` MUST be [monontonically non-decreasing][monotonic]. This means that
48/// a call to `now()` MUST NOT ever return a value less than the value returned
49/// by a previous call to`now()`.
50///
51/// Note that this means that timestamps returned by `now()` are expected
52/// not to overflow. Of course, all integers *will* overflow eventually, so
53/// this requirement can reasonably be weakened to expecting that timestamps
54/// returned by `now()` will not overflow unless the system has been running
55/// for a duration substantially longer than the system is expected to run
56/// for. For example, if a system is expected to run for as long as a year
57/// without being restarted, it's not unreasonable for timestamps returned
58/// by `now()` to overflow after, say, 100 years. Ideally, a general-purpose
59/// `Clock` implementation would not overflow for, say, 1,000 years.
60///
61/// The implication of this is that if the timestamp counters provided by
62/// the hardware platform are less than 64 bits wide (e.g., 16- or 32-bit
63/// timestamps), the `Clock` implementation is responsible for ensuring that
64/// they are extended to 64 bits, such as by counting overflows in the
65/// `Clock` implementation.
66///
67/// ## Examples
68///
69/// The simplest possible `Clock` implementation is one for a
70/// timestamp-counter-style hardware clock, where the timestamp counter is
71/// incremented on a fixed interval by the hardware. For such a counter, the
72/// `Clock` definition might look something like this:
73///
74///```rust
75/// use maitake::time::{Clock, Duration};
76/// # mod arch {
77/// # pub fn read_timestamp_counter() -> u64 { 0 }
78/// # pub const TIMESTAMP_COUNTER_FREQUENCY_HZ: u64 = 50_000_000;
79/// # }
80///
81/// // The fixed interval at which the timestamp counter is incremented.
82/// //
83/// // This is a made-up value; for real hardware, this value would be
84/// // determined from information provided by the hardware manufacturer,
85/// // and may need to be calculated based on the system's clock frequency.
86/// const TICK_DURATION: Duration = {
87/// let dur_ns = 1_000_000_000 / arch::TIMESTAMP_COUNTER_FREQUENCY_HZ;
88/// Duration::from_nanos(dur_ns)
89/// };
90///
91/// // Define a `Clock` implementation for the timestamp counter.
92/// let clock = Clock::new(TICK_DURATION, || {
93/// // A (pretend) function that reads the value of the timestamp
94/// // counter. In real life, this might be a specific instruction,
95/// // or a read from a timestamp counter register.
96/// arch::read_timestamp_counter()
97/// })
98/// // Adding a name to the clock definition allows it to be i
99/// // identified in fmt::Debug output.
100/// .named("timestamp-counter");
101///```
102///
103/// On some platforms, the frequency with which a timestamp counter is
104/// incremented may be configured by setting a divisor that divides the base
105/// frequency of the clock. On such a platform, it is possible to select the
106/// tick duration when constructing a new `Clock`. We could then provide a
107/// function that returns a clock with a requested tick duration:
108///
109///```rust
110/// use maitake::time::{Clock, Duration};
111/// # mod arch {
112/// # pub fn read_timestamp_counter() -> u64 { 0 }
113/// # pub fn set_clock_divisor(divisor: u32) {}
114/// # pub const CLOCK_BASE_DURATION_NS: u32 = 100;
115/// # }
116///
117/// fn new_clock(tick_duration: Duration) -> Clock {
118/// // Determine the divisor necessary to achieve the requested tick
119/// // duration, based on the hardware clock's base frequency.
120/// let divisor = {
121/// let duration_ns = tick_duration.as_nanos();
122/// assert!(
123/// duration_ns as u32 >= arch::CLOCK_BASE_DURATION_NS,
124/// "tick duration too short"
125/// );
126/// let div_u128 = duration_ns / arch::CLOCK_BASE_DURATION_NS as u128;
127/// u32::try_from(div_u128).expect("tick duration too long")
128/// };
129///
130/// // Set the divisor to the hardware clock. On real hardware, this
131/// // might be a write to a register or memory-mapped IO location
132/// // that controls the clock's divisor.
133/// arch::set_clock_divisor(divisor as u32);
134///
135/// // Define a `Clock` implementation for the timestamp counter.
136/// Clock::new(tick_duration, arch::read_timestamp_counter)
137/// .named("timestamp-counter")
138/// }
139///```
140///
141/// In addition to timestamp-counter-based hardware clocks, a `Clock` definition
142/// can be provided for an interrupt-based hardware clock. In this case, we
143/// would provide an interrupt handler for the hardware timer interrupt that
144/// increments an [`AtomicU64`](core::sync::atomic::AtomicU64) counter, and a
145/// `now()` function that reads the counter. Essentially, we are reimplementing
146/// a hardware timestamp counter in software, using the hardware timer interrupt
147/// to increment the counter. For example:
148///
149/// ```rust
150/// use maitake::time::{Clock, Duration};
151/// use core::sync::atomic::{AtomicU64, Ordering};
152/// # mod arch {
153/// # pub fn start_periodic_timer() -> u64 { 0 }
154/// # pub fn set_timer_period_ns(_: u64) {}
155/// # pub fn set_interrupt_handler(_: Interrupt, _: fn()) {}
156/// # pub enum Interrupt { Timer }
157/// # }
158///
159/// // A counter that is incremented by the hardware timer interrupt.
160/// static CLOCK_TICKS: AtomicU64 = AtomicU64::new(0);
161///
162/// // The hardware timer interrupt handler.
163/// fn timer_interrupt_handler() {
164/// // Increment the counter.
165/// CLOCK_TICKS.fetch_add(1, Ordering::Relaxed);
166/// }
167///
168/// // Returns the current timestamp by reading the counter.
169/// fn now() -> u64 {
170/// CLOCK_TICKS.load(Ordering::Relaxed)
171/// }
172///
173/// fn new_clock(tick_duration: Duration) -> Clock {
174/// // Set the hardware timer to generate periodic interrupts.
175/// arch::set_timer_period_ns(tick_duration.as_nanos() as u64);
176///
177/// // Set the interrupt handler for the hardware timer interrupt,
178/// // and start the timer.
179/// arch::set_interrupt_handler(arch::Interrupt::Timer, timer_interrupt_handler);
180/// arch::start_periodic_timer();
181///
182/// // Define a `Clock` implementation for the interrupt-based timer.
183/// Clock::new(tick_duration, now)
184/// .named("periodic-timer")
185/// }
186/// ```
187/// [`std::time::Instant`]: https://doc.rust-lang.org/std/time/struct.Instant.html
188/// [monotonic]: https://en.wikipedia.org/wiki/Monotonic_function
189#[derive(Clone, Debug)]
190pub struct Clock {
191 now: fn() -> Ticks,
192 tick_duration: Duration,
193 name: &'static str,
194}
195
196/// A measurement of a monotonically nondecreasing [`Clock`].
197/// Opaque and useful only with [`Duration`].
198///
199/// Provided that the [`Clock`] implementation is correct, `Instant`s are always
200/// guaranteed to be no less than any previously measured instant when created,
201/// and are often useful for tasks such as measuring benchmarks or timing how
202/// long an operation takes.
203///
204/// Note, however, that instants are **not** guaranteed to be **steady**. In other
205/// words, each tick of the underlying clock might not be the same length (e.g.
206/// some seconds may be longer than others). An instant may jump forwards or
207/// experience time dilation (slow down or speed up), but it will never go
208/// backwards.
209/// As part of this non-guarantee it is also not specified whether system suspends count as
210/// elapsed time or not. The behavior varies across platforms and rust versions.
211#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
212pub struct Instant(Duration);
213
214/// [`Clock`] ticks are always counted by a 64-bit unsigned integer.
215pub type Ticks = u64;
216
217impl Clock {
218 /// Returns a new [`Clock`] with the provided tick [`Duration`] and `now()`
219 /// function.
220 ///
221 /// See the [type-level documentation for `Clock`](Self#implementing-now)
222 /// for details on implementing the `now()` function.
223 #[must_use]
224 pub const fn new(tick_duration: Duration, now: fn() -> Ticks) -> Self {
225 Self {
226 now,
227 tick_duration,
228 name: "<unnamed mystery clock>",
229 }
230 }
231
232 /// Add an arbitrary user-defined name to this `Clock`.
233 ///
234 /// This is generally used to describe the hardware time source used by the
235 /// `now()` function for this `Clock`.
236 #[must_use]
237 pub const fn named(self, name: &'static str) -> Self {
238 Self { name, ..self }
239 }
240
241 /// Returns the current `now` timestamp, in [`Ticks`] of this clock's base
242 /// tick duration.
243 #[must_use]
244 pub(crate) fn now_ticks(&self) -> Ticks {
245 (self.now)()
246 }
247
248 /// Returns the [`Duration`] of one tick of this clock.
249 #[must_use]
250 pub fn tick_duration(&self) -> Duration {
251 self.tick_duration
252 }
253
254 /// Returns an [`Instant`] representing the current timestamp according to
255 /// this [`Clock`].
256 #[must_use]
257 pub(crate) fn now(&self) -> Instant {
258 let now = self.now_ticks();
259 let tick_duration = self.tick_duration();
260 Instant(ticks_to_dur(tick_duration, now))
261 }
262
263 /// Returns the maximum duration of this clock.
264 #[must_use]
265 pub fn max_duration(&self) -> Duration {
266 max_duration(self.tick_duration())
267 }
268
269 /// Returns this `Clock`'s name, if it was given one using the [`Clock::named`]
270 /// method.
271 #[must_use]
272 pub fn name(&self) -> &'static str {
273 self.name
274 }
275}
276
277#[track_caller]
278#[inline]
279#[must_use]
280pub(in crate::time) fn ticks_to_dur(tick_duration: Duration, ticks: Ticks) -> Duration {
281 const NANOS_PER_SEC: u32 = 1_000_000_000;
282 // Multiply nanoseconds as u64, because it cannot overflow that way.
283 let total_nanos = tick_duration.subsec_nanos() as u64 * ticks;
284 let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
285 let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
286 let Some(secs) = tick_duration.as_secs().checked_mul(ticks) else {
287 panic!(
288 "ticks_to_dur({tick_duration:?}, {ticks}): multiplying tick \
289 duration seconds by ticks would overflow"
290 );
291 };
292 let Some(secs) = secs.checked_add(extra_secs) else {
293 panic!("ticks_to_dur({tick_duration:?}, {ticks}): extra seconds from nanos ({extra_secs}s) would overflow total seconds")
294 };
295 debug_assert!(nanos < NANOS_PER_SEC);
296 Duration::new(secs, nanos)
297}
298
299#[track_caller]
300#[inline]
301pub(in crate::time) fn dur_to_ticks(
302 tick_duration: Duration,
303 dur: Duration,
304) -> Result<Ticks, TimerError> {
305 (dur.as_nanos() / tick_duration.as_nanos())
306 .try_into()
307 .map_err(|_| TimerError::DurationTooLong {
308 requested: dur,
309 max: max_duration(tick_duration),
310 })
311}
312
313#[track_caller]
314#[inline]
315#[must_use]
316pub(in crate::time) fn max_duration(tick_duration: Duration) -> Duration {
317 tick_duration.saturating_mul(u32::MAX)
318}
319
320impl Instant {
321 /// Returns an instant corresponding to "now".
322 ///
323 /// This function uses the [global default timer][global]. See [the
324 /// module-level documentation][global] for details on using the global
325 /// default timer.
326 ///
327 /// # Panics
328 ///
329 /// This function panics if the [global default timer][global] has not been
330 /// set.
331 ///
332 /// For a version of this function that returns a [`Result`] rather than
333 /// panicking, use [`Instant::try_now`] instead.
334 ///
335 /// [global]: crate::time#global-timers
336 #[must_use]
337 pub fn now() -> Instant {
338 Self::try_now().expect("no global timer set")
339 }
340
341 /// Returns an instant corresponding to "now", without panicking.
342 ///
343 /// This function uses the [global default timer][global]. See [the
344 /// module-level documentation][global] for details on using the global
345 /// default timer.
346 ///
347 /// # Returns
348 ///
349 /// - [`Ok`]`(`[`Instant`]`)` if the [global default timer] is available.
350 /// - [`Err`]`(`[`TimerError`]`)` if no [global default timer][global] has
351 /// been set.
352 ///
353 /// [global]: crate::time#global-timers
354 pub fn try_now() -> Result<Self, TimerError> {
355 Ok(timer::global::default()?.now())
356 }
357
358 /// Returns the amount of time elapsed from another instant to this one,
359 /// or zero duration if that instant is later than this one.
360 #[must_use]
361 pub fn duration_since(&self, earlier: Instant) -> Duration {
362 self.checked_duration_since(earlier).unwrap_or_default()
363 }
364
365 /// Returns the amount of time elapsed from another instant to this one,
366 /// or [`None`]` if that instant is later than this one.
367 #[must_use]
368 pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
369 self.0.checked_sub(earlier.0)
370 }
371
372 /// Returns the amount of time elapsed since this instant.
373 #[must_use]
374 pub fn elapsed(&self) -> Duration {
375 self.0
376 }
377
378 /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
379 /// `Instant` (which means it's inside the bounds of the underlying data structure), [`None`]
380 /// otherwise.
381 #[must_use]
382 pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
383 self.0.checked_add(duration).map(Instant)
384 }
385
386 /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
387 /// `Instant` (which means it's inside the bounds of the underlying data structure), [`None`]
388 /// otherwise.
389 #[must_use]
390 pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
391 self.0.checked_sub(duration).map(Instant)
392 }
393}
394
395impl Add<Duration> for Instant {
396 type Output = Instant;
397
398 /// # Panics
399 ///
400 /// This function may panic if the resulting point in time cannot be represented by the
401 /// underlying data structure. See [`Instant::checked_add`] for a version without panic.
402 fn add(self, other: Duration) -> Instant {
403 self.checked_add(other)
404 .expect("overflow when adding duration to instant")
405 }
406}
407
408impl AddAssign<Duration> for Instant {
409 fn add_assign(&mut self, other: Duration) {
410 *self = *self + other;
411 }
412}
413
414impl Sub<Duration> for Instant {
415 type Output = Instant;
416
417 fn sub(self, other: Duration) -> Instant {
418 self.checked_sub(other)
419 .expect("overflow when subtracting duration from instant")
420 }
421}
422
423impl SubAssign<Duration> for Instant {
424 fn sub_assign(&mut self, other: Duration) {
425 *self = *self - other;
426 }
427}
428
429impl Sub<Instant> for Instant {
430 type Output = Duration;
431
432 /// Returns the amount of time elapsed from another instant to this one,
433 /// or zero duration if that instant is later than this one.
434 fn sub(self, other: Instant) -> Duration {
435 self.duration_since(other)
436 }
437}
438
439impl fmt::Display for Instant {
440 #[inline]
441 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442 fmt::Debug::fmt(&self.0, f)
443 }
444}