1use crate::{Clock, Duration, Error, ProcessTimePoint, Result, TimePoint};
4
5pub(crate) fn errno() -> i32 {
6 errno::errno().into()
7}
8
9pub struct SystemClock;
11
12impl Clock for SystemClock {
13 type Output = TimePoint;
14
15 fn try_now() -> Result<Self::Output> {
16 let mut ts = libc::timespec {
17 tv_sec: 0,
18 tv_nsec: 0,
19 };
20 let ret = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut ts) };
21 if ret != 0 {
22 return Err(Error::SystemError("clock_gettime", errno()));
23 }
24 let d = Duration::from_secs(ts.tv_sec as u64) + Duration::from_nanos(ts.tv_nsec as u64);
25 Ok(TimePoint(d))
26 }
27}
28
29#[cfg(have_steady_clock)]
30#[doc = "A steady clock."]
31pub struct SteadyClock;
32
33#[cfg(have_steady_clock)]
34impl Clock for SteadyClock {
35 type Output = TimePoint;
36
37 fn try_now() -> Result<Self::Output> {
38 let mut ts = libc::timespec {
39 tv_sec: 0,
40 tv_nsec: 0,
41 };
42 let ret = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts) };
43 if ret != 0 {
44 return Err(Error::SystemError("clock_gettime", errno()));
45 }
46 let d = Duration::from_secs(ts.tv_sec as u64) + Duration::from_nanos(ts.tv_nsec as u64);
47 Ok(TimePoint(d))
48 }
49}
50
51fn tick_factor() -> Result<u64> {
52 let factor = unsafe { libc::sysconf(libc::_SC_CLK_TCK) };
53 if factor <= 0 {
54 return Err(Error::SystemError("sysconf(_SC_CLK_TCK)", errno()));
55 }
56 if factor > 1_000_000_000 {
57 return Err(Error::ClkFreqTooHigh);
58 }
59 Ok((1_000_000_000 / factor) as u64)
60}
61
62#[inline(always)]
63fn times() -> Result<(libc::clock_t, libc::tms)> {
64 let mut tm = libc::tms {
65 tms_utime: 0,
66 tms_stime: 0,
67 tms_cutime: 0,
68 tms_cstime: 0,
69 };
70 let ret = unsafe { libc::times(&mut tm) };
71 if ret == -1i64 as libc::clock_t {
72 return Err(Error::SystemError("times", errno()));
73 }
74 Ok((ret, tm))
75}
76
77pub struct ProcessRealCPUClock;
79
80impl Clock for ProcessRealCPUClock {
81 type Output = TimePoint;
82
83 fn try_now() -> Result<Self::Output> {
84 let (c, _) = times()?;
85 let factor = tick_factor()?;
86 let d = Duration::from_nanos((c as u64) * factor);
87 Ok(TimePoint(d))
88 }
89}
90
91pub struct ProcessUserCPUClock;
93
94impl Clock for ProcessUserCPUClock {
95 type Output = TimePoint;
96
97 fn try_now() -> Result<Self::Output> {
98 let (_, tm) = times()?;
99 let factor = tick_factor()?;
100 let d = Duration::from_nanos(((tm.tms_utime + tm.tms_cutime) as u64) * factor);
101 Ok(TimePoint(d))
102 }
103}
104
105pub struct ProcessSystemCPUClock;
107
108impl Clock for ProcessSystemCPUClock {
109 type Output = TimePoint;
110
111 fn try_now() -> Result<Self::Output> {
112 let (_, tm) = times()?;
113 let factor = tick_factor()?;
114 let d = Duration::from_nanos(((tm.tms_stime + tm.tms_cstime) as u64) * factor);
115 Ok(TimePoint(d))
116 }
117}
118
119pub struct ProcessCPUClock;
121
122impl Clock for ProcessCPUClock {
123 type Output = ProcessTimePoint;
124
125 fn try_now() -> Result<Self::Output> {
126 let (c, tm) = times()?;
127 let factor = tick_factor()?;
128 Ok(ProcessTimePoint {
129 real: Duration::from_nanos((c as u64) * factor),
130 user: Duration::from_nanos(((tm.tms_utime + tm.tms_cutime) as u64) * factor),
131 system: Duration::from_nanos(((tm.tms_stime + tm.tms_cstime) as u64) * factor),
132 })
133 }
134}
135
136pub struct ThreadClock;
138
139#[cfg(not(have_clock_thread_cputime_id))]
140extern "C" {
141 fn pthread_getcpuclockid(
142 thread_id: libc::pthread_t,
143 clock_id: *mut libc::clockid_t,
144 ) -> libc::c_int;
145}
146
147#[cfg(not(have_clock_thread_cputime_id))]
148#[inline(always)]
149fn get_thread_clock_id() -> Result<libc::clockid_t> {
150 let mut clock_id: libc::clockid_t = 0;
151 let ret = unsafe { pthread_getcpuclockid(libc::pthread_self(), &mut clock_id) };
152 if ret != 0 {
153 return Err(Error::SystemError("pthread_getcpuclockid", errno()));
154 }
155 Ok(clock_id)
156}
157
158impl Clock for ThreadClock {
159 type Output = TimePoint;
160
161 fn try_now() -> Result<Self::Output> {
162 let mut ts = libc::timespec {
163 tv_sec: 0,
164 tv_nsec: 0,
165 };
166 #[cfg(have_clock_thread_cputime_id)]
167 let clock_id = libc::CLOCK_THREAD_CPUTIME_ID;
168 #[cfg(not(have_clock_thread_cputime_id))]
169 let clock_id = get_thread_clock_id()?;
170 let ret = unsafe { libc::clock_gettime(clock_id, &mut ts) };
171 if ret != 0 {
172 return Err(Error::SystemError("clock_gettime", errno()));
173 }
174 let d = Duration::from_secs(ts.tv_sec as u64) + Duration::from_nanos(ts.tv_nsec as u64);
175 Ok(TimePoint(d))
176 }
177}