|
| 1 | +use crate::sys::time::TimeSpec; |
| 2 | +use crate::unistd::Pid; |
| 3 | +use crate::{Errno, Error, Result}; |
| 4 | +use libc::{self, clockid_t}; |
| 5 | +use std::mem::MaybeUninit; |
| 6 | + |
| 7 | +/// Clock identifier |
| 8 | +/// |
| 9 | +/// Newtype pattern around `clockid_t` (which is just alias). It pervents bugs caused by |
| 10 | +/// accidentally passing wrong value. |
| 11 | +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] |
| 12 | +pub struct ClockId(clockid_t); |
| 13 | + |
| 14 | +impl ClockId { |
| 15 | + /// Creates `ClockId` from raw `clockid_t` |
| 16 | + pub fn from_raw(clk_id: clockid_t) -> Self { |
| 17 | + ClockId(clk_id) |
| 18 | + } |
| 19 | + |
| 20 | + /// Returns `ClockId` of a `pid` CPU-time clock |
| 21 | + #[cfg(target_os = "linux")] |
| 22 | + pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> { |
| 23 | + clock_getcpuclockid(pid) |
| 24 | + } |
| 25 | + |
| 26 | + /// Returns resolution of the clock id |
| 27 | + pub fn res(self) -> Result<TimeSpec> { |
| 28 | + clock_getres(self) |
| 29 | + } |
| 30 | + |
| 31 | + /// Returns time on the clock id |
| 32 | + pub fn time(self) -> Result<TimeSpec> { |
| 33 | + clock_gettime(self) |
| 34 | + } |
| 35 | + |
| 36 | + /// Sets time to `timespec` on the clock id |
| 37 | + #[cfg(not(any( |
| 38 | + target_os = "macos", |
| 39 | + target_os = "ios", |
| 40 | + all( |
| 41 | + not(any(target_env = "uclibc", target_env = "newlibc")), |
| 42 | + any(target_os = "redox", target_os = "hermit",), |
| 43 | + ), |
| 44 | + )))] |
| 45 | + pub fn set_time(self, timespec: TimeSpec) -> Result<()> { |
| 46 | + clock_settime(self, timespec) |
| 47 | + } |
| 48 | + |
| 49 | + /// Gets the raw `clockid_t` wrapped by `self` |
| 50 | + pub fn as_raw(self) -> clockid_t { |
| 51 | + self.0 |
| 52 | + } |
| 53 | + |
| 54 | + #[cfg(any( |
| 55 | + target_os = "fuchsia", |
| 56 | + all( |
| 57 | + not(any(target_env = "uclibc", target_env = "newlib")), |
| 58 | + any(target_os = "linux", target_os = "android", target_os = "emscripten"), |
| 59 | + ) |
| 60 | + ))] |
| 61 | + pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME); |
| 62 | + #[cfg(any( |
| 63 | + target_os = "fuchsia", |
| 64 | + all( |
| 65 | + not(any(target_env = "uclibc", target_env = "newlib")), |
| 66 | + any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 67 | + ) |
| 68 | + ))] |
| 69 | + pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM); |
| 70 | + pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); |
| 71 | + #[cfg(any( |
| 72 | + target_os = "fuchsia", |
| 73 | + all( |
| 74 | + not(any(target_env = "uclibc", target_env = "newlib")), |
| 75 | + any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 76 | + ) |
| 77 | + ))] |
| 78 | + pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE); |
| 79 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 80 | + pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST); |
| 81 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 82 | + pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE); |
| 83 | + #[cfg(any( |
| 84 | + target_os = "fuchsia", |
| 85 | + all( |
| 86 | + not(any(target_env = "uclibc", target_env = "newlib")), |
| 87 | + any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 88 | + ) |
| 89 | + ))] |
| 90 | + pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); |
| 91 | + #[cfg(any( |
| 92 | + target_os = "fuchsia", |
| 93 | + target_env = "uclibc", |
| 94 | + target_os = "macos", |
| 95 | + target_os = "ios", |
| 96 | + target_os = "freebsd", |
| 97 | + target_os = "dragonfly", |
| 98 | + all( |
| 99 | + not(target_env = "newlib"), |
| 100 | + any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 101 | + ) |
| 102 | + ))] |
| 103 | + pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); |
| 104 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 105 | + pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); |
| 106 | + pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME); |
| 107 | + #[cfg(any( |
| 108 | + target_os = "fuchsia", |
| 109 | + all( |
| 110 | + not(any(target_env = "uclibc", target_env = "newlib")), |
| 111 | + any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 112 | + ) |
| 113 | + ))] |
| 114 | + pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM); |
| 115 | + #[cfg(any( |
| 116 | + target_os = "fuchsia", |
| 117 | + all( |
| 118 | + not(any(target_env = "uclibc", target_env = "newlib")), |
| 119 | + any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 120 | + ) |
| 121 | + ))] |
| 122 | + pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE); |
| 123 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 124 | + pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST); |
| 125 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 126 | + pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE); |
| 127 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 128 | + pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); |
| 129 | + #[cfg(any( |
| 130 | + target_os = "fuchsia", |
| 131 | + all( |
| 132 | + not(any(target_env = "uclibc", target_env = "newlib")), |
| 133 | + any( |
| 134 | + target_os = "emscripten", |
| 135 | + all(target_os = "linux", target_env = "musl") |
| 136 | + ) |
| 137 | + ) |
| 138 | + ))] |
| 139 | + pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE); |
| 140 | + #[cfg(any( |
| 141 | + target_os = "fuchsia", |
| 142 | + all( |
| 143 | + not(any(target_env = "uclibc", target_env = "newlib")), |
| 144 | + any( |
| 145 | + target_os = "emscripten", |
| 146 | + all(target_os = "linux", target_env = "musl") |
| 147 | + ) |
| 148 | + ) |
| 149 | + ))] |
| 150 | + pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); |
| 151 | + #[cfg(any( |
| 152 | + target_env = "uclibc", |
| 153 | + target_os = "fuchsia", |
| 154 | + target_os = "ios", |
| 155 | + target_os = "macos", |
| 156 | + target_os = "freebsd", |
| 157 | + target_os = "dragonfly", |
| 158 | + all( |
| 159 | + not(target_env = "newlib"), |
| 160 | + any(target_os = "linux", target_os = "android", target_os = "emscripten",), |
| 161 | + ), |
| 162 | + ))] |
| 163 | + pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID); |
| 164 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 165 | + pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); |
| 166 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 167 | + pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST); |
| 168 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 169 | + pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE); |
| 170 | + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 171 | + pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); |
| 172 | +} |
| 173 | + |
| 174 | +impl Into<clockid_t> for ClockId { |
| 175 | + fn into(self) -> clockid_t { |
| 176 | + self.as_raw() |
| 177 | + } |
| 178 | +} |
| 179 | + |
| 180 | +impl From<clockid_t> for ClockId { |
| 181 | + fn from(clk_id: clockid_t) -> Self { |
| 182 | + ClockId::from_raw(clk_id) |
| 183 | + } |
| 184 | +} |
| 185 | + |
| 186 | +impl std::fmt::Display for ClockId { |
| 187 | + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| 188 | + std::fmt::Display::fmt(&self.0, f) |
| 189 | + } |
| 190 | +} |
| 191 | + |
| 192 | +/// Get the resolution of the specified clock, (see |
| 193 | +/// [clock_getres(2)](https://www.man7.org/linux/man-pages/man2/clock_getres.2.html)). |
| 194 | +pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> { |
| 195 | + let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); |
| 196 | + let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) }; |
| 197 | + Errno::result(ret)?; |
| 198 | + let res = unsafe { c_time.assume_init() }; |
| 199 | + Ok(TimeSpec::from(res)) |
| 200 | +} |
| 201 | + |
| 202 | +/// Get the time of the specified clock, (see |
| 203 | +/// [clock_gettime(2)](https://www.man7.org/linux/man-pages/man2/clock_gettime.2.html)). |
| 204 | +pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> { |
| 205 | + let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); |
| 206 | + let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) }; |
| 207 | + Errno::result(ret)?; |
| 208 | + let res = unsafe { c_time.assume_init() }; |
| 209 | + Ok(TimeSpec::from(res)) |
| 210 | +} |
| 211 | + |
| 212 | +/// Set the time of the specified clock, (see |
| 213 | +/// [clock_settime(2)](https://www.man7.org/linux/man-pages/man2/clock_settime.2.html)). |
| 214 | +#[cfg(not(any( |
| 215 | + target_os = "macos", |
| 216 | + target_os = "ios", |
| 217 | + all( |
| 218 | + not(any(target_env = "uclibc", target_env = "newlibc")), |
| 219 | + any(target_os = "redox", target_os = "hermit",), |
| 220 | + ), |
| 221 | +)))] |
| 222 | +pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { |
| 223 | + let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; |
| 224 | + Errno::result(ret).map(drop) |
| 225 | +} |
| 226 | + |
| 227 | +/// Get the clock id of the specified process id, (see |
| 228 | +/// [clock_getcpuclockid(3)](https://www.man7.org/linux/man-pages/man3/clock_getcpuclockid.3.html)). |
| 229 | +#[cfg(target_os = "linux")] |
| 230 | +pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> { |
| 231 | + let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit(); |
| 232 | + let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) }; |
| 233 | + if ret == 0 { |
| 234 | + let res = unsafe { clk_id.assume_init() }; |
| 235 | + Ok(ClockId::from(res)) |
| 236 | + } else { |
| 237 | + Err(Error::Sys(Errno::from_i32(ret))) |
| 238 | + } |
| 239 | +} |
0 commit comments