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