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