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