1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::{Clock, Duration, Instant};
use libc::{clockid_t, timespec, CLOCK_BOOTTIME, CLOCK_MONOTONIC_RAW};
pub trait PosixClock: Default {
const CLOCK_ID: clockid_t;
fn now_raw() -> timespec {
unsafe {
let mut t: timespec = std::mem::uninitialized();
let res = libc::clock_gettime(Self::CLOCK_ID, &mut t);
assert_eq!(
res,
0,
"Failed to read Linux clock with id {}",
Self::CLOCK_ID
);
t
}
}
fn resolution_raw() -> timespec {
unsafe {
let mut t: timespec = std::mem::uninitialized();
let res = libc::clock_getres(Self::CLOCK_ID, &mut t);
assert_eq!(
res,
0,
"Failed to check resolution of Linux clock with id {}",
Self::CLOCK_ID
);
t
}
}
fn resolution() -> Duration {
let t = Self::resolution_raw();
Duration((t.tv_sec as i64) * 1_000_000_000 + (t.tv_nsec as i64))
}
}
impl<C: PosixClock> Clock for C {
fn now(&self) -> Instant {
let t = Self::now_raw();
Instant((t.tv_sec as i64) * 1_000_000_000 + (t.tv_nsec as i64))
}
}
#[derive(Default)]
pub struct BootTimeClock;
impl PosixClock for BootTimeClock {
const CLOCK_ID: clockid_t = CLOCK_BOOTTIME;
}
#[derive(Default)]
pub struct MonotonicRawClock;
impl PosixClock for MonotonicRawClock {
const CLOCK_ID: clockid_t = CLOCK_MONOTONIC_RAW;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::clocks;
fn generic_posix_clock_test<C: PosixClock>() {
let t_raw_1 = C::now_raw();
let t_raw_2 = C::now_raw();
assert!(
t_raw_2.tv_sec > t_raw_1.tv_sec
|| (t_raw_2.tv_sec == t_raw_1.tv_sec && t_raw_2.tv_nsec >= t_raw_1.tv_nsec)
);
let r_raw_1 = C::resolution_raw();
let r_raw_2 = C::resolution_raw();
assert_eq!(r_raw_1.tv_sec, r_raw_2.tv_sec);
assert_eq!(r_raw_1.tv_nsec, r_raw_2.tv_nsec);
let r = C::resolution();
assert_eq!(r.as_nanos() / 1_000_000_000, r_raw_2.tv_sec as i64);
assert_eq!(r.as_nanos() % 1_000_000_000, r_raw_2.tv_nsec as i64);
assert!(r <= Duration::MILLISECOND);
clocks::tests::generic_clock_test::<C>();
}
#[test]
fn boot_time_clock() {
generic_posix_clock_test::<BootTimeClock>();
}
#[test]
fn monotonic_raw_clock() {
generic_posix_clock_test::<MonotonicRawClock>();
}
}