irox_safe_linux/
time.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2024 IROX Contributors
3//
4
5//!
6//! Syscalls from `time.c`
7
8use crate::errno::Errno;
9use crate::{syscall_1, syscall_2};
10pub use irox_enums::{EnumIterItem, EnumName};
11
12pub const SYSCALL_TIMES: u64 = 100;
13pub const SYSCALL_CLOCK_GETTIME: u64 = 228;
14pub const SYSCALL_CLOCK_GETRES: u64 = 229;
15
16///
17/// Equivalent of POSIX's clock_t type.
18pub type ClockT = u64;
19
20///
21/// Equivalent of POSIX's clock_t type.
22#[derive(Debug, Copy, Clone, Eq, PartialEq, EnumName, EnumIterItem)]
23#[repr(u32)]
24pub enum ClockType {
25    ///
26    /// The identifier for the system-wide clock measuring real time.  The "Wall-clock" time usually
27    /// set via NTP/PTP/RTC/etc.
28    Realtime = 0,
29
30    ///
31    /// The identifier for the system-wide monotonic clock, which is defined as a clock measuring
32    /// real time, whose value cannot be set via `clock_settime()` and which cannot have negative
33    /// clock jumps. This clock is set to some random value and increases at a constant rate in a
34    /// positive direction and can roll-over around the maximum value.  Used to measure/instrument
35    /// precise durational time.
36    Monotonic = 1,
37
38    ///
39    /// The CPU-Time clock associated with the process making the call
40    ProcessCPUTime = 2,
41
42    /// The CPU-Time clock associated with the thread making the call
43    ThreadCPUTime = 3,
44
45    MonotonicRaw = 4,
46
47    ///
48    /// The realtime clock, but at a much coarser resolution.  My system has this at 10ms
49    RealtimeCoarse = 5,
50
51    ///
52    /// The monotonic clock, but at a much coarser resolution.  My system has this at 10ms.
53    MonotonicCoarse = 6,
54    BootTime = 7,
55    RealTimeAlarm = 8,
56    BootTimeAlarm = 9,
57    TAI = 11,
58}
59
60///
61/// Kernel's version of `Instant`, referenced to a specific clock.
62#[repr(C)]
63#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
64pub struct Timespec {
65    /// Seconds value
66    pub tv_sec: u64,
67    /// Nanoseconds value
68    pub tv_nsec: u64,
69}
70
71///
72/// Associates a returned [`Timespec`] with the [`ClockType`] it was requested with.
73#[derive(Debug, Copy, Clone, Eq, PartialEq)]
74pub struct ClockTimespec {
75    pub timespec: Timespec,
76    pub clock: ClockType,
77}
78
79///
80/// A Block of times provided by the kernel.
81#[repr(C)]
82#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
83pub struct Times {
84    /// User time
85    pub tms_utime: ClockT,
86    /// System time
87    pub tms_stime: ClockT,
88    /// User time of children
89    pub tms_cutime: ClockT,
90    /// System time of children
91    pub tms_cstime: ClockT,
92}
93
94///
95/// Calls into the Kernel and requests the current value of the specified clock.
96pub fn clock_gettime(clock_type: ClockType) -> Result<ClockTimespec, Errno> {
97    let mut ts: Timespec = Default::default();
98
99    let ret = unsafe {
100        let ptr = core::ptr::from_mut(&mut ts);
101        syscall_2!(SYSCALL_CLOCK_GETTIME, clock_type as u64, ptr)
102    };
103
104    if ret != 0 {
105        return Err(ret.into());
106    }
107    Ok(ClockTimespec {
108        clock: clock_type,
109        timespec: ts,
110    })
111}
112
113#[derive(Debug, Copy, Clone, Eq, PartialEq)]
114pub struct ClockResolution {
115    pub clock: ClockType,
116    pub resolution_ns: u64,
117}
118
119///
120/// Calls into the Kernel and requests the resolution of the specified clock.
121pub fn clock_getres(clock_type: ClockType) -> Result<ClockResolution, Errno> {
122    let mut ts: Timespec = Default::default();
123
124    let ret = unsafe {
125        let ptr = core::ptr::from_mut(&mut ts);
126        syscall_2!(SYSCALL_CLOCK_GETRES, clock_type as u64, ptr)
127    };
128
129    if ret != 0 {
130        return Err(ret.into());
131    }
132    Ok(ClockResolution {
133        clock: clock_type,
134        resolution_ns: ts.tv_nsec,
135    })
136}
137
138#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
139pub struct TimesTicks {
140    pub times: Times,
141    /// Number of clock ticks since some arbitrary point in the past.
142    pub ticks: u64,
143}
144
145/// Returns the current process times & a 'ticks' value at the time of the call.
146pub fn times() -> Result<TimesTicks, Errno> {
147    let mut ts: Times = Default::default();
148
149    let ret = unsafe {
150        let ptr = core::ptr::from_mut(&mut ts);
151        syscall_1!(SYSCALL_TIMES, ptr)
152    };
153
154    if ret < 0 {
155        return Err(ret.into());
156    }
157    Ok(TimesTicks {
158        times: ts,
159        ticks: ret as u64,
160    })
161}
162
163#[cfg(test)]
164mod tests {
165    use crate::errno::Errno;
166    use crate::time::*;
167
168    #[test]
169    pub fn test_clock_gettime() -> Result<(), Errno> {
170        let out = clock_gettime(ClockType::Realtime)?;
171
172        println!("{out:#?}");
173
174        for clock in ClockType::iter_items() {
175            let out = clock_gettime(clock);
176            println!("{clock:?}: {out:#?}");
177        }
178
179        Ok(())
180    }
181
182    #[test]
183    pub fn test_clock_getres() -> Result<(), Errno> {
184        let out = clock_getres(ClockType::Realtime)?;
185
186        println!("{out:#?}");
187
188        for clock in ClockType::iter_items() {
189            let out = clock_getres(clock);
190            println!("{clock:?}: {out:#?}");
191        }
192
193        Ok(())
194    }
195
196    #[test]
197    pub fn test_times() -> Result<(), Errno> {
198        let out = times()?;
199        println!("{out:#?}");
200        Ok(())
201    }
202}