|
| 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 | +} |
0 commit comments