use crate::sys::time::TimeSpec;
#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
#[cfg(feature = "process")]
use crate::unistd::Pid;
use crate::{Errno, Result};
use libc::{self, clockid_t};
use std::mem::MaybeUninit;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ClockId(clockid_t);
impl ClockId {
pub const fn from_raw(clk_id: clockid_t) -> Self {
ClockId(clk_id)
}
feature! {
#![feature = "process"]
#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> {
clock_getcpuclockid(pid)
}
}
#[cfg(not(target_os = "redox"))]
pub fn res(self) -> Result<TimeSpec> {
clock_getres(self)
}
pub fn now(self) -> Result<TimeSpec> {
clock_gettime(self)
}
#[cfg(not(any(
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
target_os = "redox",
target_os = "hermit"
)))]
pub fn set_time(self, timespec: TimeSpec) -> Result<()> {
clock_settime(self, timespec)
}
pub const fn as_raw(self) -> clockid_t {
self.0
}
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME);
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
pub const CLOCK_BOOTTIME_ALARM: ClockId =
ClockId(libc::CLOCK_BOOTTIME_ALARM);
pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
pub const CLOCK_MONOTONIC_COARSE: ClockId =
ClockId(libc::CLOCK_MONOTONIC_COARSE);
#[cfg(freebsdlike)]
pub const CLOCK_MONOTONIC_FAST: ClockId =
ClockId(libc::CLOCK_MONOTONIC_FAST);
#[cfg(freebsdlike)]
pub const CLOCK_MONOTONIC_PRECISE: ClockId =
ClockId(libc::CLOCK_MONOTONIC_PRECISE);
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
#[cfg(any(
linux_android,
apple_targets,
freebsdlike,
target_os = "emscripten",
target_os = "fuchsia",
target_os = "redox",
))]
pub const CLOCK_PROCESS_CPUTIME_ID: ClockId =
ClockId(libc::CLOCK_PROCESS_CPUTIME_ID);
#[cfg(freebsdlike)]
pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
pub const CLOCK_REALTIME_ALARM: ClockId =
ClockId(libc::CLOCK_REALTIME_ALARM);
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
pub const CLOCK_REALTIME_COARSE: ClockId =
ClockId(libc::CLOCK_REALTIME_COARSE);
#[cfg(freebsdlike)]
pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST);
#[cfg(freebsdlike)]
pub const CLOCK_REALTIME_PRECISE: ClockId =
ClockId(libc::CLOCK_REALTIME_PRECISE);
#[cfg(freebsdlike)]
pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
#[allow(missing_docs)] #[cfg(any(
target_os = "emscripten",
target_os = "fuchsia",
all(target_os = "linux", target_env = "musl")
))]
pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
#[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
#[cfg(any(
linux_android,
apple_targets,
freebsdlike,
target_os = "emscripten",
target_os = "fuchsia",
))]
pub const CLOCK_THREAD_CPUTIME_ID: ClockId =
ClockId(libc::CLOCK_THREAD_CPUTIME_ID);
#[cfg(freebsdlike)]
pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
#[cfg(freebsdlike)]
pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST);
#[cfg(freebsdlike)]
pub const CLOCK_UPTIME_PRECISE: ClockId =
ClockId(libc::CLOCK_UPTIME_PRECISE);
#[cfg(freebsdlike)]
pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL);
}
impl From<ClockId> for clockid_t {
fn from(clock_id: ClockId) -> Self {
clock_id.as_raw()
}
}
impl From<clockid_t> for ClockId {
fn from(clk_id: clockid_t) -> Self {
ClockId::from_raw(clk_id)
}
}
impl std::fmt::Display for ClockId {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
#[cfg(not(target_os = "redox"))]
pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
let ret =
unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) };
Errno::result(ret)?;
let res = unsafe { c_time.assume_init() };
Ok(TimeSpec::from(res))
}
pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
let ret =
unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) };
Errno::result(ret)?;
let res = unsafe { c_time.assume_init() };
Ok(TimeSpec::from(res))
}
#[cfg(not(any(
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
target_os = "redox",
target_os = "hermit"
)))]
pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
let ret =
unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
Errno::result(ret).map(drop)
}
#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
#[cfg(feature = "process")]
#[cfg_attr(docsrs, doc(cfg(feature = "process")))]
pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit();
let ret =
unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) };
if ret == 0 {
let res = unsafe { clk_id.assume_init() };
Ok(ClockId::from(res))
} else {
Err(Errno::from_raw(ret))
}
}
#[cfg(any(
linux_android,
solarish,
freebsdlike,
target_os = "netbsd",
target_os = "hurd",
target_os = "aix"
))]
libc_bitflags! {
pub struct ClockNanosleepFlags: libc::c_int {
TIMER_ABSTIME;
}
}
#[cfg(any(
linux_android,
solarish,
freebsdlike,
target_os = "netbsd",
target_os = "hurd",
target_os = "aix"
))]
pub fn clock_nanosleep(
clock_id: ClockId,
flags: ClockNanosleepFlags,
request: &TimeSpec,
) -> Result<TimeSpec> {
let mut remain = TimeSpec::new(0, 0);
let ret = unsafe {
libc::clock_nanosleep(
clock_id.as_raw(),
flags.bits(),
request.as_ref() as *const _,
remain.as_mut() as *mut _,
)
};
if ret == 0 {
Ok(remain)
} else {
Err(Errno::from_raw(ret))
}
}