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