Skip to main content

ic_host_process/observation/clock/
mod.rs

1//! Native clocks and thread identity. No sampling, retention or application policy.
2
3#[cfg(unix)]
4use rustix::time::{ClockId, DynamicClockId, clock_gettime_dynamic};
5
6#[cfg(unix)]
7#[expect(
8    clippy::cast_sign_loss,
9    reason = "successful native clocks have nonnegative seconds and nanoseconds"
10)]
11fn clock_ns(clock: ClockId) -> Option<u64> {
12    let value = clock_gettime_dynamic(DynamicClockId::Known(clock)).ok()?;
13    Some(
14        (value.tv_sec as u64)
15            .saturating_mul(1_000_000_000)
16            .saturating_add(value.tv_nsec as u64),
17    )
18}
19
20/// Host monotonic nanoseconds, falling back to a process-local Instant epoch.
21#[must_use]
22pub fn monotonic_ns() -> u64 {
23    static START: std::sync::OnceLock<std::time::Instant> = std::sync::OnceLock::new();
24    #[cfg(unix)]
25    if let Some(value) = clock_ns(ClockId::Monotonic) {
26        return value;
27    }
28    u64::try_from(
29        START
30            .get_or_init(std::time::Instant::now)
31            .elapsed()
32            .as_nanos(),
33    )
34    .unwrap_or(u64::MAX)
35}
36
37/// CPU nanoseconds of the current thread; zero when the native clock is unavailable.
38#[must_use]
39pub fn thread_cpu_ns() -> u64 {
40    #[cfg(unix)]
41    if let Some(value) = clock_ns(ClockId::ThreadCPUTime) {
42        return value;
43    }
44    0
45}
46
47/// Current native thread identity; zero on unsupported hosts or query failure.
48#[must_use]
49pub fn tid() -> u64 {
50    #[cfg(target_os = "linux")]
51    {
52        u64::try_from(rustix::thread::gettid().as_raw_pid()).unwrap_or_default()
53    }
54    #[cfg(target_os = "macos")]
55    {
56        let mut id = 0;
57        // SAFETY: a null thread selects the current thread; id is writable.
58        #[expect(
59            unsafe_code,
60            reason = "Darwin thread ID has no matching Rustix interface"
61        )]
62        if unsafe { libc::pthread_threadid_np(0, &raw mut id) } == 0 {
63            id
64        } else {
65            0
66        }
67    }
68    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
69    {
70        0
71    }
72}