about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/std/src/os/linux/fs.rs21
-rw-r--r--library/std/src/sys/unix/fs.rs109
-rw-r--r--library/std/src/sys/unix/futex.rs9
-rw-r--r--library/std/src/sys/unix/thread_parker.rs3
-rw-r--r--library/std/src/sys/unix/time.rs231
5 files changed, 205 insertions, 168 deletions
diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs
index 9d18ccbeb24..23267c44685 100644
--- a/library/std/src/os/linux/fs.rs
+++ b/library/std/src/os/linux/fs.rs
@@ -356,19 +356,34 @@ impl MetadataExt for Metadata {
         self.as_inner().as_inner().st_size as u64
     }
     fn st_atime(&self) -> i64 {
-        self.as_inner().as_inner().st_atime as i64
+        let file_attr = self.as_inner();
+        #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+        if let Some(atime) = file_attr.stx_atime() {
+            return atime.tv_sec;
+        }
+        file_attr.as_inner().st_atime as i64
     }
     fn st_atime_nsec(&self) -> i64 {
         self.as_inner().as_inner().st_atime_nsec as i64
     }
     fn st_mtime(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime as i64
+        let file_attr = self.as_inner();
+        #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+        if let Some(mtime) = file_attr.stx_mtime() {
+            return mtime.tv_sec;
+        }
+        file_attr.as_inner().st_mtime as i64
     }
     fn st_mtime_nsec(&self) -> i64 {
         self.as_inner().as_inner().st_mtime_nsec as i64
     }
     fn st_ctime(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime as i64
+        let file_attr = self.as_inner();
+        #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+        if let Some(ctime) = file_attr.stx_ctime() {
+            return ctime.tv_sec;
+        }
+        file_attr.as_inner().st_ctime as i64
     }
     fn st_ctime_nsec(&self) -> i64 {
         self.as_inner().as_inner().st_ctime_nsec as i64
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 27fc7accdae..61fb2814018 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -113,10 +113,19 @@ cfg_has_statx! {{
         // This is needed to check if btime is supported by the filesystem.
         stx_mask: u32,
         stx_btime: libc::statx_timestamp,
+        // With statx, we can overcome 32-bit `time_t` too.
+        #[cfg(target_pointer_width = "32")]
+        stx_atime: libc::statx_timestamp,
+        #[cfg(target_pointer_width = "32")]
+        stx_ctime: libc::statx_timestamp,
+        #[cfg(target_pointer_width = "32")]
+        stx_mtime: libc::statx_timestamp,
+
     }
 
-    // We prefer `statx` on Linux if available, which contains file creation time.
-    // Default `stat64` contains no creation time.
+    // We prefer `statx` on Linux if available, which contains file creation time,
+    // as well as 64-bit timestamps of all kinds.
+    // Default `stat64` contains no creation time and may have 32-bit `time_t`.
     unsafe fn try_statx(
         fd: c_int,
         path: *const c_char,
@@ -192,6 +201,13 @@ cfg_has_statx! {{
         let extra = StatxExtraFields {
             stx_mask: buf.stx_mask,
             stx_btime: buf.stx_btime,
+            // Store full times to avoid 32-bit `time_t` truncation.
+            #[cfg(target_pointer_width = "32")]
+            stx_atime: buf.stx_atime,
+            #[cfg(target_pointer_width = "32")]
+            stx_ctime: buf.stx_ctime,
+            #[cfg(target_pointer_width = "32")]
+            stx_mtime: buf.stx_mtime,
         };
 
         Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
@@ -310,6 +326,36 @@ cfg_has_statx! {{
         fn from_stat64(stat: stat64) -> Self {
             Self { stat, statx_extra_fields: None }
         }
+
+        #[cfg(target_pointer_width = "32")]
+        pub fn stx_mtime(&self) -> Option<&libc::statx_timestamp> {
+            if let Some(ext) = &self.statx_extra_fields {
+                if (ext.stx_mask & libc::STATX_MTIME) != 0 {
+                    return Some(&ext.stx_mtime);
+                }
+            }
+            None
+        }
+
+        #[cfg(target_pointer_width = "32")]
+        pub fn stx_atime(&self) -> Option<&libc::statx_timestamp> {
+            if let Some(ext) = &self.statx_extra_fields {
+                if (ext.stx_mask & libc::STATX_ATIME) != 0 {
+                    return Some(&ext.stx_atime);
+                }
+            }
+            None
+        }
+
+        #[cfg(target_pointer_width = "32")]
+        pub fn stx_ctime(&self) -> Option<&libc::statx_timestamp> {
+            if let Some(ext) = &self.statx_extra_fields {
+                if (ext.stx_mask & libc::STATX_CTIME) != 0 {
+                    return Some(&ext.stx_ctime);
+                }
+            }
+            None
+        }
     }
 } else {
     impl FileAttr {
@@ -335,24 +381,15 @@ impl FileAttr {
 #[cfg(target_os = "netbsd")]
 impl FileAttr {
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_mtime as libc::time_t,
-            tv_nsec: self.stat.st_mtimensec as libc::c_long,
-        }))
+        Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtimensec as i64))
     }
 
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_atime as libc::time_t,
-            tv_nsec: self.stat.st_atimensec as libc::c_long,
-        }))
+        Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atimensec as i64))
     }
 
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_birthtime as libc::time_t,
-            tv_nsec: self.stat.st_birthtimensec as libc::c_long,
-        }))
+        Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtimensec as i64))
     }
 }
 
@@ -360,34 +397,36 @@ impl FileAttr {
 impl FileAttr {
     #[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))]
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_mtime as libc::time_t,
-            tv_nsec: self.stat.st_mtime_nsec as _,
-        }))
+        #[cfg(target_pointer_width = "32")]
+        cfg_has_statx! {
+            if let Some(mtime) = self.stx_mtime() {
+                return Ok(SystemTime::new(mtime.tv_sec, mtime.tv_nsec as i64));
+            }
+        }
+
+        Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64))
     }
 
     #[cfg(any(target_os = "vxworks", target_os = "espidf"))]
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_mtime as libc::time_t,
-            tv_nsec: 0,
-        }))
+        Ok(SystemTime::new(self.stat.st_mtime as i64, 0))
     }
 
     #[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_atime as libc::time_t,
-            tv_nsec: self.stat.st_atime_nsec as _,
-        }))
+        #[cfg(target_pointer_width = "32")]
+        cfg_has_statx! {
+            if let Some(atime) = self.stx_atime() {
+                return Ok(SystemTime::new(atime.tv_sec, atime.tv_nsec as i64));
+            }
+        }
+
+        Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64))
     }
 
     #[cfg(any(target_os = "vxworks", target_os = "espidf"))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_atime as libc::time_t,
-            tv_nsec: 0,
-        }))
+        Ok(SystemTime::new(self.stat.st_atime as i64, 0))
     }
 
     #[cfg(any(
@@ -397,10 +436,7 @@ impl FileAttr {
         target_os = "ios"
     ))]
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_birthtime as libc::time_t,
-            tv_nsec: self.stat.st_birthtime_nsec as libc::c_long,
-        }))
+        Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64))
     }
 
     #[cfg(not(any(
@@ -413,10 +449,7 @@ impl FileAttr {
         cfg_has_statx! {
             if let Some(ext) = &self.statx_extra_fields {
                 return if (ext.stx_mask & libc::STATX_BTIME) != 0 {
-                    Ok(SystemTime::from(libc::timespec {
-                        tv_sec: ext.stx_btime.tv_sec as libc::time_t,
-                        tv_nsec: ext.stx_btime.tv_nsec as _,
-                    }))
+                    Ok(SystemTime::new(ext.stx_btime.tv_sec, ext.stx_btime.tv_nsec as i64))
                 } else {
                     Err(io::const_io_error!(
                         io::ErrorKind::Uncategorized,
diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs
index 678c6f0d6ea..c1966d67078 100644
--- a/library/std/src/sys/unix/futex.rs
+++ b/library/std/src/sys/unix/futex.rs
@@ -24,8 +24,9 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
     // Calculate the timeout as an absolute timespec.
     //
     // Overflows are rounded up to an infinite timeout (None).
-    let timespec =
-        timeout.and_then(|d| Some(Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)?));
+    let timespec = timeout
+        .and_then(|d| Some(Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)?))
+        .and_then(|t| t.to_timespec());
 
     loop {
         // No need to wait if the value already changed.
@@ -41,7 +42,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
                     // identical. It supports absolute timeouts through a flag
                     // in the _umtx_time struct.
                     let umtx_timeout = timespec.map(|t| libc::_umtx_time {
-                        _timeout: t.t,
+                        _timeout: t,
                         _flags: libc::UMTX_ABSTIME,
                         _clockid: libc::CLOCK_MONOTONIC as u32,
                     });
@@ -62,7 +63,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
                         futex as *const AtomicU32,
                         libc::FUTEX_WAIT_BITSET | libc::FUTEX_PRIVATE_FLAG,
                         expected,
-                        timespec.as_ref().map_or(null(), |t| &t.t as *const libc::timespec),
+                        timespec.as_ref().map_or(null(), |t| t as *const libc::timespec),
                         null::<u32>(), // This argument is unused for FUTEX_WAIT_BITSET.
                         !0u32,         // A full bitmask, to make it behave like a regular FUTEX_WAIT.
                     )
diff --git a/library/std/src/sys/unix/thread_parker.rs b/library/std/src/sys/unix/thread_parker.rs
index cf37c01598b..30ed2ec7f54 100644
--- a/library/std/src/sys/unix/thread_parker.rs
+++ b/library/std/src/sys/unix/thread_parker.rs
@@ -79,7 +79,8 @@ unsafe fn wait_timeout(
         (Timespec::now(libc::CLOCK_MONOTONIC), dur)
     };
 
-    let timeout = now.checked_add_duration(&dur).map(|t| t.t).unwrap_or(TIMESPEC_MAX);
+    let timeout =
+        now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
     let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
     debug_assert!(r == libc::ETIMEDOUT || r == 0);
 }
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index d43ceec9c8a..ac8355188bb 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -1,21 +1,63 @@
-use crate::cmp::Ordering;
+use crate::fmt;
 use crate::time::Duration;
 
-use core::hash::{Hash, Hasher};
-
-pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
+pub use self::inner::Instant;
 use crate::convert::TryInto;
 
 const NSEC_PER_SEC: u64 = 1_000_000_000;
+pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SystemTime {
+    pub(in crate::sys::unix) t: Timespec,
+}
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub(in crate::sys::unix) struct Timespec {
-    pub t: libc::timespec,
+    tv_sec: i64,
+    tv_nsec: i64,
+}
+
+impl SystemTime {
+    pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
+        SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
+    }
+
+    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 From<libc::timespec> for SystemTime {
+    fn from(t: libc::timespec) -> SystemTime {
+        SystemTime { t: Timespec::from(t) }
+    }
+}
+
+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()
+    }
 }
 
 impl Timespec {
     const fn zero() -> Timespec {
-        Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
+        Timespec { tv_sec: 0, tv_nsec: 0 }
+    }
+
+    fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
+        Timespec { tv_sec, tv_nsec }
     }
 
     pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
@@ -23,22 +65,22 @@ impl Timespec {
             // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
             // to optimize it into a branchless form (see also #75545):
             //
-            // 1. `self.t.tv_sec - other.t.tv_sec` shows up as a common expression
+            // 1. `self.tv_sec - other.tv_sec` shows up as a common expression
             //    in both branches, i.e. the `else` must have its `- 1`
             //    subtraction after the common one, not interleaved with it
-            //    (it used to be `self.t.tv_sec - 1 - other.t.tv_sec`)
+            //    (it used to be `self.tv_sec - 1 - other.tv_sec`)
             //
             // 2. the `Duration::new` call (or any other additional complexity)
             //    is outside of the `if`-`else`, not duplicated in both branches
             //
             // Ideally this code could be rearranged such that it more
             // directly expresses the lower-cost behavior we want from it.
-            let (secs, nsec) = if self.t.tv_nsec >= other.t.tv_nsec {
-                ((self.t.tv_sec - other.t.tv_sec) as u64, (self.t.tv_nsec - other.t.tv_nsec) as u32)
+            let (secs, nsec) = if self.tv_nsec >= other.tv_nsec {
+                ((self.tv_sec - other.tv_sec) as u64, (self.tv_nsec - other.tv_nsec) as u32)
             } else {
                 (
-                    (self.t.tv_sec - other.t.tv_sec - 1) as u64,
-                    self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
+                    (self.tv_sec - other.tv_sec - 1) as u64,
+                    self.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.tv_nsec as u32,
                 )
             };
 
@@ -54,89 +96,65 @@ impl Timespec {
     pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = other
             .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
+            .try_into() // <- target type would be `i64`
             .ok()
-            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+            .and_then(|secs| self.tv_sec.checked_add(secs))?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
-        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+        let mut nsec = other.subsec_nanos() + self.tv_nsec as u32;
         if nsec >= NSEC_PER_SEC as u32 {
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
         }
-        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
+        Some(Timespec::new(secs, nsec as i64))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = other
             .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
+            .try_into() // <- target type would be `i64`
             .ok()
-            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+            .and_then(|secs| self.tv_sec.checked_sub(secs))?;
 
         // Similar to above, nanos can't overflow.
-        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
+        let mut nsec = self.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: libc::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))
+        Some(Timespec::new(secs, nsec as i64))
     }
-}
 
-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)
+    pub fn to_timespec(&self) -> Option<libc::timespec> {
+        use crate::convert::TryInto;
+        Some(libc::timespec {
+            tv_sec: self.tv_sec.try_into().ok()?,
+            tv_nsec: self.tv_nsec.try_into().ok()?,
+        })
     }
 }
 
-impl Hash for Timespec {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.t.tv_sec.hash(state);
-        self.t.tv_nsec.hash(state);
+impl From<libc::timespec> for Timespec {
+    fn from(t: libc::timespec) -> Timespec {
+        Timespec::new(t.tv_sec as i64, t.tv_nsec as i64)
     }
 }
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 mod inner {
-    use crate::fmt;
     use crate::sync::atomic::{AtomicU64, Ordering};
     use crate::sys::cvt;
     use crate::sys_common::mul_div_u64;
     use crate::time::Duration;
 
-    use super::Timespec;
-    use super::NSEC_PER_SEC;
+    use super::{SystemTime, Timespec, NSEC_PER_SEC};
 
     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
     pub struct Instant {
         t: u64,
     }
 
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub struct SystemTime {
-        pub(in crate::sys::unix) t: Timespec,
-    }
-
-    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
-
     #[repr(C)]
     #[derive(Copy, Clone)]
     struct mach_timebase_info {
@@ -178,41 +196,17 @@ mod inner {
             cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
             return SystemTime::from(s);
         }
+    }
 
-        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 From<libc::timeval> for Timespec {
+        fn from(t: libc::timeval) -> Timespec {
+            Timespec::new(t.tv_sec as i64, 1000 * t.tv_usec as i64)
         }
     }
 
     impl From<libc::timeval> for SystemTime {
         fn from(t: libc::timeval) -> SystemTime {
-            SystemTime::from(libc::timespec {
-                tv_sec: t.tv_sec,
-                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
-            })
-        }
-    }
-
-    impl From<libc::timespec> for SystemTime {
-        fn from(t: libc::timespec) -> SystemTime {
-            SystemTime { t: Timespec { t } }
-        }
-    }
-
-    impl fmt::Debug for SystemTime {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            f.debug_struct("SystemTime")
-                .field("tv_sec", &self.t.t.tv_sec)
-                .field("tv_nsec", &self.t.t.tv_nsec)
-                .finish()
+            SystemTime { t: Timespec::from(t) }
         }
     }
 
@@ -270,20 +264,13 @@ mod inner {
     use crate::sys::cvt;
     use crate::time::Duration;
 
-    use super::Timespec;
+    use super::{SystemTime, Timespec};
 
     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
     pub struct Instant {
         t: Timespec,
     }
 
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub struct SystemTime {
-        pub(in crate::sys::unix) t: Timespec,
-    }
-
-    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
-
     impl Instant {
         pub fn now() -> Instant {
             Instant { t: Timespec::now(libc::CLOCK_MONOTONIC) }
@@ -305,8 +292,8 @@ mod inner {
     impl fmt::Debug for Instant {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             f.debug_struct("Instant")
-                .field("tv_sec", &self.t.t.tv_sec)
-                .field("tv_nsec", &self.t.t.tv_nsec)
+                .field("tv_sec", &self.t.tv_sec)
+                .field("tv_nsec", &self.t.tv_nsec)
                 .finish()
         }
     }
@@ -315,33 +302,6 @@ mod inner {
         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 From<libc::timespec> for SystemTime {
-        fn from(t: libc::timespec) -> SystemTime {
-            SystemTime { t: Timespec { t } }
-        }
-    }
-
-    impl fmt::Debug for SystemTime {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            f.debug_struct("SystemTime")
-                .field("tv_sec", &self.t.t.tv_sec)
-                .field("tv_nsec", &self.t.t.tv_nsec)
-                .finish()
-        }
     }
 
     #[cfg(not(any(target_os = "dragonfly", target_os = "espidf")))]
@@ -351,9 +311,36 @@ mod inner {
 
     impl Timespec {
         pub fn now(clock: clock_t) -> Timespec {
+            // Try to use 64-bit time in preparation for Y2038.
+            #[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32"))]
+            {
+                use crate::sys::weak::weak;
+
+                // __clock_gettime64 was added to 32-bit arches in glibc 2.34,
+                // and it handles both vDSO calls and ENOSYS fallbacks itself.
+                weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int);
+
+                #[repr(C)]
+                struct __timespec64 {
+                    tv_sec: i64,
+                    #[cfg(target_endian = "big")]
+                    _padding: i32,
+                    tv_nsec: i32,
+                    #[cfg(target_endian = "little")]
+                    _padding: i32,
+                }
+
+                if let Some(clock_gettime64) = __clock_gettime64.get() {
+                    let mut t = MaybeUninit::uninit();
+                    cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
+                    let t = unsafe { t.assume_init() };
+                    return Timespec { tv_sec: t.tv_sec, tv_nsec: t.tv_nsec as i64 };
+                }
+            }
+
             let mut t = MaybeUninit::uninit();
             cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
-            Timespec { t: unsafe { t.assume_init() } }
+            Timespec::from(unsafe { t.assume_init() })
         }
     }
 }