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
40     #[cfg(not(target_os = "redox"))]
res(self) -> Result<TimeSpec>41     pub fn res(self) -> Result<TimeSpec> {
42         clock_getres(self)
43     }
44 
45     /// Returns the current time on the clock id
now(self) -> Result<TimeSpec>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     )))]
set_time(self, timespec: TimeSpec) -> Result<()>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`
as_raw(self) -> clockid_t64     pub 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 
188 impl Into<clockid_t> for ClockId {
into(self) -> clockid_t189     fn into(self) -> clockid_t {
190         self.as_raw()
191     }
192 }
193 
194 impl From<clockid_t> for ClockId {
from(clk_id: clockid_t) -> Self195     fn from(clk_id: clockid_t) -> Self {
196         ClockId::from_raw(clk_id)
197     }
198 }
199 
200 impl std::fmt::Display for ClockId {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result201     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"))]
clock_getres(clock_id: ClockId) -> Result<TimeSpec>209 pub 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)).
clock_gettime(clock_id: ClockId) -> Result<TimeSpec>219 pub 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 )))]
clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()>237 pub 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 ))]
clock_getcpuclockid(pid: Pid) -> Result<ClockId>251 pub 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(Error::Sys(Errno::from_i32(ret)))
259     }
260 }
261