1use crate::sys::time::TimeSpec;
3#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
4#[cfg(feature = "process")]
5use crate::unistd::Pid;
6use crate::{Errno, Result};
7use libc::{self, clockid_t};
8use std::mem::MaybeUninit;
9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
14pub struct ClockId(clockid_t);
15
16impl ClockId {
17 pub const fn from_raw(clk_id: clockid_t) -> Self {
19 ClockId(clk_id)
20 }
21
22 feature! {
23 #![feature = "process"]
24 #[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
26 pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> {
27 clock_getcpuclockid(pid)
28 }
29 }
30
31 #[cfg(not(target_os = "redox"))]
33 pub fn res(self) -> Result<TimeSpec> {
34 clock_getres(self)
35 }
36
37 pub fn now(self) -> Result<TimeSpec> {
39 clock_gettime(self)
40 }
41
42 #[cfg(not(any(
44 target_os = "ios",
45 target_os = "tvos",
46 target_os = "watchos",
47 target_os = "redox",
48 target_os = "hermit"
49 )))]
50 pub fn set_time(self, timespec: TimeSpec) -> Result<()> {
51 clock_settime(self, timespec)
52 }
53
54 pub const fn as_raw(self) -> clockid_t {
56 self.0
57 }
58
59 #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
60 pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME);
63 #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
66 pub const CLOCK_BOOTTIME_ALARM: ClockId =
67 ClockId(libc::CLOCK_BOOTTIME_ALARM);
68 pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
70 #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
72 pub const CLOCK_MONOTONIC_COARSE: ClockId =
73 ClockId(libc::CLOCK_MONOTONIC_COARSE);
74 #[cfg(freebsdlike)]
75 pub const CLOCK_MONOTONIC_FAST: ClockId =
77 ClockId(libc::CLOCK_MONOTONIC_FAST);
78 #[cfg(freebsdlike)]
79 pub const CLOCK_MONOTONIC_PRECISE: ClockId =
81 ClockId(libc::CLOCK_MONOTONIC_PRECISE);
82 #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
85 pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
86 #[cfg(any(
87 linux_android,
88 apple_targets,
89 freebsdlike,
90 target_os = "emscripten",
91 target_os = "fuchsia",
92 target_os = "redox",
93 ))]
94 pub const CLOCK_PROCESS_CPUTIME_ID: ClockId =
96 ClockId(libc::CLOCK_PROCESS_CPUTIME_ID);
97 #[cfg(freebsdlike)]
98 pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
100 pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
102 #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
104 pub const CLOCK_REALTIME_ALARM: ClockId =
105 ClockId(libc::CLOCK_REALTIME_ALARM);
106 #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
108 pub const CLOCK_REALTIME_COARSE: ClockId =
109 ClockId(libc::CLOCK_REALTIME_COARSE);
110 #[cfg(freebsdlike)]
111 pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST);
113 #[cfg(freebsdlike)]
114 pub const CLOCK_REALTIME_PRECISE: ClockId =
116 ClockId(libc::CLOCK_REALTIME_PRECISE);
117 #[cfg(freebsdlike)]
118 pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
121 #[allow(missing_docs)] #[cfg(any(
123 target_os = "emscripten",
124 target_os = "fuchsia",
125 all(
126 target_os = "linux",
127 any(target_env = "musl", target_env = "ohos")
128 )
129 ))]
130 pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
131 #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
135 pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
136 #[cfg(any(
137 linux_android,
138 apple_targets,
139 freebsdlike,
140 target_os = "emscripten",
141 target_os = "fuchsia",
142 ))]
143 pub const CLOCK_THREAD_CPUTIME_ID: ClockId =
145 ClockId(libc::CLOCK_THREAD_CPUTIME_ID);
146 #[cfg(freebsdlike)]
147 pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
150 #[cfg(freebsdlike)]
151 pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST);
153 #[cfg(freebsdlike)]
154 pub const CLOCK_UPTIME_PRECISE: ClockId =
156 ClockId(libc::CLOCK_UPTIME_PRECISE);
157 #[cfg(freebsdlike)]
158 pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL);
160}
161
162impl From<ClockId> for clockid_t {
163 fn from(clock_id: ClockId) -> Self {
164 clock_id.as_raw()
165 }
166}
167
168impl From<clockid_t> for ClockId {
169 fn from(clk_id: clockid_t) -> Self {
170 ClockId::from_raw(clk_id)
171 }
172}
173
174impl std::fmt::Display for ClockId {
175 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
176 std::fmt::Display::fmt(&self.0, f)
177 }
178}
179
180#[cfg(not(target_os = "redox"))]
183pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
184 let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
185 let ret =
186 unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) };
187 Errno::result(ret)?;
188 let res = unsafe { c_time.assume_init() };
189 Ok(TimeSpec::from(res))
190}
191
192pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
195 let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
196 let ret =
197 unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) };
198 Errno::result(ret)?;
199 let res = unsafe { c_time.assume_init() };
200 Ok(TimeSpec::from(res))
201}
202
203#[cfg(not(any(
206 target_os = "ios",
207 target_os = "tvos",
208 target_os = "watchos",
209 target_os = "redox",
210 target_os = "hermit"
211)))]
212pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
213 let ret =
214 unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
215 Errno::result(ret).map(drop)
216}
217
218#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
221#[cfg(feature = "process")]
222#[cfg_attr(docsrs, doc(cfg(feature = "process")))]
223pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
224 let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit();
225 let ret =
226 unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) };
227 if ret == 0 {
228 let res = unsafe { clk_id.assume_init() };
229 Ok(ClockId::from(res))
230 } else {
231 Err(Errno::from_raw(ret))
232 }
233}
234
235#[cfg(any(
236 linux_android,
237 solarish,
238 freebsdlike,
239 target_os = "netbsd",
240 target_os = "hurd",
241 target_os = "aix"
242))]
243libc_bitflags! {
244 pub struct ClockNanosleepFlags: libc::c_int {
246 TIMER_ABSTIME;
249 }
250}
251
252#[cfg(any(
262 linux_android,
263 solarish,
264 freebsdlike,
265 target_os = "netbsd",
266 target_os = "hurd",
267 target_os = "aix"
268))]
269pub fn clock_nanosleep(
270 clock_id: ClockId,
271 flags: ClockNanosleepFlags,
272 request: &TimeSpec,
273) -> Result<TimeSpec> {
274 let mut remain = TimeSpec::new(0, 0);
275 let ret = unsafe {
276 libc::clock_nanosleep(
277 clock_id.as_raw(),
278 flags.bits(),
279 request.as_ref() as *const _,
280 remain.as_mut() as *mut _,
281 )
282 };
283 if ret == 0 {
284 Ok(remain)
285 } else {
286 Err(Errno::from_raw(ret))
287 }
288}