clock_steering/
lib.rs

1//! Logic for steering OS clocks, aimed at NTP and PTP.
2//!
3//! This code is used in our implementations of NTP [ntpd-rs](https://github.com/pendulum-project/ntpd-rs) and PTP [statime](https://github.com/pendulum-project/statime).
4use core::time::Duration;
5
6#[cfg(unix)]
7pub mod unix;
8
9/// A moment in time.
10///
11/// The format makes it easy to convert into libc data structures, and supports subnanoseconds that
12/// certain hardware can provide for additional precision. The value is an offset from the [unix epoch](https://en.wikipedia.org/wiki/Unix_time).
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
14pub struct Timestamp {
15    pub seconds: libc::time_t,
16    /// Nanos must be between 0 and 999999999 inclusive
17    pub nanos: u32,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
21pub struct TimeOffset {
22    pub seconds: libc::time_t,
23    /// Nanos must be between 0 and 999999999 inclusive
24    pub nanos: u32,
25}
26
27/// Indicate whether a leap second must be applied
28#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
29pub enum LeapIndicator {
30    /// No leap second warning
31    #[default]
32    NoWarning,
33    /// Last minute of the day has 61 seconds
34    Leap61,
35    /// Last minute of the day has 59 seconds
36    Leap59,
37    /// Unknown leap second status (the clock is unsynchronized)
38    Unknown,
39}
40
41/// Trait for reading information from and modifying an OS clock
42pub trait Clock {
43    type Error: std::error::Error;
44
45    // feature(error_in_core) https://github.com/rust-lang/rust/issues/103765
46    // type Error: core::error::Error;
47
48    /// Get the current time.
49    fn now(&self) -> Result<Timestamp, Self::Error>;
50
51    /// Get the clock's resolution.
52    ///
53    /// The output [`Timestamp`] will be all zeros when the resolution is
54    /// unavailable.
55    fn resolution(&self) -> Result<Timestamp, Self::Error>;
56
57    /// Change the frequency of the clock.
58    /// Returns the time at which the change was applied.
59    ///
60    /// The unit of the input is milliseconds (of drift) per second,
61    /// compared to the "natural" frequency of the clock.
62    fn set_frequency(&self, frequency: f64) -> Result<Timestamp, Self::Error>;
63
64    /// Get the frequency of the clock
65    /// The unit of the output is milliseconds (of drift) per second,
66    /// compared to the "natural" frequency of the clock.
67    fn get_frequency(&self) -> Result<f64, Self::Error>;
68
69    /// Change the current time of the clock by an offset.
70    /// Returns the time at which the change was applied.
71    fn step_clock(&self, offset: TimeOffset) -> Result<Timestamp, Self::Error>;
72
73    /// Change the indicators for upcoming leap seconds.
74    fn set_leap_seconds(&self, leap_status: LeapIndicator) -> Result<(), Self::Error>;
75
76    /// Disable all standard NTP kernel clock discipline. It is all your responsibility now.
77    ///
78    /// The disabled settings are:
79    ///
80    /// - [`libc::STA_PLL`]: kernel phase-locked loop
81    /// - [`libc::STA_FLL`]: kernel frequency-locked loop
82    /// - [`libc::STA_PPSTIME`]: pulse-per-second time
83    /// - [`libc::STA_PPSFREQ`]: pulse-per-second frequency discipline
84    fn disable_kernel_ntp_algorithm(&self) -> Result<(), Self::Error>;
85
86    /// Set the offset between TAI and UTC.
87    fn set_tai(&self, tai_offset: i32) -> Result<(), Self::Error>;
88
89    /// Get the offset between TAI and UTC.
90    fn get_tai(&self) -> Result<i32, Self::Error>;
91
92    /// Provide the system with the current best estimates for the statistical
93    /// error of the clock, and the maximum deviation due to frequency error and
94    /// distance to the root clock.
95    fn error_estimate_update(
96        &self,
97        estimated_error: Duration,
98        maximum_error: Duration,
99    ) -> Result<(), Self::Error>;
100}