Rollup merge of #154234 - stepancheg:hermit-timespec, r=Mark-Simulacrum

Use common Timestamp impl in Hermit (attempt 2)

The goal is to have less code to maintain, so to be able to make changes easier.

Previous attempt https://github.com/rust-lang/rust/pull/148847 was asked to postpone because there was restructure of code, which is complete now.

r? joboet
This commit is contained in:
Stuart Cook
2026-03-28 15:01:39 +11:00
committed by GitHub
5 changed files with 17 additions and 125 deletions
+3 -3
View File
@@ -109,15 +109,15 @@ pub struct DirBuilder {
impl FileAttr {
pub fn modified(&self) -> io::Result<SystemTime> {
Ok(SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec))
SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec.into())
}
pub fn accessed(&self) -> io::Result<SystemTime> {
Ok(SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec))
SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec.into())
}
pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec))
SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec.into())
}
pub fn size(&self) -> u64 {
+1
View File
@@ -22,6 +22,7 @@
use crate::sys::env;
pub mod futex;
#[path = "../unix/time.rs"]
pub mod time;
pub fn unsupported<T>() -> io::Result<T> {
-110
View File
@@ -1,110 +0,0 @@
use hermit_abi::{self, timespec};
use crate::cmp::Ordering;
use crate::hash::{Hash, Hasher};
use crate::time::Duration;
const NSEC_PER_SEC: i32 = 1_000_000_000;
#[derive(Copy, Clone, Debug)]
pub struct Timespec {
pub t: timespec,
}
impl Timespec {
pub const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1);
pub const MIN: Timespec = Self::new(i64::MIN, 0);
pub const fn zero() -> Timespec {
Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } }
}
pub const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec {
assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC);
// SAFETY: The assert above checks tv_nsec is within the valid range
Timespec { t: timespec { tv_sec, tv_nsec } }
}
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 {
debug_assert!(a >= b);
a.wrapping_sub(b).cast_unsigned()
}
if self >= other {
// Logic here is identical to Unix version of `Timestamp::sub_timespec`,
// check comments there why operations do not overflow.
Ok(if self.t.tv_nsec >= other.t.tv_nsec {
Duration::new(
sub_ge_to_unsigned(self.t.tv_sec, other.t.tv_sec),
(self.t.tv_nsec - other.t.tv_nsec) as u32,
)
} else {
Duration::new(
sub_ge_to_unsigned(self.t.tv_sec - 1, other.t.tv_sec),
(self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32,
)
})
} else {
match other.sub_timespec(self) {
Ok(d) => Err(d),
Err(d) => Ok(d),
}
}
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?;
// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap();
if nsec >= NSEC_PER_SEC.try_into().unwrap() {
nsec -= u32::try_from(NSEC_PER_SEC).unwrap();
secs = secs.checked_add(1)?;
}
Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?;
// Similar to above, nanos can't overflow.
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
if nsec < 0 {
nsec += NSEC_PER_SEC as i32;
secs = secs.checked_sub(1)?;
}
Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
}
}
impl PartialEq for Timespec {
fn eq(&self, other: &Timespec) -> bool {
self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
}
}
impl Eq for Timespec {}
impl PartialOrd for Timespec {
fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Timespec {
fn cmp(&self, other: &Timespec) -> Ordering {
let me = (self.t.tv_sec, self.t.tv_nsec);
let other = (other.t.tv_sec, other.t.tv_nsec);
me.cmp(&other)
}
}
impl Hash for Timespec {
fn hash<H: Hasher>(&self, state: &mut H) {
self.t.tv_sec.hash(state);
self.t.tv_nsec.hash(state);
}
}
+2 -1
View File
@@ -17,7 +17,7 @@
tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64,
};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub(crate) struct Timespec {
pub tv_sec: i64,
pub tv_nsec: Nanoseconds,
@@ -66,6 +66,7 @@ pub const fn new(tv_sec: i64, tv_nsec: i64) -> Result<Timespec, io::Error> {
}
}
#[allow(dead_code)]
pub fn now(clock: libc::clockid_t) -> Timespec {
use crate::mem::MaybeUninit;
use crate::sys::cvt;
+11 -11
View File
@@ -1,18 +1,21 @@
use hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME};
use crate::hash::Hash;
use crate::io;
use crate::sys::pal::time::Timespec;
use crate::time::Duration;
fn clock_gettime(clock: hermit_abi::clockid_t) -> Timespec {
let mut t = hermit_abi::timespec { tv_sec: 0, tv_nsec: 0 };
let _ = unsafe { hermit_abi::clock_gettime(clock, &raw mut t) };
Timespec::new(t.tv_sec, t.tv_nsec.into()).unwrap()
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant(Timespec);
impl Instant {
pub fn now() -> Instant {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) };
Instant(time)
Instant(clock_gettime(CLOCK_MONOTONIC))
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
@@ -38,15 +41,12 @@ impl SystemTime {
pub const MIN: SystemTime = SystemTime(Timespec::MIN);
pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime {
SystemTime(Timespec::new(tv_sec, tv_nsec))
pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
Ok(SystemTime(Timespec::new(tv_sec, tv_nsec)?))
}
pub fn now() -> SystemTime {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) };
SystemTime(time)
SystemTime(clock_gettime(CLOCK_REALTIME))
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {