about summary refs log tree commit diff
path: root/library
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-07-07 05:31:07 +0000
committerGitHub <noreply@github.com>2025-07-07 05:31:07 +0000
commit51cba7839a62ccbc1afc0c0804175577013052ea (patch)
treeddd6a21b5ea26dbb7814908658bface600f6fd20 /library
parentb2d8c81f7f1930f1a0d1a882c69322c9d7bb0545 (diff)
parent0e043a86f06d32dc9dfb4cb993ae37dfbc7c23c6 (diff)
Merge pull request #4449 from rust-lang/rustup-2025-07-07
Automatic Rustup
Diffstat (limited to 'library')
-rw-r--r--library/core/src/ffi/va_list.rs18
-rw-r--r--library/core/src/intrinsics/mod.rs23
-rw-r--r--library/core/src/ops/arith.rs2
-rw-r--r--library/core/src/slice/mod.rs8
-rw-r--r--library/core/src/slice/sort/shared/smallsort.rs2
-rw-r--r--library/core/src/slice/sort/stable/drift.rs4
-rw-r--r--library/core/src/str/count.rs2
-rw-r--r--library/core/src/str/iter.rs6
-rw-r--r--library/core/src/str/validations.rs2
-rw-r--r--library/portable-simd/crates/core_simd/src/lane_count.rs2
-rw-r--r--library/std/src/sync/poison.rs2
-rw-r--r--library/std/src/sys/net/connection/uefi/mod.rs13
-rw-r--r--library/std/src/sys/net/connection/uefi/tcp.rs6
-rw-r--r--library/std/src/sys/net/connection/uefi/tcp4.rs39
-rw-r--r--library/std/src/sys/pal/hermit/thread.rs10
-rw-r--r--library/std/src/sys/pal/itron/thread.rs10
-rw-r--r--library/std/src/sys/pal/sgx/thread.rs10
-rw-r--r--library/std/src/sys/pal/teeos/thread.rs10
-rw-r--r--library/std/src/sys/pal/uefi/thread.rs10
-rw-r--r--library/std/src/sys/pal/unix/thread.rs72
-rw-r--r--library/std/src/sys/pal/unix/time.rs18
-rw-r--r--library/std/src/sys/pal/unsupported/thread.rs6
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs10
-rw-r--r--library/std/src/sys/pal/wasm/atomics/thread.rs10
-rw-r--r--library/std/src/sys/pal/windows/thread.rs10
-rw-r--r--library/std/src/sys/pal/xous/thread.rs10
-rw-r--r--library/std/src/thread/mod.rs35
-rw-r--r--library/std/src/time.rs9
-rw-r--r--library/std/tests/thread.rs14
29 files changed, 310 insertions, 63 deletions
diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs
index 8f7c090bc1b..88ad1197777 100644
--- a/library/core/src/ffi/va_list.rs
+++ b/library/core/src/ffi/va_list.rs
@@ -5,6 +5,7 @@
 use crate::ffi::c_void;
 #[allow(unused_imports)]
 use crate::fmt;
+use crate::intrinsics::{va_arg, va_copy, va_end};
 use crate::marker::{PhantomData, PhantomInvariantLifetime};
 use crate::ops::{Deref, DerefMut};
 
@@ -280,20 +281,3 @@ impl<'f> Drop for VaListImpl<'f> {
         // This works for now, since `va_end` is a no-op on all current LLVM targets.
     }
 }
-
-/// Destroy the arglist `ap` after initialization with `va_start` or
-/// `va_copy`.
-#[rustc_intrinsic]
-#[rustc_nounwind]
-unsafe fn va_end(ap: &mut VaListImpl<'_>);
-
-/// Copies the current location of arglist `src` to the arglist `dst`.
-#[rustc_intrinsic]
-#[rustc_nounwind]
-unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
-
-/// Loads an argument of type `T` from the `va_list` `ap` and increment the
-/// argument `ap` points to.
-#[rustc_intrinsic]
-#[rustc_nounwind]
-unsafe fn va_arg<T: VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index ab99492638e..791d10eda6d 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -54,6 +54,7 @@
 )]
 #![allow(missing_docs)]
 
+use crate::ffi::va_list::{VaArgSafe, VaListImpl};
 use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple};
 use crate::ptr;
 
@@ -3142,3 +3143,25 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize
         }
     )
 }
+
+/// Copies the current location of arglist `src` to the arglist `dst`.
+///
+/// FIXME: document safety requirements
+#[rustc_intrinsic]
+#[rustc_nounwind]
+pub unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
+
+/// Loads an argument of type `T` from the `va_list` `ap` and increment the
+/// argument `ap` points to.
+///
+/// FIXME: document safety requirements
+#[rustc_intrinsic]
+#[rustc_nounwind]
+pub unsafe fn va_arg<T: VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
+
+/// Destroy the arglist `ap` after initialization with `va_start` or `va_copy`.
+///
+/// FIXME: document safety requirements
+#[rustc_intrinsic]
+#[rustc_nounwind]
+pub unsafe fn va_end(ap: &mut VaListImpl<'_>);
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index 7ffde233da3..e53c128efe0 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -627,7 +627,7 @@ macro_rules! rem_impl_float {
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
-        impl Rem for $t {
+        impl const Rem for $t {
             type Output = $t;
 
             #[inline]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 3a3f44c6b85..dc09ba8d788 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1316,7 +1316,7 @@ impl<T> [T] {
         assert_unsafe_precondition!(
             check_language_ub,
             "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
-            (n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0,
+            (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n),
         );
         // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
         let new_len = unsafe { exact_div(self.len(), N) };
@@ -1512,7 +1512,7 @@ impl<T> [T] {
         assert_unsafe_precondition!(
             check_language_ub,
             "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
-            (n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0
+            (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n)
         );
         // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
         let new_len = unsafe { exact_div(self.len(), N) };
@@ -4866,7 +4866,7 @@ impl<T> [T] {
 
         let byte_offset = elem_start.wrapping_sub(self_start);
 
-        if byte_offset % size_of::<T>() != 0 {
+        if !byte_offset.is_multiple_of(size_of::<T>()) {
             return None;
         }
 
@@ -4920,7 +4920,7 @@ impl<T> [T] {
 
         let byte_start = subslice_start.wrapping_sub(self_start);
 
-        if byte_start % size_of::<T>() != 0 {
+        if !byte_start.is_multiple_of(size_of::<T>()) {
             return None;
         }
 
diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs
index 4280f7570db..400daba16c1 100644
--- a/library/core/src/slice/sort/shared/smallsort.rs
+++ b/library/core/src/slice/sort/shared/smallsort.rs
@@ -823,7 +823,7 @@ unsafe fn bidirectional_merge<T: FreezeMarker, F: FnMut(&T, &T) -> bool>(
         let right_end = right_rev.wrapping_add(1);
 
         // Odd length, so one element is left unconsumed in the input.
-        if len % 2 != 0 {
+        if !len.is_multiple_of(2) {
             let left_nonempty = left < left_end;
             let last_src = if left_nonempty { left } else { right };
             ptr::copy_nonoverlapping(last_src, dst, 1);
diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs
index cf1df1e91a5..1edffe095a8 100644
--- a/library/core/src/slice/sort/stable/drift.rs
+++ b/library/core/src/slice/sort/stable/drift.rs
@@ -158,7 +158,7 @@ fn merge_tree_scale_factor(n: usize) -> u64 {
         panic!("Platform not supported");
     }
 
-    ((1 << 62) + n as u64 - 1) / n as u64
+    (1u64 << 62).div_ceil(n as u64)
 }
 
 // Note: merge_tree_depth output is < 64 when left < right as f*x and f*y must
@@ -182,7 +182,7 @@ fn sqrt_approx(n: usize) -> usize {
     // Finally we note that the exponentiation / division can be done directly
     // with shifts. We OR with 1 to avoid zero-checks in the integer log.
     let ilog = (n | 1).ilog2();
-    let shift = (1 + ilog) / 2;
+    let shift = ilog.div_ceil(2);
     ((1 << shift) + (n >> shift)) / 2
 }
 
diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs
index 452403b23de..f59ad3e66b4 100644
--- a/library/core/src/str/count.rs
+++ b/library/core/src/str/count.rs
@@ -52,7 +52,7 @@ fn do_count_chars(s: &str) -> usize {
     // Check the properties of `CHUNK_SIZE` and `UNROLL_INNER` that are required
     // for correctness.
     const _: () = assert!(CHUNK_SIZE < 256);
-    const _: () = assert!(CHUNK_SIZE % UNROLL_INNER == 0);
+    const _: () = assert!(CHUNK_SIZE.is_multiple_of(UNROLL_INNER));
 
     // SAFETY: transmuting `[u8]` to `[usize]` is safe except for size
     // differences which are handled by `align_to`.
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 425c4eaee28..bcf886484ad 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -102,7 +102,7 @@ impl<'a> Iterator for Chars<'a> {
         // `(len + 3)` can't overflow, because we know that the `slice::Iter`
         // belongs to a slice in memory which has a maximum length of
         // `isize::MAX` (that's well below `usize::MAX`).
-        ((len + 3) / 4, Some(len))
+        (len.div_ceil(4), Some(len))
     }
 
     #[inline]
@@ -1532,11 +1532,11 @@ impl<'a> Iterator for EncodeUtf16<'a> {
         // belongs to a slice in memory which has a maximum length of
         // `isize::MAX` (that's well below `usize::MAX`)
         if self.extra == 0 {
-            ((len + 2) / 3, Some(len))
+            (len.div_ceil(3), Some(len))
         } else {
             // We're in the middle of a surrogate pair, so add the remaining
             // surrogate to the bounds.
-            ((len + 2) / 3 + 1, Some(len + 1))
+            (len.div_ceil(3) + 1, Some(len + 1))
         }
     }
 }
diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs
index 8174e4ff97d..b54d6478e58 100644
--- a/library/core/src/str/validations.rs
+++ b/library/core/src/str/validations.rs
@@ -219,7 +219,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
             // Ascii case, try to skip forward quickly.
             // When the pointer is aligned, read 2 words of data per iteration
             // until we find a word containing a non-ascii byte.
-            if align != usize::MAX && align.wrapping_sub(index) % USIZE_BYTES == 0 {
+            if align != usize::MAX && align.wrapping_sub(index).is_multiple_of(USIZE_BYTES) {
                 let ptr = v.as_ptr();
                 while index < blocks_end {
                     // SAFETY: since `align - index` and `ascii_block_size` are
diff --git a/library/portable-simd/crates/core_simd/src/lane_count.rs b/library/portable-simd/crates/core_simd/src/lane_count.rs
index 280b27bc9bc..bbdfd5f5f3e 100644
--- a/library/portable-simd/crates/core_simd/src/lane_count.rs
+++ b/library/portable-simd/crates/core_simd/src/lane_count.rs
@@ -8,7 +8,7 @@ pub struct LaneCount<const N: usize>;
 
 impl<const N: usize> LaneCount<N> {
     /// The number of bytes in a bitmask with this many lanes.
-    pub const BITMASK_LEN: usize = (N + 7) / 8;
+    pub const BITMASK_LEN: usize = N.div_ceil(8);
 }
 
 /// Statically guarantees that a lane count is marked as supported.
diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs
index cc1d0b30152..571f0d14248 100644
--- a/library/std/src/sync/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -13,7 +13,7 @@
 //! depend on the primitive. See [#Overview] bellow.
 //!
 //! For the alternative implementations that do not employ poisoning,
-//! see `std::sys::nonpoisoning`.
+//! see `std::sync::nonpoisoning`.
 //!
 //! # Overview
 //!
diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs
index 2d465bd0efa..6835ba44ee2 100644
--- a/library/std/src/sys/net/connection/uefi/mod.rs
+++ b/library/std/src/sys/net/connection/uefi/mod.rs
@@ -38,16 +38,17 @@ impl TcpStream {
         unsupported()
     }
 
-    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
-        unsupported()
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
     }
 
-    pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
-        unsupported()
+    pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|buf| self.read(buf), cursor)
     }
 
-    pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        unsupported()
+    pub fn read_vectored(&self, buf: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        // FIXME: UEFI does support vectored read, so implement that.
+        crate::io::default_read_vectored(|b| self.read(b), buf)
     }
 
     pub fn is_read_vectored(&self) -> bool {
diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs
index 9c3462e3468..55b6dbf2490 100644
--- a/library/std/src/sys/net/connection/uefi/tcp.rs
+++ b/library/std/src/sys/net/connection/uefi/tcp.rs
@@ -24,4 +24,10 @@ impl Tcp {
             Self::V4(client) => client.write(buf),
         }
     }
+
+    pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        match self {
+            Self::V4(client) => client.read(buf),
+        }
+    }
 }
diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs
index d0f0d27d975..af1ba2be47a 100644
--- a/library/std/src/sys/net/connection/uefi/tcp4.rs
+++ b/library/std/src/sys/net/connection/uefi/tcp4.rs
@@ -128,6 +128,45 @@ impl Tcp4 {
         }
     }
 
+    pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let evt = unsafe { self.create_evt() }?;
+        let completion_token =
+            tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
+        let data_len = u32::try_from(buf.len()).unwrap_or(u32::MAX);
+
+        let fragment = tcp4::FragmentData {
+            fragment_length: data_len,
+            fragment_buffer: buf.as_mut_ptr().cast::<crate::ffi::c_void>(),
+        };
+        let mut tx_data = tcp4::ReceiveData {
+            urgent_flag: r_efi::efi::Boolean::FALSE,
+            data_length: data_len,
+            fragment_count: 1,
+            fragment_table: [fragment],
+        };
+
+        let protocol = self.protocol.as_ptr();
+        let mut token = tcp4::IoToken {
+            completion_token,
+            packet: tcp4::IoTokenPacket {
+                rx_data: (&raw mut tx_data).cast::<tcp4::ReceiveData<0>>(),
+            },
+        };
+
+        let r = unsafe { ((*protocol).receive)(protocol, &mut token) };
+        if r.is_error() {
+            return Err(io::Error::from_raw_os_error(r.as_usize()));
+        }
+
+        self.wait_for_flag();
+
+        if completion_token.status.is_error() {
+            Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
+        } else {
+            Ok(data_len as usize)
+        }
+    }
+
     unsafe fn create_evt(&self) -> io::Result<helpers::OwnedEvent> {
         self.flag.store(false, Ordering::Relaxed);
         helpers::OwnedEvent::new(
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index bb68a824fc3..9bc5a16b800 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -4,7 +4,7 @@ use super::hermit_abi;
 use crate::ffi::CStr;
 use crate::mem::ManuallyDrop;
 use crate::num::NonZero;
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 use crate::{io, ptr};
 
 pub type Tid = hermit_abi::Tid;
@@ -86,6 +86,14 @@ impl Thread {
         }
     }
 
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     pub fn join(self) {
         unsafe {
             let _ = hermit_abi::join(self.tid);
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index a974f4f17ae..813e1cbcd58 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -10,7 +10,7 @@ use crate::mem::ManuallyDrop;
 use crate::num::NonZero;
 use crate::ptr::NonNull;
 use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 use crate::{hint, io};
 
 pub struct Thread {
@@ -205,6 +205,14 @@ impl Thread {
         }
     }
 
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     pub fn join(self) {
         // Safety: `ThreadInner` is alive at this point
         let inner = unsafe { self.p_inner.as_ref() };
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index 219ef1b7a98..85f6dcd96b4 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -5,7 +5,7 @@ use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 
 pub struct Thread(task_queue::JoinHandle);
 
@@ -132,6 +132,14 @@ impl Thread {
         usercalls::wait_timeout(0, dur, || true);
     }
 
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     pub fn join(self) {
         self.0.wait();
     }
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs
index e3b4908f858..b9cdc7a2a58 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/pal/teeos/thread.rs
@@ -2,7 +2,7 @@ use crate::ffi::CStr;
 use crate::mem::{self, ManuallyDrop};
 use crate::num::NonZero;
 use crate::sys::os;
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 use crate::{cmp, io, ptr};
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024;
@@ -109,6 +109,14 @@ impl Thread {
         }
     }
 
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     /// must join, because no pthread_detach supported
     pub fn join(self) {
         let id = self.into_id();
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
index 7d4006ff4b2..e4776ec42fb 100644
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ b/library/std/src/sys/pal/uefi/thread.rs
@@ -3,7 +3,7 @@ use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
 use crate::ptr::NonNull;
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 
 pub struct Thread(!);
 
@@ -39,6 +39,14 @@ impl Thread {
         }
     }
 
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     pub fn join(self) {
         self.0
     }
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index d8b189413f4..53f0d1eeda5 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -6,7 +6,7 @@ use crate::sys::weak::dlsym;
 #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))]
 use crate::sys::weak::weak;
 use crate::sys::{os, stack_overflow};
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 use crate::{cmp, io, ptr};
 #[cfg(not(any(
     target_os = "l4re",
@@ -296,6 +296,76 @@ impl Thread {
         }
     }
 
+    // Any unix that has clock_nanosleep
+    // If this list changes update the MIRI chock_nanosleep shim
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "netbsd",
+        target_os = "linux",
+        target_os = "android",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "dragonfly",
+        target_os = "hurd",
+        target_os = "fuchsia",
+        target_os = "vxworks",
+    ))]
+    pub fn sleep_until(deadline: Instant) {
+        let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else {
+            // The deadline is further in the future then can be passed to
+            // clock_nanosleep. We have to use Self::sleep instead. This might
+            // happen on 32 bit platforms, especially closer to 2038.
+            let now = Instant::now();
+            if let Some(delay) = deadline.checked_duration_since(now) {
+                Self::sleep(delay);
+            }
+            return;
+        };
+
+        unsafe {
+            // When we get interrupted (res = EINTR) call clock_nanosleep again
+            loop {
+                let res = libc::clock_nanosleep(
+                    super::time::Instant::CLOCK_ID,
+                    libc::TIMER_ABSTIME,
+                    &ts,
+                    core::ptr::null_mut(), // not required with TIMER_ABSTIME
+                );
+
+                if res == 0 {
+                    break;
+                } else {
+                    assert_eq!(
+                        res,
+                        libc::EINTR,
+                        "timespec is in range,
+                         clockid is valid and kernel should support it"
+                    );
+                }
+            }
+        }
+    }
+
+    // Any unix that does not have clock_nanosleep
+    #[cfg(not(any(
+        target_os = "freebsd",
+        target_os = "netbsd",
+        target_os = "linux",
+        target_os = "android",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "dragonfly",
+        target_os = "hurd",
+        target_os = "fuchsia",
+        target_os = "vxworks",
+    )))]
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     pub fn join(self) {
         let id = self.into_id();
         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs
index 0074d767474..bd7f74fea6a 100644
--- a/library/std/src/sys/pal/unix/time.rs
+++ b/library/std/src/sys/pal/unix/time.rs
@@ -261,6 +261,10 @@ pub struct Instant {
 }
 
 impl Instant {
+    #[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://www.manpagez.com/man/3/clock_gettime/
         //
@@ -273,11 +277,7 @@ impl Instant {
         //
         // Instant on macos was historically implemented using mach_absolute_time;
         // we preserve this value domain out of an abundance of caution.
-        #[cfg(target_vendor = "apple")]
-        const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
-        #[cfg(not(target_vendor = "apple"))]
-        const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC;
-        Instant { t: Timespec::now(clock_id) }
+        Instant { t: Timespec::now(Self::CLOCK_ID) }
     }
 
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
@@ -291,6 +291,14 @@ impl Instant {
     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
+    }
 }
 
 impl fmt::Debug for Instant {
diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs
index 89f8bad7026..8a3119fa292 100644
--- a/library/std/src/sys/pal/unsupported/thread.rs
+++ b/library/std/src/sys/pal/unsupported/thread.rs
@@ -2,7 +2,7 @@ use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 
 pub struct Thread(!);
 
@@ -26,6 +26,10 @@ impl Thread {
         panic!("can't sleep");
     }
 
+    pub fn sleep_until(_deadline: Instant) {
+        panic!("can't sleep");
+    }
+
     pub fn join(self) {
         self.0
     }
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index cc569bb3daf..5f21a553673 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -2,7 +2,7 @@
 
 use crate::ffi::CStr;
 use crate::num::NonZero;
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 use crate::{io, mem};
 
 cfg_if::cfg_if! {
@@ -171,6 +171,14 @@ impl Thread {
         }
     }
 
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     pub fn join(self) {
         cfg_if::cfg_if! {
             if #[cfg(target_feature = "atomics")] {
diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs
index dd5aff391fd..44ce3eab109 100644
--- a/library/std/src/sys/pal/wasm/atomics/thread.rs
+++ b/library/std/src/sys/pal/wasm/atomics/thread.rs
@@ -2,7 +2,7 @@ use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
 use crate::sys::unsupported;
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 
 pub struct Thread(!);
 
@@ -41,6 +41,14 @@ impl Thread {
         }
     }
 
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     pub fn join(self) {}
 }
 
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 45e52cf4d04..14785171755 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -8,7 +8,7 @@ use crate::os::windows::io::{AsRawHandle, HandleOrNull};
 use crate::sys::handle::Handle;
 use crate::sys::{c, stack_overflow};
 use crate::sys_common::FromInner;
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 use crate::{io, ptr};
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -106,6 +106,14 @@ impl Thread {
         }
     }
 
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     pub fn handle(&self) -> &Handle {
         &self.handle
     }
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs
index 0ebb46dc19f..1b344e984dc 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/pal/xous/thread.rs
@@ -8,7 +8,7 @@ use crate::os::xous::ffi::{
     map_memory, update_memory_flags,
 };
 use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 
 pub struct Thread {
     tid: ThreadId,
@@ -128,6 +128,14 @@ impl Thread {
         }
     }
 
+    pub fn sleep_until(deadline: Instant) {
+        let now = Instant::now();
+
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            Self::sleep(delay);
+        }
+    }
+
     pub fn join(self) {
         join_thread(self.tid).unwrap();
     }
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 26b2fb44724..6075173db47 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -897,8 +897,31 @@ pub fn sleep(dur: Duration) {
 ///
 /// # Platform-specific behavior
 ///
-/// This function uses [`sleep`] internally, see its platform-specific behavior.
+/// In most cases this function will call an OS specific function. Where that
+/// is not supported [`sleep`] is used. Those platforms are referred to as other
+/// in the table below.
 ///
+/// # Underlying System calls
+///
+/// The following system calls are [currently] being used:
+///
+/// |  Platform |               System call                                            |
+/// |-----------|----------------------------------------------------------------------|
+/// | Linux     | [clock_nanosleep] (Monotonic clock)                                  |
+/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock)]                        |
+/// | Android   | [clock_nanosleep] (Monotonic Clock)]                                 |
+/// | Solaris   | [clock_nanosleep] (Monotonic Clock)]                                 |
+/// | Illumos   | [clock_nanosleep] (Monotonic Clock)]                                 |
+/// | Dragonfly | [clock_nanosleep] (Monotonic Clock)]                                 |
+/// | Hurd      | [clock_nanosleep] (Monotonic Clock)]                                 |
+/// | Fuchsia   | [clock_nanosleep] (Monotonic Clock)]                                 |
+/// | Vxworks   | [clock_nanosleep] (Monotonic Clock)]                                 |
+/// | Other     | `sleep_until` uses [`sleep`] and does not issue a syscall itself     |
+///
+/// [currently]: crate::io#platform-specific-behavior
+/// [clock_nanosleep]: https://linux.die.net/man/3/clock_nanosleep
+///
+/// **Disclaimer:** These system calls might change over time.
 ///
 /// # Examples
 ///
@@ -923,9 +946,9 @@ pub fn sleep(dur: Duration) {
 /// }
 /// ```
 ///
-/// A slow api we must not call too fast and which takes a few
+/// A slow API we must not call too fast and which takes a few
 /// tries before succeeding. By using `sleep_until` the time the
-/// api call takes does not influence when we retry or when we give up
+/// API call takes does not influence when we retry or when we give up
 ///
 /// ```no_run
 /// #![feature(thread_sleep_until)]
@@ -960,11 +983,7 @@ pub fn sleep(dur: Duration) {
 /// ```
 #[unstable(feature = "thread_sleep_until", issue = "113752")]
 pub fn sleep_until(deadline: Instant) {
-    let now = Instant::now();
-
-    if let Some(delay) = deadline.checked_duration_since(now) {
-        sleep(delay);
-    }
+    imp::Thread::sleep_until(deadline)
 }
 
 /// Used to ensure that `park` and `park_timeout` do not unwind, as that can
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 393426be087..cd0683f44c9 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -407,6 +407,15 @@ impl Instant {
     pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
         self.0.checked_sub_duration(&duration).map(Instant)
     }
+
+    // Used by platform specific `sleep_until` implementations such as the one used on Linux.
+    #[cfg_attr(
+        not(target_os = "linux"),
+        allow(unused, reason = "not every platform has a specific `sleep_until`")
+    )]
+    pub(crate) fn into_inner(self) -> time::Instant {
+        self.0
+    }
 }
 
 #[stable(feature = "time2", since = "1.8.0")]
diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs
index 1bb17d149fa..32561dd6ab6 100644
--- a/library/std/tests/thread.rs
+++ b/library/std/tests/thread.rs
@@ -1,7 +1,8 @@
+#![feature(thread_sleep_until)]
 use std::cell::{Cell, RefCell};
 use std::sync::{Arc, Mutex};
 use std::thread;
-use std::time::Duration;
+use std::time::{Duration, Instant};
 
 #[test]
 #[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
@@ -18,6 +19,17 @@ fn sleep_very_long() {
 }
 
 #[test]
+fn sleep_until() {
+    let now = Instant::now();
+    let period = Duration::from_millis(100);
+    let deadline = now + period;
+    thread::sleep_until(deadline);
+
+    let elapsed = now.elapsed();
+    assert!(elapsed >= period);
+}
+
+#[test]
 fn thread_local_containing_const_statements() {
     // This exercises the `const $init:block` cases of the thread_local macro.
     // Despite overlapping with expression syntax, the `const { ... }` is not