std: move time implementations to sys (UNIX)
Now for UNIX: `Timespec` is also used for things like futex or `Condvar` timeouts, so it stays in the PAL along with some related definitions. Everything else is `SystemTime`- and `Instant`-specific, and is thus moved to `sys::time`.
This commit is contained in:
parent
6cb343bfb2
commit
05bbfa2593
4 changed files with 154 additions and 146 deletions
|
|
@ -1822,7 +1822,7 @@ impl File {
|
|||
_ => {
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))]
|
||||
{
|
||||
use crate::sys::{time::__timespec64, weak::weak};
|
||||
use crate::sys::pal::{time::__timespec64, weak::weak};
|
||||
|
||||
// Added in glibc 2.34
|
||||
weak!(
|
||||
|
|
@ -2258,7 +2258,7 @@ fn set_times_impl(p: &CStr, times: FileTimes, follow_symlinks: bool) -> io::Resu
|
|||
let flags = if follow_symlinks { 0 } else { libc::AT_SYMLINK_NOFOLLOW };
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))]
|
||||
{
|
||||
use crate::sys::{time::__timespec64, weak::weak};
|
||||
use crate::sys::pal::{time::__timespec64, weak::weak};
|
||||
|
||||
// Added in glibc 2.34
|
||||
weak!(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use core::num::niche_types::Nanoseconds;
|
||||
|
||||
use crate::sys::AsInner;
|
||||
use crate::io;
|
||||
use crate::time::Duration;
|
||||
use crate::{fmt, io};
|
||||
|
||||
const NSEC_PER_SEC: u64 = 1_000_000_000;
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
|
||||
|
||||
#[allow(dead_code)] // Used for pthread condvar timeouts
|
||||
pub const TIMESPEC_MAX: libc::timespec =
|
||||
libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
|
||||
|
|
@ -18,60 +17,19 @@ pub(in crate::sys) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec {
|
|||
tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct SystemTime {
|
||||
pub(crate) t: Timespec,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(crate) struct Timespec {
|
||||
tv_sec: i64,
|
||||
tv_nsec: Nanoseconds,
|
||||
}
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime { t: Timespec::MAX };
|
||||
|
||||
pub const MIN: SystemTime = SystemTime { t: Timespec::MIN };
|
||||
|
||||
#[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))]
|
||||
pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
|
||||
Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? })
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.t.sub_timespec(&other.t)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SystemTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SystemTime")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
pub tv_sec: i64,
|
||||
pub tv_nsec: Nanoseconds,
|
||||
}
|
||||
|
||||
impl Timespec {
|
||||
const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) };
|
||||
pub const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) };
|
||||
|
||||
// As described below, on Apple OS, dates before epoch are represented differently.
|
||||
// This is not an issue here however, because we are using tv_sec = i64::MIN,
|
||||
// which will cause the compatibility wrapper to not be executed at all.
|
||||
const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) };
|
||||
pub const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) };
|
||||
|
||||
const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec {
|
||||
Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } }
|
||||
|
|
@ -81,7 +39,7 @@ impl Timespec {
|
|||
unsafe { Self::new_unchecked(0, 0) }
|
||||
}
|
||||
|
||||
const fn new(tv_sec: i64, tv_nsec: i64) -> Result<Timespec, io::Error> {
|
||||
pub const fn new(tv_sec: i64, tv_nsec: i64) -> Result<Timespec, io::Error> {
|
||||
// On Apple OS, dates before epoch are represented differently than on other
|
||||
// Unix platforms: e.g. 1/10th of a second before epoch is represented as `seconds=-1`
|
||||
// and `nanoseconds=100_000_000` on other platforms, but is `seconds=0` and
|
||||
|
|
@ -263,98 +221,3 @@ impl __timespec64 {
|
|||
Self { tv_sec, tv_nsec, _padding: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Instant {
|
||||
t: Timespec,
|
||||
}
|
||||
|
||||
impl Instant {
|
||||
// CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
|
||||
// ner as CLOCK_MONOTONIC_RAW, but that does not incre-
|
||||
// ment while the system is asleep. The returned value
|
||||
// is identical to the result of mach_absolute_time()
|
||||
// after the appropriate mach_timebase conversion is
|
||||
// applied.
|
||||
//
|
||||
// We use `CLOCK_UPTIME_RAW` instead of `CLOCK_MONOTONIC` since
|
||||
// `CLOCK_UPTIME_RAW` is based on `mach_absolute_time`, which is the
|
||||
// clock that all timeouts and deadlines are measured against inside
|
||||
// the kernel.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
|
||||
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC;
|
||||
|
||||
pub fn now() -> Instant {
|
||||
// https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html
|
||||
Instant { t: Timespec::now(Self::CLOCK_ID) }
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.t.sub_timespec(&other.t).ok()
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
not(target_os = "linux"),
|
||||
allow(unused, reason = "needed by the `sleep_until` on some unix platforms")
|
||||
)]
|
||||
pub(crate) fn into_timespec(self) -> Timespec {
|
||||
self.t
|
||||
}
|
||||
|
||||
/// Returns `self` converted into units of `mach_absolute_time`, or `None`
|
||||
/// if `self` is before the system boot time. If the conversion cannot be
|
||||
/// performed precisely, this ceils the result up to the nearest
|
||||
/// representable value.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub fn into_mach_absolute_time_ceil(self) -> Option<u128> {
|
||||
#[repr(C)]
|
||||
struct mach_timebase_info {
|
||||
numer: u32,
|
||||
denom: u32,
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
unsafe fn mach_timebase_info(info: *mut mach_timebase_info) -> libc::kern_return_t;
|
||||
}
|
||||
|
||||
let secs = u64::try_from(self.t.tv_sec).ok()?;
|
||||
|
||||
let mut timebase = mach_timebase_info { numer: 0, denom: 0 };
|
||||
assert_eq!(unsafe { mach_timebase_info(&mut timebase) }, libc::KERN_SUCCESS);
|
||||
|
||||
// Since `tv_sec` is 64-bit and `tv_nsec` is smaller than 1 billion,
|
||||
// this cannot overflow. The resulting number needs at most 94 bits.
|
||||
let nanos =
|
||||
u128::from(secs) * u128::from(NSEC_PER_SEC) + u128::from(self.t.tv_nsec.as_inner());
|
||||
// This multiplication cannot overflow since multiplying a 94-bit
|
||||
// number by a 32-bit number yields a number that needs at most
|
||||
// 126 bits.
|
||||
Some((nanos * u128::from(timebase.denom)).div_ceil(u128::from(timebase.numer)))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<Timespec> for Instant {
|
||||
fn as_inner(&self) -> &Timespec {
|
||||
&self.t
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Instant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Instant")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ cfg_select! {
|
|||
mod uefi;
|
||||
use uefi as imp;
|
||||
}
|
||||
target_family = "unix" => {
|
||||
mod unix;
|
||||
use unix as imp;
|
||||
}
|
||||
target_os = "vexos" => {
|
||||
mod vexos;
|
||||
#[expect(unused)]
|
||||
|
|
|
|||
141
library/std/src/sys/time/unix.rs
Normal file
141
library/std/src/sys/time/unix.rs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
use crate::sys::AsInner;
|
||||
use crate::sys::pal::time::Timespec;
|
||||
use crate::time::Duration;
|
||||
use crate::{fmt, io};
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct SystemTime {
|
||||
pub(crate) t: Timespec,
|
||||
}
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime { t: Timespec::MAX };
|
||||
|
||||
pub const MIN: SystemTime = SystemTime { t: Timespec::MIN };
|
||||
|
||||
#[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))]
|
||||
pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
|
||||
Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? })
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.t.sub_timespec(&other.t)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SystemTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SystemTime")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Instant {
|
||||
t: Timespec,
|
||||
}
|
||||
|
||||
impl Instant {
|
||||
// CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
|
||||
// ner as CLOCK_MONOTONIC_RAW, but that does not incre-
|
||||
// ment while the system is asleep. The returned value
|
||||
// is identical to the result of mach_absolute_time()
|
||||
// after the appropriate mach_timebase conversion is
|
||||
// applied.
|
||||
//
|
||||
// We use `CLOCK_UPTIME_RAW` instead of `CLOCK_MONOTONIC` since
|
||||
// `CLOCK_UPTIME_RAW` is based on `mach_absolute_time`, which is the
|
||||
// clock that all timeouts and deadlines are measured against inside
|
||||
// the kernel.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
|
||||
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC;
|
||||
|
||||
pub fn now() -> Instant {
|
||||
// https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html
|
||||
Instant { t: Timespec::now(Self::CLOCK_ID) }
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.t.sub_timespec(&other.t).ok()
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
not(target_os = "linux"),
|
||||
allow(unused, reason = "needed by the `sleep_until` on some unix platforms")
|
||||
)]
|
||||
pub(crate) fn into_timespec(self) -> Timespec {
|
||||
self.t
|
||||
}
|
||||
|
||||
/// Returns `self` converted into units of `mach_absolute_time`, or `None`
|
||||
/// if `self` is before the system boot time. If the conversion cannot be
|
||||
/// performed precisely, this ceils the result up to the nearest
|
||||
/// representable value.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub fn into_mach_absolute_time_ceil(self) -> Option<u128> {
|
||||
#[repr(C)]
|
||||
struct mach_timebase_info {
|
||||
numer: u32,
|
||||
denom: u32,
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
unsafe fn mach_timebase_info(info: *mut mach_timebase_info) -> libc::kern_return_t;
|
||||
}
|
||||
|
||||
let secs = u64::try_from(self.t.tv_sec).ok()?;
|
||||
|
||||
let mut timebase = mach_timebase_info { numer: 0, denom: 0 };
|
||||
assert_eq!(unsafe { mach_timebase_info(&mut timebase) }, libc::KERN_SUCCESS);
|
||||
|
||||
// Since `tv_sec` is 64-bit and `tv_nsec` is smaller than 1 billion,
|
||||
// this cannot overflow. The resulting number needs at most 94 bits.
|
||||
let nanos = 1_000_000_000 * u128::from(secs) + u128::from(self.t.tv_nsec.as_inner());
|
||||
// This multiplication cannot overflow since multiplying a 94-bit
|
||||
// number by a 32-bit number yields a number that needs at most
|
||||
// 126 bits.
|
||||
Some((nanos * u128::from(timebase.denom)).div_ceil(u128::from(timebase.numer)))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<Timespec> for Instant {
|
||||
fn as_inner(&self) -> &Timespec {
|
||||
&self.t
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Instant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Instant")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue