nix/
time.rs

1use crate::sys::time::TimeSpec;
2#[cfg(any(
3    target_os = "freebsd",
4    target_os = "dragonfly",
5    target_os = "linux",
6    target_os = "android",
7    target_os = "emscripten",
8))]
9#[cfg(feature = "process")]
10use crate::unistd::Pid;
11use crate::{Errno, Result};
12use libc::{self, clockid_t};
13use std::mem::MaybeUninit;
14
15/// Clock identifier
16///
17/// Newtype pattern around `clockid_t` (which is just alias). It prevents bugs caused by
18/// accidentally passing wrong value.
19#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
20pub struct ClockId(clockid_t);
21
22impl ClockId {
23    /// Creates `ClockId` from raw `clockid_t`
24    pub const fn from_raw(clk_id: clockid_t) -> Self {
25        ClockId(clk_id)
26    }
27
28    feature! {
29    #![feature = "process"]
30    /// Returns `ClockId` of a `pid` CPU-time clock
31    #[cfg(any(
32        target_os = "freebsd",
33        target_os = "dragonfly",
34        target_os = "linux",
35        target_os = "android",
36        target_os = "emscripten",
37    ))]
38    #[cfg_attr(docsrs, doc(cfg(all())))]
39    pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> {
40        clock_getcpuclockid(pid)
41    }
42    }
43
44    /// Returns resolution of the clock id
45    #[cfg(not(target_os = "redox"))]
46    #[cfg_attr(docsrs, doc(cfg(all())))]
47    pub fn res(self) -> Result<TimeSpec> {
48        clock_getres(self)
49    }
50
51    /// Returns the current time on the clock id
52    pub fn now(self) -> Result<TimeSpec> {
53        clock_gettime(self)
54    }
55
56    /// Sets time to `timespec` on the clock id
57    #[cfg(not(any(
58        target_os = "macos",
59        target_os = "ios",
60        target_os = "redox",
61        target_os = "hermit",
62    )))]
63    #[cfg_attr(docsrs, doc(cfg(all())))]
64    pub fn set_time(self, timespec: TimeSpec) -> Result<()> {
65        clock_settime(self, timespec)
66    }
67
68    /// Gets the raw `clockid_t` wrapped by `self`
69    pub const fn as_raw(self) -> clockid_t {
70        self.0
71    }
72
73    #[cfg(any(
74        target_os = "android",
75        target_os = "emscripten",
76        target_os = "fuchsia",
77        target_os = "linux"
78    ))]
79    #[cfg_attr(docsrs, doc(cfg(all())))]
80    pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME);
81    #[cfg(any(
82        target_os = "android",
83        target_os = "emscripten",
84        target_os = "fuchsia",
85        target_os = "linux"
86    ))]
87    #[cfg_attr(docsrs, doc(cfg(all())))]
88    pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM);
89    pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
90    #[cfg(any(
91        target_os = "android",
92        target_os = "emscripten",
93        target_os = "fuchsia",
94        target_os = "linux"
95    ))]
96    #[cfg_attr(docsrs, doc(cfg(all())))]
97    pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE);
98    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
99    #[cfg_attr(docsrs, doc(cfg(all())))]
100    pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST);
101    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
102    #[cfg_attr(docsrs, doc(cfg(all())))]
103    pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE);
104    #[cfg(any(
105        target_os = "android",
106        target_os = "emscripten",
107        target_os = "fuchsia",
108        target_os = "linux"
109    ))]
110    #[cfg_attr(docsrs, doc(cfg(all())))]
111    pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
112    #[cfg(any(
113        target_os = "android",
114        target_os = "emscripten",
115        target_os = "fuchsia",
116        target_os = "macos",
117        target_os = "ios",
118        target_os = "freebsd",
119        target_os = "dragonfly",
120        target_os = "redox",
121        target_os = "linux"
122    ))]
123    #[cfg_attr(docsrs, doc(cfg(all())))]
124    pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID);
125    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
126    #[cfg_attr(docsrs, doc(cfg(all())))]
127    pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
128    pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
129    #[cfg(any(
130        target_os = "android",
131        target_os = "emscripten",
132        target_os = "fuchsia",
133        target_os = "linux"
134    ))]
135    #[cfg_attr(docsrs, doc(cfg(all())))]
136    pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM);
137    #[cfg(any(
138        target_os = "android",
139        target_os = "emscripten",
140        target_os = "fuchsia",
141        target_os = "linux"
142    ))]
143    #[cfg_attr(docsrs, doc(cfg(all())))]
144    pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE);
145    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
146    #[cfg_attr(docsrs, doc(cfg(all())))]
147    pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST);
148    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
149    #[cfg_attr(docsrs, doc(cfg(all())))]
150    pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE);
151    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
152    #[cfg_attr(docsrs, doc(cfg(all())))]
153    pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
154    #[cfg(any(
155        target_os = "emscripten",
156        target_os = "fuchsia",
157        all(target_os = "linux", target_env = "musl")
158    ))]
159    #[cfg_attr(docsrs, doc(cfg(all())))]
160    pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
161    #[cfg(any(
162        target_os = "android",
163        target_os = "emscripten",
164        target_os = "fuchsia",
165        target_os = "linux"
166    ))]
167    #[cfg_attr(docsrs, doc(cfg(all())))]
168    pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
169    #[cfg(any(
170        target_os = "android",
171        target_os = "emscripten",
172        target_os = "fuchsia",
173        target_os = "ios",
174        target_os = "macos",
175        target_os = "freebsd",
176        target_os = "dragonfly",
177        target_os = "linux"
178    ))]
179    #[cfg_attr(docsrs, doc(cfg(all())))]
180    pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID);
181    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
182    #[cfg_attr(docsrs, doc(cfg(all())))]
183    pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
184    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
185    #[cfg_attr(docsrs, doc(cfg(all())))]
186    pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST);
187    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
188    #[cfg_attr(docsrs, doc(cfg(all())))]
189    pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE);
190    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
191    #[cfg_attr(docsrs, doc(cfg(all())))]
192    pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL);
193}
194
195impl From<ClockId> for clockid_t {
196    fn from(clock_id: ClockId) -> Self {
197        clock_id.as_raw()
198    }
199}
200
201impl From<clockid_t> for ClockId {
202    fn from(clk_id: clockid_t) -> Self {
203        ClockId::from_raw(clk_id)
204    }
205}
206
207impl std::fmt::Display for ClockId {
208    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
209        std::fmt::Display::fmt(&self.0, f)
210    }
211}
212
213/// Get the resolution of the specified clock, (see
214/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
215#[cfg(not(target_os = "redox"))]
216#[cfg_attr(docsrs, doc(cfg(all())))]
217pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
218    let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
219    let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) };
220    Errno::result(ret)?;
221    let res = unsafe { c_time.assume_init() };
222    Ok(TimeSpec::from(res))
223}
224
225/// Get the time of the specified clock, (see
226/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)).
227pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
228    let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
229    let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) };
230    Errno::result(ret)?;
231    let res = unsafe { c_time.assume_init() };
232    Ok(TimeSpec::from(res))
233}
234
235/// Set the time of the specified clock, (see
236/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)).
237#[cfg(not(any(
238    target_os = "macos",
239    target_os = "ios",
240    target_os = "redox",
241    target_os = "hermit",
242)))]
243#[cfg_attr(docsrs, doc(cfg(all())))]
244pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
245    let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
246    Errno::result(ret).map(drop)
247}
248
249/// Get the clock id of the specified process id, (see
250/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)).
251#[cfg(any(
252    target_os = "freebsd",
253    target_os = "dragonfly",
254    target_os = "linux",
255    target_os = "android",
256    target_os = "emscripten",
257))]
258#[cfg(feature = "process")]
259#[cfg_attr(docsrs, doc(cfg(feature = "process")))]
260pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
261    let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit();
262    let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) };
263    if ret == 0 {
264        let res = unsafe { clk_id.assume_init() };
265        Ok(ClockId::from(res))
266    } else {
267        Err(Errno::from_i32(ret))
268    }
269}