use crate::{
Clock,
wrapping_u64::{U64Calibration, WrappingU64Instant, WrappingU64Time},
};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Tsc(());
impl Clock for Tsc {
type Time = WrappingU64Time;
type Calibration = U64Calibration;
#[inline(always)]
fn now(&self) -> WrappingU64Instant {
WrappingU64Instant(unsafe { core::arch::x86_64::_rdtsc() })
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct TscUnavailable;
impl core::fmt::Display for TscUnavailable {
fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str("No stable TSC available")
}
}
#[cfg(feature = "std")]
impl std::error::Error for TscUnavailable {}
impl Tsc {
pub fn try_new_assume_stable() -> Result<Self, TscUnavailable> {
let edx = core::arch::x86_64::__cpuid(1).edx;
if (edx & (1 << 4)) != 0 {
Ok(Tsc(()))
} else {
Err(TscUnavailable)
}
}
#[cfg(all(target_os = "linux", feature = "std"))]
pub fn try_new_linux_sys() -> Result<Self, TscUnavailable> {
let stable_tsc_detected = std::fs::read_to_string(
"/sys/devices/system/clocksource/clocksource0/available_clocksource",
)
.is_ok_and(|x| x.contains("tsc"));
if stable_tsc_detected {
Ok(Tsc(()))
} else {
Err(TscUnavailable)
}
}
}