indexbus_platform_ops/
time.rs

1//! Time-related operational helpers.
2//!
3//! **Contracts**
4//! - This is best-effort and intended for diagnostics/metrics.
5//! - On Linux this prefers `CLOCK_MONOTONIC_RAW` when available.
6//! - On non-Linux platforms the fallback is not strictly monotonic.
7
8use crate::errors::{Error, Result};
9
10/// Best-effort monotonic-ish timestamp in nanoseconds.
11///
12/// On Linux, uses `clock_gettime(CLOCK_MONOTONIC_RAW)` when available, falling back to
13/// `CLOCK_MONOTONIC`.
14///
15/// On non-Linux platforms, falls back to `SystemTime` (not strictly monotonic) to keep
16/// the code portable.
17pub fn monotonic_now_ns() -> u64 {
18    #[cfg(target_os = "linux")]
19    unsafe {
20        let mut ts: libc::timespec = std::mem::zeroed();
21
22        #[allow(non_upper_case_globals)]
23        const CLOCK_MONOTONIC_RAW: libc::clockid_t = 4;
24
25        let mut rc = libc::clock_gettime(CLOCK_MONOTONIC_RAW, &mut ts as *mut _);
26        if rc != 0 {
27            rc = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts as *mut _);
28        }
29
30        if rc != 0 {
31            return 0;
32        }
33
34        (ts.tv_sec as u128)
35            .saturating_mul(1_000_000_000)
36            .saturating_add(ts.tv_nsec as u128)
37            .min(u128::from(u64::MAX)) as u64
38    }
39
40    #[cfg(not(target_os = "linux"))]
41    {
42        use std::time::SystemTime;
43        SystemTime::now()
44            .duration_since(SystemTime::UNIX_EPOCH)
45            .ok()
46            .map(|d| d.as_nanos().min(u128::from(u64::MAX)) as u64)
47            .unwrap_or(0)
48    }
49}
50
51/// A stricter monotonic timestamp helper that errors instead of returning 0.
52pub fn try_monotonic_now_ns() -> Result<u64> {
53    let v = monotonic_now_ns();
54    if v == 0 {
55        Err(Error::msg("failed to read monotonic clock"))
56    } else {
57        Ok(v)
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn monotonic_now_is_nonzero() {
67        let v = try_monotonic_now_ns().unwrap();
68        assert!(v > 0);
69    }
70}