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 =
89        ClockId(libc::CLOCK_BOOTTIME_ALARM);
90    pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
91    #[cfg(any(
92        target_os = "android",
93        target_os = "emscripten",
94        target_os = "fuchsia",
95        target_os = "linux"
96    ))]
97    #[cfg_attr(docsrs, doc(cfg(all())))]
98    pub const CLOCK_MONOTONIC_COARSE: ClockId =
99        ClockId(libc::CLOCK_MONOTONIC_COARSE);
100    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
101    #[cfg_attr(docsrs, doc(cfg(all())))]
102    pub const CLOCK_MONOTONIC_FAST: ClockId =
103        ClockId(libc::CLOCK_MONOTONIC_FAST);
104    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
105    #[cfg_attr(docsrs, doc(cfg(all())))]
106    pub const CLOCK_MONOTONIC_PRECISE: ClockId =
107        ClockId(libc::CLOCK_MONOTONIC_PRECISE);
108    #[cfg(any(
109        target_os = "android",
110        target_os = "emscripten",
111        target_os = "fuchsia",
112        target_os = "linux"
113    ))]
114    #[cfg_attr(docsrs, doc(cfg(all())))]
115    pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
116    #[cfg(any(
117        target_os = "android",
118        target_os = "emscripten",
119        target_os = "fuchsia",
120        target_os = "macos",
121        target_os = "ios",
122        target_os = "freebsd",
123        target_os = "dragonfly",
124        target_os = "redox",
125        target_os = "linux"
126    ))]
127    #[cfg_attr(docsrs, doc(cfg(all())))]
128    pub const CLOCK_PROCESS_CPUTIME_ID: ClockId =
129        ClockId(libc::CLOCK_PROCESS_CPUTIME_ID);
130    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
131    #[cfg_attr(docsrs, doc(cfg(all())))]
132    pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
133    pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
134    #[cfg(any(
135        target_os = "android",
136        target_os = "emscripten",
137        target_os = "fuchsia",
138        target_os = "linux"
139    ))]
140    #[cfg_attr(docsrs, doc(cfg(all())))]
141    pub const CLOCK_REALTIME_ALARM: ClockId =
142        ClockId(libc::CLOCK_REALTIME_ALARM);
143    #[cfg(any(
144        target_os = "android",
145        target_os = "emscripten",
146        target_os = "fuchsia",
147        target_os = "linux"
148    ))]
149    #[cfg_attr(docsrs, doc(cfg(all())))]
150    pub const CLOCK_REALTIME_COARSE: ClockId =
151        ClockId(libc::CLOCK_REALTIME_COARSE);
152    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
153    #[cfg_attr(docsrs, doc(cfg(all())))]
154    pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST);
155    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
156    #[cfg_attr(docsrs, doc(cfg(all())))]
157    pub const CLOCK_REALTIME_PRECISE: ClockId =
158        ClockId(libc::CLOCK_REALTIME_PRECISE);
159    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
160    #[cfg_attr(docsrs, doc(cfg(all())))]
161    pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
162    #[cfg(any(
163        target_os = "emscripten",
164        target_os = "fuchsia",
165        all(target_os = "linux", target_env = "musl")
166    ))]
167    #[cfg_attr(docsrs, doc(cfg(all())))]
168    pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
169    #[cfg(any(
170        target_os = "android",
171        target_os = "emscripten",
172        target_os = "fuchsia",
173        target_os = "linux"
174    ))]
175    #[cfg_attr(docsrs, doc(cfg(all())))]
176    pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
177    #[cfg(any(
178        target_os = "android",
179        target_os = "emscripten",
180        target_os = "fuchsia",
181        target_os = "ios",
182        target_os = "macos",
183        target_os = "freebsd",
184        target_os = "dragonfly",
185        target_os = "linux"
186    ))]
187    #[cfg_attr(docsrs, doc(cfg(all())))]
188    pub const CLOCK_THREAD_CPUTIME_ID: ClockId =
189        ClockId(libc::CLOCK_THREAD_CPUTIME_ID);
190    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
191    #[cfg_attr(docsrs, doc(cfg(all())))]
192    pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
193    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
194    #[cfg_attr(docsrs, doc(cfg(all())))]
195    pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST);
196    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
197    #[cfg_attr(docsrs, doc(cfg(all())))]
198    pub const CLOCK_UPTIME_PRECISE: ClockId =
199        ClockId(libc::CLOCK_UPTIME_PRECISE);
200    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
201    #[cfg_attr(docsrs, doc(cfg(all())))]
202    pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL);
203}
204
205impl From<ClockId> for clockid_t {
206    fn from(clock_id: ClockId) -> Self {
207        clock_id.as_raw()
208    }
209}
210
211impl From<clockid_t> for ClockId {
212    fn from(clk_id: clockid_t) -> Self {
213        ClockId::from_raw(clk_id)
214    }
215}
216
217impl std::fmt::Display for ClockId {
218    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
219        std::fmt::Display::fmt(&self.0, f)
220    }
221}
222
223/// Get the resolution of the specified clock, (see
224/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
225#[cfg(not(target_os = "redox"))]
226#[cfg_attr(docsrs, doc(cfg(all())))]
227pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
228    let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
229    let ret =
230        unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) };
231    Errno::result(ret)?;
232    let res = unsafe { c_time.assume_init() };
233    Ok(TimeSpec::from(res))
234}
235
236/// Get the time of the specified clock, (see
237/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)).
238pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
239    let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
240    let ret =
241        unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) };
242    Errno::result(ret)?;
243    let res = unsafe { c_time.assume_init() };
244    Ok(TimeSpec::from(res))
245}
246
247/// Set the time of the specified clock, (see
248/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)).
249#[cfg(not(any(
250    target_os = "macos",
251    target_os = "ios",
252    target_os = "redox",
253    target_os = "hermit",
254)))]
255#[cfg_attr(docsrs, doc(cfg(all())))]
256pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
257    let ret =
258        unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
259    Errno::result(ret).map(drop)
260}
261
262/// Get the clock id of the specified process id, (see
263/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)).
264#[cfg(any(
265    target_os = "freebsd",
266    target_os = "dragonfly",
267    target_os = "linux",
268    target_os = "android",
269    target_os = "emscripten",
270))]
271#[cfg(feature = "process")]
272#[cfg_attr(docsrs, doc(cfg(feature = "process")))]
273pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
274    let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit();
275    let ret =
276        unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) };
277    if ret == 0 {
278        let res = unsafe { clk_id.assume_init() };
279        Ok(ClockId::from(res))
280    } else {
281        Err(Errno::from_i32(ret))
282    }
283}