| Andrew Walbran | 12f6140 | 2020-10-14 11:10:53 +0100 | [diff] [blame^] | 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` |
| 23 | 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 | ))] |
| 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 | pub fn res(self) -> Result<TimeSpec> { |
| 41 | clock_getres(self) |
| 42 | } |
| 43 | |
| 44 | /// Returns the current time on the clock id |
| 45 | pub fn now(self) -> Result<TimeSpec> { |
| 46 | clock_gettime(self) |
| 47 | } |
| 48 | |
| 49 | /// Sets time to `timespec` on the clock id |
| 50 | #[cfg(not(any( |
| 51 | target_os = "macos", |
| 52 | target_os = "ios", |
| 53 | all( |
| 54 | not(any(target_env = "uclibc", target_env = "newlibc")), |
| 55 | any(target_os = "redox", target_os = "hermit",), |
| 56 | ), |
| 57 | )))] |
| 58 | pub fn set_time(self, timespec: TimeSpec) -> Result<()> { |
| 59 | clock_settime(self, timespec) |
| 60 | } |
| 61 | |
| 62 | /// Gets the raw `clockid_t` wrapped by `self` |
| 63 | pub fn as_raw(self) -> clockid_t { |
| 64 | self.0 |
| 65 | } |
| 66 | |
| 67 | #[cfg(any( |
| 68 | target_os = "fuchsia", |
| 69 | all( |
| 70 | not(any(target_env = "uclibc", target_env = "newlib")), |
| 71 | any(target_os = "linux", target_os = "android", target_os = "emscripten"), |
| 72 | ) |
| 73 | ))] |
| 74 | pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME); |
| 75 | #[cfg(any( |
| 76 | target_os = "fuchsia", |
| 77 | all( |
| 78 | not(any(target_env = "uclibc", target_env = "newlib")), |
| 79 | any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 80 | ) |
| 81 | ))] |
| 82 | pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM); |
| 83 | pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); |
| 84 | #[cfg(any( |
| 85 | target_os = "fuchsia", |
| 86 | all( |
| 87 | not(any(target_env = "uclibc", target_env = "newlib")), |
| 88 | any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 89 | ) |
| 90 | ))] |
| 91 | pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE); |
| 92 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 93 | pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST); |
| 94 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 95 | pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE); |
| 96 | #[cfg(any( |
| 97 | target_os = "fuchsia", |
| 98 | all( |
| 99 | not(any(target_env = "uclibc", target_env = "newlib")), |
| 100 | any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 101 | ) |
| 102 | ))] |
| 103 | pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); |
| 104 | #[cfg(any( |
| 105 | target_os = "fuchsia", |
| 106 | target_env = "uclibc", |
| 107 | target_os = "macos", |
| 108 | target_os = "ios", |
| 109 | target_os = "freebsd", |
| 110 | target_os = "dragonfly", |
| 111 | all( |
| 112 | not(target_env = "newlib"), |
| 113 | any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 114 | ) |
| 115 | ))] |
| 116 | pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); |
| 117 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 118 | pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); |
| 119 | pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME); |
| 120 | #[cfg(any( |
| 121 | target_os = "fuchsia", |
| 122 | all( |
| 123 | not(any(target_env = "uclibc", target_env = "newlib")), |
| 124 | any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 125 | ) |
| 126 | ))] |
| 127 | pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM); |
| 128 | #[cfg(any( |
| 129 | target_os = "fuchsia", |
| 130 | all( |
| 131 | not(any(target_env = "uclibc", target_env = "newlib")), |
| 132 | any(target_os = "linux", target_os = "android", target_os = "emscripten") |
| 133 | ) |
| 134 | ))] |
| 135 | pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE); |
| 136 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 137 | pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST); |
| 138 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 139 | pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE); |
| 140 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 141 | pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); |
| 142 | #[cfg(any( |
| 143 | target_os = "fuchsia", |
| 144 | all( |
| 145 | not(any(target_env = "uclibc", target_env = "newlib")), |
| 146 | any( |
| 147 | target_os = "emscripten", |
| 148 | all(target_os = "linux", target_env = "musl") |
| 149 | ) |
| 150 | ) |
| 151 | ))] |
| 152 | pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE); |
| 153 | #[cfg(any( |
| 154 | target_os = "fuchsia", |
| 155 | all( |
| 156 | not(any(target_env = "uclibc", target_env = "newlib")), |
| 157 | any( |
| 158 | target_os = "emscripten", |
| 159 | all(target_os = "linux", target_env = "musl") |
| 160 | ) |
| 161 | ) |
| 162 | ))] |
| 163 | pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); |
| 164 | #[cfg(any( |
| 165 | target_env = "uclibc", |
| 166 | target_os = "fuchsia", |
| 167 | target_os = "ios", |
| 168 | target_os = "macos", |
| 169 | target_os = "freebsd", |
| 170 | target_os = "dragonfly", |
| 171 | all( |
| 172 | not(target_env = "newlib"), |
| 173 | any(target_os = "linux", target_os = "android", target_os = "emscripten",), |
| 174 | ), |
| 175 | ))] |
| 176 | pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID); |
| 177 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 178 | pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); |
| 179 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 180 | pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST); |
| 181 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 182 | pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE); |
| 183 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] |
| 184 | pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); |
| 185 | } |
| 186 | |
| 187 | impl Into<clockid_t> for ClockId { |
| 188 | fn into(self) -> clockid_t { |
| 189 | self.as_raw() |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | impl From<clockid_t> for ClockId { |
| 194 | fn from(clk_id: clockid_t) -> Self { |
| 195 | ClockId::from_raw(clk_id) |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | impl std::fmt::Display for ClockId { |
| 200 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| 201 | std::fmt::Display::fmt(&self.0, f) |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | /// Get the resolution of the specified clock, (see |
| 206 | /// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)). |
| 207 | pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> { |
| 208 | let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); |
| 209 | let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) }; |
| 210 | Errno::result(ret)?; |
| 211 | let res = unsafe { c_time.assume_init() }; |
| 212 | Ok(TimeSpec::from(res)) |
| 213 | } |
| 214 | |
| 215 | /// Get the time of the specified clock, (see |
| 216 | /// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)). |
| 217 | pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> { |
| 218 | let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); |
| 219 | let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) }; |
| 220 | Errno::result(ret)?; |
| 221 | let res = unsafe { c_time.assume_init() }; |
| 222 | Ok(TimeSpec::from(res)) |
| 223 | } |
| 224 | |
| 225 | /// Set the time of the specified clock, (see |
| 226 | /// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)). |
| 227 | #[cfg(not(any( |
| 228 | target_os = "macos", |
| 229 | target_os = "ios", |
| 230 | all( |
| 231 | not(any(target_env = "uclibc", target_env = "newlibc")), |
| 232 | any(target_os = "redox", target_os = "hermit",), |
| 233 | ), |
| 234 | )))] |
| 235 | pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { |
| 236 | let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; |
| 237 | Errno::result(ret).map(drop) |
| 238 | } |
| 239 | |
| 240 | /// Get the clock id of the specified process id, (see |
| 241 | /// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)). |
| 242 | #[cfg(any( |
| 243 | target_os = "freebsd", |
| 244 | target_os = "dragonfly", |
| 245 | target_os = "linux", |
| 246 | target_os = "android", |
| 247 | target_os = "emscripten", |
| 248 | ))] |
| 249 | pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> { |
| 250 | let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit(); |
| 251 | let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) }; |
| 252 | if ret == 0 { |
| 253 | let res = unsafe { clk_id.assume_init() }; |
| 254 | Ok(ClockId::from(res)) |
| 255 | } else { |
| 256 | Err(Error::Sys(Errno::from_i32(ret))) |
| 257 | } |
| 258 | } |