about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/hermit/condvar.rs90
-rw-r--r--library/std/src/sys/hermit/fs.rs12
-rw-r--r--library/std/src/sys/hermit/futex.rs39
-rw-r--r--library/std/src/sys/hermit/mod.rs17
-rw-r--r--library/std/src/sys/hermit/mutex.rs216
-rw-r--r--library/std/src/sys/hermit/net.rs2
-rw-r--r--library/std/src/sys/hermit/rwlock.rs144
-rw-r--r--library/std/src/sys/itron/mutex.rs6
-rw-r--r--library/std/src/sys/sgx/abi/thread.rs8
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/alloc.rs28
-rw-r--r--library/std/src/sys/sgx/mod.rs2
-rw-r--r--library/std/src/sys/sgx/mutex.rs3
-rw-r--r--library/std/src/sys/solid/mod.rs2
-rw-r--r--library/std/src/sys/solid/os.rs4
-rw-r--r--library/std/src/sys/unix/locks/fuchsia_mutex.rs5
-rw-r--r--library/std/src/sys/unix/locks/futex_mutex.rs5
-rw-r--r--library/std/src/sys/unix/locks/futex_rwlock.rs2
-rw-r--r--library/std/src/sys/unix/locks/mod.rs6
-rw-r--r--library/std/src/sys/unix/locks/pthread_mutex.rs2
-rw-r--r--library/std/src/sys/unix/mod.rs36
-rw-r--r--library/std/src/sys/unix/os.rs12
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs4
-rw-r--r--library/std/src/sys/unix/thread.rs2
-rw-r--r--library/std/src/sys/unix/thread_parker/mod.rs21
-rw-r--r--library/std/src/sys/unix/thread_parker/netbsd.rs113
-rw-r--r--library/std/src/sys/unix/thread_parker/pthread.rs (renamed from library/std/src/sys/unix/thread_parker.rs)14
-rw-r--r--library/std/src/sys/unsupported/common.rs2
-rw-r--r--library/std/src/sys/unsupported/locks/condvar.rs1
-rw-r--r--library/std/src/sys/unsupported/locks/mod.rs2
-rw-r--r--library/std/src/sys/unsupported/locks/mutex.rs4
-rw-r--r--library/std/src/sys/unsupported/locks/rwlock.rs1
-rw-r--r--library/std/src/sys/wasm/mod.rs2
-rw-r--r--library/std/src/sys/windows/alloc.rs1
-rw-r--r--library/std/src/sys/windows/c.rs22
-rw-r--r--library/std/src/sys/windows/cmath.rs2
-rw-r--r--library/std/src/sys/windows/fs.rs56
-rw-r--r--library/std/src/sys/windows/locks/mod.rs2
-rw-r--r--library/std/src/sys/windows/locks/mutex.rs2
-rw-r--r--library/std/src/sys/windows/mod.rs2
-rw-r--r--library/std/src/sys/windows/path.rs9
-rw-r--r--library/std/src/sys/windows/path/tests.rs31
-rw-r--r--library/std/src/sys/windows/rand.rs117
42 files changed, 447 insertions, 604 deletions
diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs
deleted file mode 100644
index 22059ca0dbe..00000000000
--- a/library/std/src/sys/hermit/condvar.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-use crate::ffi::c_void;
-use crate::ptr;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sys::hermit::abi;
-use crate::sys::locks::Mutex;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-use crate::time::Duration;
-
-// The implementation is inspired by Andrew D. Birrell's paper
-// "Implementing Condition Variables with Semaphores"
-
-pub struct Condvar {
-    counter: AtomicUsize,
-    sem1: *const c_void,
-    sem2: *const c_void,
-}
-
-pub(crate) type MovableCondvar = LazyBox<Condvar>;
-
-impl LazyInit for Condvar {
-    fn init() -> Box<Self> {
-        Box::new(Self::new())
-    }
-}
-
-unsafe impl Send for Condvar {}
-unsafe impl Sync for Condvar {}
-
-impl Condvar {
-    pub fn new() -> Self {
-        let mut condvar =
-            Self { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() };
-        unsafe {
-            let _ = abi::sem_init(&mut condvar.sem1, 0);
-            let _ = abi::sem_init(&mut condvar.sem2, 0);
-        }
-        condvar
-    }
-
-    pub unsafe fn notify_one(&self) {
-        if self.counter.load(SeqCst) > 0 {
-            self.counter.fetch_sub(1, SeqCst);
-            abi::sem_post(self.sem1);
-            abi::sem_timedwait(self.sem2, 0);
-        }
-    }
-
-    pub unsafe fn notify_all(&self) {
-        let counter = self.counter.swap(0, SeqCst);
-        for _ in 0..counter {
-            abi::sem_post(self.sem1);
-        }
-        for _ in 0..counter {
-            abi::sem_timedwait(self.sem2, 0);
-        }
-    }
-
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        self.counter.fetch_add(1, SeqCst);
-        mutex.unlock();
-        abi::sem_timedwait(self.sem1, 0);
-        abi::sem_post(self.sem2);
-        mutex.lock();
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        self.counter.fetch_add(1, SeqCst);
-        mutex.unlock();
-        let millis = dur.as_millis().min(u32::MAX as u128) as u32;
-
-        let res = if millis > 0 {
-            abi::sem_timedwait(self.sem1, millis)
-        } else {
-            abi::sem_trywait(self.sem1)
-        };
-
-        abi::sem_post(self.sem2);
-        mutex.lock();
-        res == 0
-    }
-}
-
-impl Drop for Condvar {
-    fn drop(&mut self) {
-        unsafe {
-            let _ = abi::sem_destroy(self.sem1);
-            let _ = abi::sem_destroy(self.sem2);
-        }
-    }
-}
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 1c5efa94bd3..f921839cf52 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -41,6 +41,9 @@ pub struct OpenOptions {
     mode: i32,
 }
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {}
+
 pub struct FilePermissions(!);
 
 pub struct FileType(!);
@@ -110,6 +113,11 @@ impl fmt::Debug for FilePermissions {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, _t: SystemTime) {}
+    pub fn set_modified(&mut self, _t: SystemTime) {}
+}
+
 impl FileType {
     pub fn is_dir(&self) -> bool {
         self.0
@@ -344,6 +352,10 @@ impl File {
     pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
         Err(Error::from_raw_os_error(22))
     }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        Err(Error::from_raw_os_error(22))
+    }
 }
 
 impl DirBuilder {
diff --git a/library/std/src/sys/hermit/futex.rs b/library/std/src/sys/hermit/futex.rs
new file mode 100644
index 00000000000..b64c174b06c
--- /dev/null
+++ b/library/std/src/sys/hermit/futex.rs
@@ -0,0 +1,39 @@
+use super::abi;
+use crate::ptr::null;
+use crate::sync::atomic::AtomicU32;
+use crate::time::Duration;
+
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+    // Calculate the timeout as a relative timespec.
+    //
+    // Overflows are rounded up to an infinite timeout (None).
+    let timespec = timeout.and_then(|dur| {
+        Some(abi::timespec {
+            tv_sec: dur.as_secs().try_into().ok()?,
+            tv_nsec: dur.subsec_nanos().into(),
+        })
+    });
+
+    let r = unsafe {
+        abi::futex_wait(
+            futex.as_mut_ptr(),
+            expected,
+            timespec.as_ref().map_or(null(), |t| t as *const abi::timespec),
+            abi::FUTEX_RELATIVE_TIMEOUT,
+        )
+    };
+
+    r != -abi::errno::ETIMEDOUT
+}
+
+#[inline]
+pub fn futex_wake(futex: &AtomicU32) -> bool {
+    unsafe { abi::futex_wake(futex.as_mut_ptr(), 1) > 0 }
+}
+
+#[inline]
+pub fn futex_wake_all(futex: &AtomicU32) {
+    unsafe {
+        abi::futex_wake(futex.as_mut_ptr(), i32::MAX);
+    }
+}
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 60b7a973cc2..827d82900ea 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -25,6 +25,7 @@ pub mod cmath;
 pub mod env;
 pub mod fd;
 pub mod fs;
+pub mod futex;
 #[path = "../unsupported/io.rs"]
 pub mod io;
 pub mod memchr;
@@ -45,14 +46,14 @@ pub mod thread_local_dtor;
 pub mod thread_local_key;
 pub mod time;
 
-mod condvar;
-mod mutex;
-mod rwlock;
-
+#[path = "../unix/locks"]
 pub mod locks {
-    pub use super::condvar::*;
-    pub use super::mutex::*;
-    pub use super::rwlock::*;
+    mod futex_condvar;
+    mod futex_mutex;
+    mod futex_rwlock;
+    pub(crate) use futex_condvar::MovableCondvar;
+    pub(crate) use futex_mutex::{MovableMutex, Mutex};
+    pub(crate) use futex_rwlock::{MovableRwLock, RwLock};
 }
 
 use crate::io::ErrorKind;
@@ -98,7 +99,7 @@ pub extern "C" fn __rust_abort() {
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
+pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
     let _ = net::init();
     args::init(argc, argv);
 }
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
deleted file mode 100644
index eb15a04ffcf..00000000000
--- a/library/std/src/sys/hermit/mutex.rs
+++ /dev/null
@@ -1,216 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::collections::VecDeque;
-use crate::hint;
-use crate::ops::{Deref, DerefMut, Drop};
-use crate::ptr;
-use crate::sync::atomic::{AtomicUsize, Ordering};
-use crate::sys::hermit::abi;
-
-/// This type provides a lock based on busy waiting to realize mutual exclusion
-///
-/// # Description
-///
-/// This structure behaves a lot like a common mutex. There are some differences:
-///
-/// - By using busy waiting, it can be used outside the runtime.
-/// - It is a so called ticket lock and is completely fair.
-#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
-#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
-struct Spinlock<T: ?Sized> {
-    queue: AtomicUsize,
-    dequeue: AtomicUsize,
-    data: UnsafeCell<T>,
-}
-
-unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
-unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}
-
-/// A guard to which the protected data can be accessed
-///
-/// When the guard falls out of scope it will release the lock.
-struct SpinlockGuard<'a, T: ?Sized + 'a> {
-    dequeue: &'a AtomicUsize,
-    data: &'a mut T,
-}
-
-impl<T> Spinlock<T> {
-    pub const fn new(user_data: T) -> Spinlock<T> {
-        Spinlock {
-            queue: AtomicUsize::new(0),
-            dequeue: AtomicUsize::new(1),
-            data: UnsafeCell::new(user_data),
-        }
-    }
-
-    #[inline]
-    fn obtain_lock(&self) {
-        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
-        let mut counter: u16 = 0;
-        while self.dequeue.load(Ordering::SeqCst) != ticket {
-            counter += 1;
-            if counter < 100 {
-                hint::spin_loop();
-            } else {
-                counter = 0;
-                unsafe {
-                    abi::yield_now();
-                }
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
-        self.obtain_lock();
-        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
-    }
-}
-
-impl<T: ?Sized + Default> Default for Spinlock<T> {
-    fn default() -> Spinlock<T> {
-        Spinlock::new(Default::default())
-    }
-}
-
-impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
-    type Target = T;
-    fn deref(&self) -> &T {
-        &*self.data
-    }
-}
-
-impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
-    fn deref_mut(&mut self) -> &mut T {
-        &mut *self.data
-    }
-}
-
-impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
-    /// The dropping of the SpinlockGuard will release the lock it was created from.
-    fn drop(&mut self) {
-        self.dequeue.fetch_add(1, Ordering::SeqCst);
-    }
-}
-
-/// Realize a priority queue for tasks
-struct PriorityQueue {
-    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
-    prio_bitmap: u64,
-}
-
-impl PriorityQueue {
-    pub const fn new() -> PriorityQueue {
-        PriorityQueue {
-            queues: [
-                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
-                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
-                None, None, None,
-            ],
-            prio_bitmap: 0,
-        }
-    }
-
-    /// Add a task id by its priority to the queue
-    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
-        let i: usize = prio.into().into();
-        self.prio_bitmap |= (1 << i) as u64;
-        if let Some(queue) = &mut self.queues[i] {
-            queue.push_back(id);
-        } else {
-            let mut queue = VecDeque::new();
-            queue.push_back(id);
-            self.queues[i] = Some(queue);
-        }
-    }
-
-    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
-        if let Some(queue) = &mut self.queues[queue_index] {
-            let id = queue.pop_front();
-
-            if queue.is_empty() {
-                self.prio_bitmap &= !(1 << queue_index as u64);
-            }
-
-            id
-        } else {
-            None
-        }
-    }
-
-    /// Pop the task handle with the highest priority from the queue
-    pub fn pop(&mut self) -> Option<abi::Tid> {
-        for i in 0..abi::NO_PRIORITIES {
-            if self.prio_bitmap & (1 << i) != 0 {
-                return self.pop_from_queue(i);
-            }
-        }
-
-        None
-    }
-}
-
-struct MutexInner {
-    locked: bool,
-    blocked_task: PriorityQueue,
-}
-
-impl MutexInner {
-    pub const fn new() -> MutexInner {
-        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
-    }
-}
-
-pub struct Mutex {
-    inner: Spinlock<MutexInner>,
-}
-
-pub type MovableMutex = Mutex;
-
-unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {}
-
-impl Mutex {
-    pub const fn new() -> Mutex {
-        Mutex { inner: Spinlock::new(MutexInner::new()) }
-    }
-
-    #[inline]
-    pub unsafe fn init(&mut self) {}
-
-    #[inline]
-    pub unsafe fn lock(&self) {
-        loop {
-            let mut guard = self.inner.lock();
-            if guard.locked == false {
-                guard.locked = true;
-                return;
-            } else {
-                let prio = abi::get_priority();
-                let id = abi::getpid();
-
-                guard.blocked_task.push(prio, id);
-                abi::block_current_task();
-                drop(guard);
-                abi::yield_now();
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn unlock(&self) {
-        let mut guard = self.inner.lock();
-        guard.locked = false;
-        if let Some(tid) = guard.blocked_task.pop() {
-            abi::wakeup_task(tid);
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        let mut guard = self.inner.lock();
-        if guard.locked == false {
-            guard.locked = true;
-        }
-        guard.locked
-    }
-}
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs
index 74547617150..8a13879d8cc 100644
--- a/library/std/src/sys/hermit/net.rs
+++ b/library/std/src/sys/hermit/net.rs
@@ -487,6 +487,4 @@ pub mod netc {
 
     #[derive(Copy, Clone)]
     pub struct sockaddr {}
-
-    pub type socklen_t = usize;
 }
diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs
deleted file mode 100644
index 9701bab1f66..00000000000
--- a/library/std/src/sys/hermit/rwlock.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::sys::locks::{MovableCondvar, Mutex};
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-
-pub struct RwLock {
-    lock: Mutex,
-    cond: MovableCondvar,
-    state: UnsafeCell<State>,
-}
-
-pub type MovableRwLock = RwLock;
-
-enum State {
-    Unlocked,
-    Reading(usize),
-    Writing,
-}
-
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
-
-// This rwlock implementation is a relatively simple implementation which has a
-// condition variable for readers/writers as well as a mutex protecting the
-// internal state of the lock. A current downside of the implementation is that
-// unlocking the lock will notify *all* waiters rather than just readers or just
-// writers. This can cause lots of "thundering stampede" problems. While
-// hopefully correct this implementation is very likely to want to be changed in
-// the future.
-
-impl RwLock {
-    pub const fn new() -> RwLock {
-        RwLock {
-            lock: Mutex::new(),
-            cond: MovableCondvar::new(),
-            state: UnsafeCell::new(State::Unlocked),
-        }
-    }
-
-    #[inline]
-    pub unsafe fn read(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_readers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_readers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn write(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_writers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_writers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        self.lock.lock();
-        let notify = (*self.state.get()).dec_readers();
-        self.lock.unlock();
-        if notify {
-            // FIXME: should only wake up one of these some of the time
-            self.cond.notify_all();
-        }
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        self.lock.lock();
-        (*self.state.get()).dec_writers();
-        self.lock.unlock();
-        // FIXME: should only wake up one of these some of the time
-        self.cond.notify_all();
-    }
-}
-
-impl State {
-    fn inc_readers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Reading(1);
-                true
-            }
-            State::Reading(ref mut cnt) => {
-                *cnt += 1;
-                true
-            }
-            State::Writing => false,
-        }
-    }
-
-    fn inc_writers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Writing;
-                true
-            }
-            State::Reading(_) | State::Writing => false,
-        }
-    }
-
-    fn dec_readers(&mut self) -> bool {
-        let zero = match *self {
-            State::Reading(ref mut cnt) => {
-                *cnt -= 1;
-                *cnt == 0
-            }
-            State::Unlocked | State::Writing => invalid(),
-        };
-        if zero {
-            *self = State::Unlocked;
-        }
-        zero
-    }
-
-    fn dec_writers(&mut self) {
-        match *self {
-            State::Writing => {}
-            State::Unlocked | State::Reading(_) => invalid(),
-        }
-        *self = State::Unlocked;
-    }
-}
-
-fn invalid() -> ! {
-    panic!("inconsistent rwlock");
-}
diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs
index 715e94c3b3d..085662e6d44 100644
--- a/library/std/src/sys/itron/mutex.rs
+++ b/library/std/src/sys/itron/mutex.rs
@@ -31,12 +31,6 @@ impl Mutex {
         Mutex { mtx: SpinIdOnceCell::new() }
     }
 
-    pub unsafe fn init(&mut self) {
-        // Initialize `self.mtx` eagerly
-        let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx"));
-        unsafe { self.mtx.set_unchecked((id, ())) };
-    }
-
     /// Get the inner mutex's ID, which is lazily created.
     fn raw(&self) -> abi::ID {
         match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) {
diff --git a/library/std/src/sys/sgx/abi/thread.rs b/library/std/src/sys/sgx/abi/thread.rs
index ef55b821a2b..2b23e368cc3 100644
--- a/library/std/src/sys/sgx/abi/thread.rs
+++ b/library/std/src/sys/sgx/abi/thread.rs
@@ -7,7 +7,11 @@ use fortanix_sgx_abi::Tcs;
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn current() -> Tcs {
     extern "C" {
-        fn get_tcs_addr() -> Tcs;
+        fn get_tcs_addr() -> *mut u8;
+    }
+    let addr = unsafe { get_tcs_addr() };
+    match Tcs::new(addr) {
+        Some(tcs) => tcs,
+        None => rtabort!("TCS must not be placed at address zero (this is a linker error)"),
     }
-    unsafe { get_tcs_addr() }
 }
diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
index 5409bd1777c..0d934318c22 100644
--- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
@@ -316,9 +316,9 @@ where
 //   | small1 | Chunk smaller than 8 bytes
 //   +--------+
 fn region_as_aligned_chunks(ptr: *const u8, len: usize) -> (usize, usize, usize) {
-    let small0_size = if ptr as usize % 8 == 0 { 0 } else { 8 - ptr as usize % 8 };
-    let small1_size = (len - small0_size as usize) % 8;
-    let big_size = len - small0_size as usize - small1_size as usize;
+    let small0_size = if ptr.is_aligned_to(8) { 0 } else { 8 - ptr.addr() % 8 };
+    let small1_size = (len - small0_size) % 8;
+    let big_size = len - small0_size - small1_size;
 
     (small0_size, big_size, small1_size)
 }
@@ -364,8 +364,8 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize)
                     mfence
                     lfence
                     ",
-                    val = in(reg_byte) *src.offset(off as isize),
-                    dst = in(reg) dst.offset(off as isize),
+                    val = in(reg_byte) *src.add(off),
+                    dst = in(reg) dst.add(off),
                     seg_sel = in(reg) &mut seg_sel,
                     options(nostack, att_syntax)
                 );
@@ -378,8 +378,8 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize)
     assert!(is_enclave_range(src, len));
     assert!(is_user_range(dst, len));
     assert!(len < isize::MAX as usize);
-    assert!(!(src as usize).overflowing_add(len).1);
-    assert!(!(dst as usize).overflowing_add(len).1);
+    assert!(!src.addr().overflowing_add(len).1);
+    assert!(!dst.addr().overflowing_add(len).1);
 
     if len < 8 {
         // Can't align on 8 byte boundary: copy safely byte per byte
@@ -404,17 +404,17 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize)
 
         unsafe {
             // Copy small0
-            copy_bytewise_to_userspace(src, dst, small0_size as _);
+            copy_bytewise_to_userspace(src, dst, small0_size);
 
             // Copy big
-            let big_src = src.offset(small0_size as _);
-            let big_dst = dst.offset(small0_size as _);
-            copy_quadwords(big_src as _, big_dst, big_size);
+            let big_src = src.add(small0_size);
+            let big_dst = dst.add(small0_size);
+            copy_quadwords(big_src, big_dst, big_size);
 
             // Copy small1
-            let small1_src = src.offset(big_size as isize + small0_size as isize);
-            let small1_dst = dst.offset(big_size as isize + small0_size as isize);
-            copy_bytewise_to_userspace(small1_src, small1_dst, small1_size as _);
+            let small1_src = src.add(big_size + small0_size);
+            let small1_dst = dst.add(big_size + small0_size);
+            copy_bytewise_to_userspace(small1_src, small1_dst, small1_size);
         }
     }
 }
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index 696400670e0..b1d32929ecf 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -47,7 +47,7 @@ pub mod locks {
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
+pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
     unsafe {
         args::init(argc, argv);
     }
diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs
index 513cd77fd2a..aa747d56b0d 100644
--- a/library/std/src/sys/sgx/mutex.rs
+++ b/library/std/src/sys/sgx/mutex.rs
@@ -21,9 +21,6 @@ impl Mutex {
     }
 
     #[inline]
-    pub unsafe fn init(&mut self) {}
-
-    #[inline]
     pub unsafe fn lock(&self) {
         let mut guard = self.inner.lock();
         if *guard.lock_var() {
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 778a589d1b7..5867979a2a7 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -56,7 +56,7 @@ pub mod locks {
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
 
 // SAFETY: must be called only once during runtime cleanup.
 pub unsafe fn cleanup() {}
diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs
index b5649d6e0ff..eecb347e599 100644
--- a/library/std/src/sys/solid/os.rs
+++ b/library/std/src/sys/solid/os.rs
@@ -8,7 +8,7 @@ use crate::os::{
     solid::ffi::{OsStrExt, OsStringExt},
 };
 use crate::path::{self, PathBuf};
-use crate::sys_common::rwlock::StaticRwLock;
+use crate::sync::RwLock;
 use crate::vec;
 
 use super::{error, itron, memchr};
@@ -78,7 +78,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
 }
 
-static ENV_LOCK: StaticRwLock = StaticRwLock::new();
+static ENV_LOCK: RwLock<()> = RwLock::new(());
 
 pub struct Env {
     iter: vec::IntoIter<(OsString, OsString)>,
diff --git a/library/std/src/sys/unix/locks/fuchsia_mutex.rs b/library/std/src/sys/unix/locks/fuchsia_mutex.rs
index ce427599c3b..117611ce43f 100644
--- a/library/std/src/sys/unix/locks/fuchsia_mutex.rs
+++ b/library/std/src/sys/unix/locks/fuchsia_mutex.rs
@@ -86,9 +86,6 @@ impl Mutex {
     }
 
     #[inline]
-    pub unsafe fn init(&mut self) {}
-
-    #[inline]
     pub unsafe fn try_lock(&self) -> bool {
         let thread_self = zx_thread_self();
         self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed).is_ok()
@@ -138,7 +135,7 @@ impl Mutex {
                 }
             }
 
-            // The state has changed or a wakeup occured, try to lock the mutex.
+            // The state has changed or a wakeup occurred, try to lock the mutex.
             match self.futex.compare_exchange(UNLOCKED, owned_state, Acquire, Relaxed) {
                 Ok(_) => return,
                 Err(updated) => state = updated,
diff --git a/library/std/src/sys/unix/locks/futex_mutex.rs b/library/std/src/sys/unix/locks/futex_mutex.rs
index 99ba86e5f99..33b13dad4d6 100644
--- a/library/std/src/sys/unix/locks/futex_mutex.rs
+++ b/library/std/src/sys/unix/locks/futex_mutex.rs
@@ -20,9 +20,6 @@ impl Mutex {
     }
 
     #[inline]
-    pub unsafe fn init(&mut self) {}
-
-    #[inline]
     pub unsafe fn try_lock(&self) -> bool {
         self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok()
     }
@@ -53,7 +50,7 @@ impl Mutex {
             // We avoid an unnecessary write if it as already set to 2,
             // to be friendlier for the caches.
             if state != 2 && self.futex.swap(2, Acquire) == 0 {
-                // We changed it from 0 to 2, so we just succesfully locked it.
+                // We changed it from 0 to 2, so we just successfully locked it.
                 return;
             }
 
diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs
index b3bbbf743f8..0cc92244eca 100644
--- a/library/std/src/sys/unix/locks/futex_rwlock.rs
+++ b/library/std/src/sys/unix/locks/futex_rwlock.rs
@@ -54,7 +54,7 @@ fn is_read_lockable(state: u32) -> bool {
     // We don't allow read-locking if there's readers waiting, even if the lock is unlocked
     // and there's no writers waiting. The only situation when this happens is after unlocking,
     // at which point the unlocking thread might be waking up writers, which have priority over readers.
-    // The unlocking thread will clear the readers waiting bit and wake up readers, if necssary.
+    // The unlocking thread will clear the readers waiting bit and wake up readers, if necessary.
     state & MASK < MAX_READERS && !has_readers_waiting(state) && !has_writers_waiting(state)
 }
 
diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs
index f5f92f69358..9bb314b7010 100644
--- a/library/std/src/sys/unix/locks/mod.rs
+++ b/library/std/src/sys/unix/locks/mod.rs
@@ -11,21 +11,21 @@ cfg_if::cfg_if! {
         mod futex_rwlock;
         mod futex_condvar;
         pub(crate) use futex_mutex::{Mutex, MovableMutex};
-        pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
+        pub(crate) use futex_rwlock::MovableRwLock;
         pub(crate) use futex_condvar::MovableCondvar;
     } else if #[cfg(target_os = "fuchsia")] {
         mod fuchsia_mutex;
         mod futex_rwlock;
         mod futex_condvar;
         pub(crate) use fuchsia_mutex::{Mutex, MovableMutex};
-        pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
+        pub(crate) use futex_rwlock::MovableRwLock;
         pub(crate) use futex_condvar::MovableCondvar;
     } else {
         mod pthread_mutex;
         mod pthread_rwlock;
         mod pthread_condvar;
         pub(crate) use pthread_mutex::{Mutex, MovableMutex};
-        pub(crate) use pthread_rwlock::{RwLock, MovableRwLock};
+        pub(crate) use pthread_rwlock::MovableRwLock;
         pub(crate) use pthread_condvar::MovableCondvar;
     }
 }
diff --git a/library/std/src/sys/unix/locks/pthread_mutex.rs b/library/std/src/sys/unix/locks/pthread_mutex.rs
index 98afee69ba6..5964935ddb5 100644
--- a/library/std/src/sys/unix/locks/pthread_mutex.rs
+++ b/library/std/src/sys/unix/locks/pthread_mutex.rs
@@ -52,7 +52,7 @@ impl Mutex {
         Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
     }
     #[inline]
-    pub unsafe fn init(&mut self) {
+    unsafe fn init(&mut self) {
         // Issue #33770
         //
         // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 3a375093099..c84e292eac1 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -44,12 +44,13 @@ pub mod thread_parker;
 pub mod time;
 
 #[cfg(target_os = "espidf")]
-pub fn init(argc: isize, argv: *const *const u8) {}
+pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {}
 
 #[cfg(not(target_os = "espidf"))]
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
+// See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`.
+pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     // The standard streams might be closed on application startup. To prevent
     // std::io::{stdin, stdout,stderr} objects from using other unrelated file
     // resources opened later, we reopen standards streams when they are closed.
@@ -61,8 +62,9 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
     // want!
     //
     // Hence, we set SIGPIPE to ignore when the program starts up in order
-    // to prevent this problem.
-    reset_sigpipe();
+    // to prevent this problem. Add `#[unix_sigpipe = "..."]` above `fn main()` to
+    // alter this behavior.
+    reset_sigpipe(sigpipe);
 
     stack_overflow::init();
     args::init(argc, argv);
@@ -151,9 +153,31 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
         }
     }
 
-    unsafe fn reset_sigpipe() {
+    unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
         #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
-        rtassert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
+        {
+            // We don't want to add this as a public type to libstd, nor do we
+            // want to `include!` a file from the compiler (which would break
+            // Miri and xargo for example), so we choose to duplicate these
+            // constants from `compiler/rustc_session/src/config/sigpipe.rs`.
+            // See the other file for docs. NOTE: Make sure to keep them in
+            // sync!
+            mod sigpipe {
+                pub const INHERIT: u8 = 1;
+                pub const SIG_IGN: u8 = 2;
+                pub const SIG_DFL: u8 = 3;
+            }
+
+            let handler = match sigpipe {
+                sigpipe::INHERIT => None,
+                sigpipe::SIG_IGN => Some(libc::SIG_IGN),
+                sigpipe::SIG_DFL => Some(libc::SIG_DFL),
+                _ => unreachable!(),
+            };
+            if let Some(handler) = handler {
+                rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
+            }
+        }
     }
 }
 
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 46545a0839f..7c70ddbd9b9 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -17,10 +17,10 @@ use crate::path::{self, PathBuf};
 use crate::ptr;
 use crate::slice;
 use crate::str;
+use crate::sync::{PoisonError, RwLock};
 use crate::sys::cvt;
 use crate::sys::fd;
 use crate::sys::memchr;
-use crate::sys_common::rwlock::{StaticRwLock, StaticRwLockReadGuard};
 use crate::vec;
 
 #[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
@@ -125,7 +125,9 @@ pub fn error_string(errno: i32) -> String {
         }
 
         let p = p as *const _;
-        str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
+        // We can't always expect a UTF-8 environment. When we don't get that luxury,
+        // it's better to give a low-quality error message than none at all.
+        String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into()
     }
 }
 
@@ -501,10 +503,10 @@ pub unsafe fn environ() -> *mut *const *const c_char {
     ptr::addr_of_mut!(environ)
 }
 
-static ENV_LOCK: StaticRwLock = StaticRwLock::new();
+static ENV_LOCK: RwLock<()> = RwLock::new(());
 
-pub fn env_read_lock() -> StaticRwLockReadGuard {
-    ENV_LOCK.read()
+pub fn env_read_lock() -> impl Drop {
+    ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner)
 }
 
 /// Returns a vector of (variable, value) byte-vector pairs for all the
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 26ae6281771..2ff8e600f7c 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -822,14 +822,14 @@ impl crate::os::linux::process::ChildExt for crate::process::Child {
         self.handle
             .pidfd
             .as_ref()
-            .ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created."))
+            .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created."))
     }
 
     fn take_pidfd(&mut self) -> io::Result<PidFd> {
         self.handle
             .pidfd
             .take()
-            .ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created."))
+            .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created."))
     }
 }
 
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 7db3065dee0..56bb71b5dcb 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -429,7 +429,7 @@ mod cgroups {
                         Some(b"") => Cgroup::V2,
                         Some(controllers)
                             if from_utf8(controllers)
-                                .is_ok_and(|c| c.split(",").any(|c| c == "cpu")) =>
+                                .is_ok_and(|c| c.split(',').any(|c| c == "cpu")) =>
                         {
                             Cgroup::V1
                         }
diff --git a/library/std/src/sys/unix/thread_parker/mod.rs b/library/std/src/sys/unix/thread_parker/mod.rs
new file mode 100644
index 00000000000..e2453580dc7
--- /dev/null
+++ b/library/std/src/sys/unix/thread_parker/mod.rs
@@ -0,0 +1,21 @@
+//! Thread parking on systems without futex support.
+
+#![cfg(not(any(
+    target_os = "linux",
+    target_os = "android",
+    all(target_os = "emscripten", target_feature = "atomics"),
+    target_os = "freebsd",
+    target_os = "openbsd",
+    target_os = "dragonfly",
+    target_os = "fuchsia",
+)))]
+
+cfg_if::cfg_if! {
+    if #[cfg(target_os = "netbsd")] {
+        mod netbsd;
+        pub use netbsd::Parker;
+    } else {
+        mod pthread;
+        pub use pthread::Parker;
+    }
+}
diff --git a/library/std/src/sys/unix/thread_parker/netbsd.rs b/library/std/src/sys/unix/thread_parker/netbsd.rs
new file mode 100644
index 00000000000..7657605b52f
--- /dev/null
+++ b/library/std/src/sys/unix/thread_parker/netbsd.rs
@@ -0,0 +1,113 @@
+use crate::ffi::{c_int, c_void};
+use crate::pin::Pin;
+use crate::ptr::{null, null_mut};
+use crate::sync::atomic::{
+    AtomicU64,
+    Ordering::{Acquire, Relaxed, Release},
+};
+use crate::time::Duration;
+use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC};
+
+extern "C" {
+    fn ___lwp_park60(
+        clock_id: clockid_t,
+        flags: c_int,
+        ts: *mut timespec,
+        unpark: lwpid_t,
+        hint: *const c_void,
+        unparkhint: *const c_void,
+    ) -> c_int;
+    fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int;
+}
+
+/// The thread is not parked and the token is not available.
+///
+/// Zero cannot be a valid LWP id, since it is used as empty value for the unpark
+/// argument in _lwp_park.
+const EMPTY: u64 = 0;
+/// The token is available. Do not park anymore.
+const NOTIFIED: u64 = u64::MAX;
+
+pub struct Parker {
+    /// The parker state. Contains either one of the two state values above or the LWP
+    /// id of the parked thread.
+    state: AtomicU64,
+}
+
+impl Parker {
+    pub unsafe fn new(parker: *mut Parker) {
+        parker.write(Parker { state: AtomicU64::new(EMPTY) })
+    }
+
+    // Does not actually need `unsafe` or `Pin`, but the pthread implementation does.
+    pub unsafe fn park(self: Pin<&Self>) {
+        // If the token has already been made available, we can skip
+        // a bit of work, so check for it here.
+        if self.state.load(Acquire) != NOTIFIED {
+            let parked = _lwp_self() as u64;
+            let hint = self.state.as_mut_ptr().cast();
+            if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() {
+                // Loop to guard against spurious wakeups.
+                loop {
+                    ___lwp_park60(0, 0, null_mut(), 0, hint, null());
+                    if self.state.load(Acquire) == NOTIFIED {
+                        break;
+                    }
+                }
+            }
+        }
+
+        // At this point, the change to NOTIFIED has always been observed with acquire
+        // ordering, so we can just use a relaxed store here (instead of a swap).
+        self.state.store(EMPTY, Relaxed);
+    }
+
+    // Does not actually need `unsafe` or `Pin`, but the pthread implementation does.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        if self.state.load(Acquire) != NOTIFIED {
+            let parked = _lwp_self() as u64;
+            let hint = self.state.as_mut_ptr().cast();
+            let mut timeout = timespec {
+                // Saturate so that the operation will definitely time out
+                // (even if it is after the heat death of the universe).
+                tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX),
+                tv_nsec: dur.subsec_nanos().into(),
+            };
+
+            if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() {
+                // Timeout needs to be mutable since it is modified on NetBSD 9.0 and
+                // above.
+                ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, hint, null());
+                // Use a swap to get acquire ordering even if the token was set after
+                // the timeout occurred.
+                self.state.swap(EMPTY, Acquire);
+                return;
+            }
+        }
+
+        self.state.store(EMPTY, Relaxed);
+    }
+
+    // Does not actually need `Pin`, but the pthread implementation does.
+    pub fn unpark(self: Pin<&Self>) {
+        let state = self.state.swap(NOTIFIED, Release);
+        if !matches!(state, EMPTY | NOTIFIED) {
+            let lwp = state as lwpid_t;
+            let hint = self.state.as_mut_ptr().cast();
+
+            // If the parking thread terminated and did not actually park, this will
+            // probably return an error, which is OK. In the worst case, another
+            // thread has received the same LWP id. It will then receive a spurious
+            // wakeup, but those are allowable per the API contract. The same reasoning
+            // applies if a timeout occurred before this call, but the state was not
+            // yet reset.
+
+            // SAFETY:
+            // The syscall has no invariants to hold. Only unsafe because it is an
+            // extern function.
+            unsafe {
+                _lwp_unpark(lwp, hint);
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/unix/thread_parker.rs b/library/std/src/sys/unix/thread_parker/pthread.rs
index ca1a7138fde..3dfc0026ed1 100644
--- a/library/std/src/sys/unix/thread_parker.rs
+++ b/library/std/src/sys/unix/thread_parker/pthread.rs
@@ -1,15 +1,5 @@
 //! Thread parking without `futex` using the `pthread` synchronization primitives.
 
-#![cfg(not(any(
-    target_os = "linux",
-    target_os = "android",
-    all(target_os = "emscripten", target_feature = "atomics"),
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "dragonfly",
-    target_os = "fuchsia",
-)))]
-
 use crate::cell::UnsafeCell;
 use crate::marker::PhantomPinned;
 use crate::pin::Pin;
@@ -59,8 +49,8 @@ unsafe fn wait_timeout(
         target_os = "espidf"
     ))]
     let (now, dur) = {
-        use super::time::SystemTime;
         use crate::cmp::min;
+        use crate::sys::time::SystemTime;
 
         // OSX implementation of `pthread_cond_timedwait` is buggy
         // with super long durations. When duration is greater than
@@ -85,7 +75,7 @@ unsafe fn wait_timeout(
         target_os = "espidf"
     )))]
     let (now, dur) = {
-        use super::time::Timespec;
+        use crate::sys::time::Timespec;
 
         (Timespec::now(libc::CLOCK_MONOTONIC), dur)
     };
diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs
index 4c9ade4a8c7..5cd9e57de19 100644
--- a/library/std/src/sys/unsupported/common.rs
+++ b/library/std/src/sys/unsupported/common.rs
@@ -6,7 +6,7 @@ pub mod memchr {
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
 
 // SAFETY: must be called only once during runtime cleanup.
 // NOTE: this is not guaranteed to run, for example when the program aborts.
diff --git a/library/std/src/sys/unsupported/locks/condvar.rs b/library/std/src/sys/unsupported/locks/condvar.rs
index e703fd0d269..527a26a12bc 100644
--- a/library/std/src/sys/unsupported/locks/condvar.rs
+++ b/library/std/src/sys/unsupported/locks/condvar.rs
@@ -7,6 +7,7 @@ pub type MovableCondvar = Condvar;
 
 impl Condvar {
     #[inline]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Condvar {
         Condvar {}
     }
diff --git a/library/std/src/sys/unsupported/locks/mod.rs b/library/std/src/sys/unsupported/locks/mod.rs
index d412ff152a0..602a2d6231a 100644
--- a/library/std/src/sys/unsupported/locks/mod.rs
+++ b/library/std/src/sys/unsupported/locks/mod.rs
@@ -3,4 +3,4 @@ mod mutex;
 mod rwlock;
 pub use condvar::{Condvar, MovableCondvar};
 pub use mutex::{MovableMutex, Mutex};
-pub use rwlock::{MovableRwLock, RwLock};
+pub use rwlock::MovableRwLock;
diff --git a/library/std/src/sys/unsupported/locks/mutex.rs b/library/std/src/sys/unsupported/locks/mutex.rs
index d7cb12e0cf9..87ea475c6e3 100644
--- a/library/std/src/sys/unsupported/locks/mutex.rs
+++ b/library/std/src/sys/unsupported/locks/mutex.rs
@@ -12,14 +12,12 @@ unsafe impl Sync for Mutex {} // no threads on this platform
 
 impl Mutex {
     #[inline]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Mutex {
         Mutex { locked: Cell::new(false) }
     }
 
     #[inline]
-    pub unsafe fn init(&mut self) {}
-
-    #[inline]
     pub unsafe fn lock(&self) {
         assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex");
     }
diff --git a/library/std/src/sys/unsupported/locks/rwlock.rs b/library/std/src/sys/unsupported/locks/rwlock.rs
index aca5fb7152c..5292691b955 100644
--- a/library/std/src/sys/unsupported/locks/rwlock.rs
+++ b/library/std/src/sys/unsupported/locks/rwlock.rs
@@ -12,6 +12,7 @@ unsafe impl Sync for RwLock {} // no threads on this platform
 
 impl RwLock {
     #[inline]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> RwLock {
         RwLock { mode: Cell::new(0) }
     }
diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs
index 4159efe2a05..93838390bee 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -57,7 +57,7 @@ cfg_if::cfg_if! {
             mod futex_rwlock;
             pub(crate) use futex_condvar::{Condvar, MovableCondvar};
             pub(crate) use futex_mutex::{Mutex, MovableMutex};
-            pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
+            pub(crate) use futex_rwlock::MovableRwLock;
         }
         #[path = "atomics/futex.rs"]
         pub mod futex;
diff --git a/library/std/src/sys/windows/alloc.rs b/library/std/src/sys/windows/alloc.rs
index fe00c08aa6a..d53ea16005f 100644
--- a/library/std/src/sys/windows/alloc.rs
+++ b/library/std/src/sys/windows/alloc.rs
@@ -16,6 +16,7 @@ mod tests;
 // Flag to indicate that the memory returned by `HeapAlloc` should be zeroed.
 const HEAP_ZERO_MEMORY: c::DWORD = 0x00000008;
 
+#[link(name = "kernel32")]
 extern "system" {
     // Get a handle to the default heap of the current process, or null if the operation fails.
     //
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index c99c8efe436..c61a7e7d1e4 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -66,6 +66,7 @@ pub type LPSYSTEM_INFO = *mut SYSTEM_INFO;
 pub type LPWSABUF = *mut WSABUF;
 pub type LPWSAOVERLAPPED = *mut c_void;
 pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void;
+pub type BCRYPT_ALG_HANDLE = LPVOID;
 
 pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
 pub type PLARGE_INTEGER = *mut c_longlong;
@@ -285,6 +286,8 @@ pub fn nt_success(status: NTSTATUS) -> bool {
     status >= 0
 }
 
+// "RNG\0"
+pub const BCRYPT_RNG_ALGORITHM: &[u16] = &[b'R' as u16, b'N' as u16, b'G' as u16, 0];
 pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002;
 
 #[repr(C)]
@@ -455,6 +458,12 @@ pub enum FILE_INFO_BY_HANDLE_CLASS {
 }
 
 #[repr(C)]
+pub struct FILE_ATTRIBUTE_TAG_INFO {
+    pub FileAttributes: DWORD,
+    pub ReparseTag: DWORD,
+}
+
+#[repr(C)]
 pub struct FILE_DISPOSITION_INFO {
     pub DeleteFile: BOOLEAN,
 }
@@ -808,10 +817,6 @@ if #[cfg(not(target_vendor = "uwp"))] {
 
     #[link(name = "advapi32")]
     extern "system" {
-        // Forbidden when targeting UWP
-        #[link_name = "SystemFunction036"]
-        pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
-
         // Allowed but unused by UWP
         pub fn OpenProcessToken(
             ProcessHandle: HANDLE,
@@ -1223,11 +1228,18 @@ extern "system" {
     // >= Vista / Server 2008
     // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
     pub fn BCryptGenRandom(
-        hAlgorithm: LPVOID,
+        hAlgorithm: BCRYPT_ALG_HANDLE,
         pBuffer: *mut u8,
         cbBuffer: ULONG,
         dwFlags: ULONG,
     ) -> NTSTATUS;
+    pub fn BCryptOpenAlgorithmProvider(
+        phalgorithm: *mut BCRYPT_ALG_HANDLE,
+        pszAlgId: LPCWSTR,
+        pszimplementation: LPCWSTR,
+        dwflags: ULONG,
+    ) -> NTSTATUS;
+    pub fn BCryptCloseAlgorithmProvider(hAlgorithm: BCRYPT_ALG_HANDLE, dwFlags: ULONG) -> NTSTATUS;
 }
 
 // Functions that aren't available on every version of Windows that we support,
diff --git a/library/std/src/sys/windows/cmath.rs b/library/std/src/sys/windows/cmath.rs
index 1a5421facd0..43ab8c7ee65 100644
--- a/library/std/src/sys/windows/cmath.rs
+++ b/library/std/src/sys/windows/cmath.rs
@@ -44,7 +44,7 @@ mod shims {
 }
 
 // On 32-bit x86 MSVC these functions aren't defined, so we just define shims
-// which promote everything fo f64, perform the calculation, and then demote
+// which promote everything to f64, perform the calculation, and then demote
 // back to f32. While not precisely correct should be "correct enough" for now.
 #[cfg(all(target_env = "msvc", target_arch = "x86"))]
 mod shims {
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index 0aa7c50ded1..155d0297e49 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -3,7 +3,7 @@ use crate::os::windows::prelude::*;
 use crate::ffi::OsString;
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
-use crate::mem;
+use crate::mem::{self, MaybeUninit};
 use crate::os::windows::io::{AsHandle, BorrowedHandle};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
@@ -326,9 +326,15 @@ impl File {
             cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?;
             let mut reparse_tag = 0;
             if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-                let mut b = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
-                if let Ok((_, buf)) = self.reparse_point(&mut b) {
-                    reparse_tag = (*buf).ReparseTag;
+                let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
+                cvt(c::GetFileInformationByHandleEx(
+                    self.handle.as_raw_handle(),
+                    c::FileAttributeTagInfo,
+                    ptr::addr_of_mut!(attr_tag).cast(),
+                    mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
+                ))?;
+                if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+                    reparse_tag = attr_tag.ReparseTag;
                 }
             }
             Ok(FileAttr {
@@ -389,9 +395,15 @@ impl File {
             attr.file_size = info.AllocationSize as u64;
             attr.number_of_links = Some(info.NumberOfLinks);
             if attr.file_type().is_reparse_point() {
-                let mut b = Align8([0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
-                if let Ok((_, buf)) = self.reparse_point(&mut b) {
-                    attr.reparse_tag = (*buf).ReparseTag;
+                let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
+                cvt(c::GetFileInformationByHandleEx(
+                    self.handle.as_raw_handle(),
+                    c::FileAttributeTagInfo,
+                    ptr::addr_of_mut!(attr_tag).cast(),
+                    mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
+                ))?;
+                if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+                    attr.reparse_tag = attr_tag.ReparseTag;
                 }
             }
             Ok(attr)
@@ -463,7 +475,7 @@ impl File {
     // avoid narrowing provenance to the actual `REPARSE_DATA_BUFFER`.
     fn reparse_point(
         &self,
-        space: &mut Align8<[u8]>,
+        space: &mut Align8<[MaybeUninit<u8>]>,
     ) -> io::Result<(c::DWORD, *const c::REPARSE_DATA_BUFFER)> {
         unsafe {
             let mut bytes = 0;
@@ -488,7 +500,7 @@ impl File {
     }
 
     fn readlink(&self) -> io::Result<PathBuf> {
-        let mut space = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
+        let mut space = Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
         let (_bytes, buf) = self.reparse_point(&mut space)?;
         unsafe {
             let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag {
@@ -658,12 +670,16 @@ impl File {
 
 /// A buffer for holding directory entries.
 struct DirBuff {
-    buffer: Box<Align8<[u8; Self::BUFFER_SIZE]>>,
+    buffer: Box<Align8<[MaybeUninit<u8>; Self::BUFFER_SIZE]>>,
 }
 impl DirBuff {
     const BUFFER_SIZE: usize = 1024;
     fn new() -> Self {
-        Self { buffer: Box::new(Align8([0u8; Self::BUFFER_SIZE])) }
+        Self {
+            // Safety: `Align8<[MaybeUninit<u8>; N]>` does not need
+            // initialization.
+            buffer: unsafe { Box::new_uninit().assume_init() },
+        }
     }
     fn capacity(&self) -> usize {
         self.buffer.0.len()
@@ -676,8 +692,8 @@ impl DirBuff {
         DirBuffIter::new(self)
     }
 }
-impl AsRef<[u8]> for DirBuff {
-    fn as_ref(&self) -> &[u8] {
+impl AsRef<[MaybeUninit<u8>]> for DirBuff {
+    fn as_ref(&self) -> &[MaybeUninit<u8>] {
         &self.buffer.0
     }
 }
@@ -686,7 +702,7 @@ impl AsRef<[u8]> for DirBuff {
 ///
 /// Currently only returns file names (UTF-16 encoded).
 struct DirBuffIter<'a> {
-    buffer: Option<&'a [u8]>,
+    buffer: Option<&'a [MaybeUninit<u8>]>,
     cursor: usize,
 }
 impl<'a> DirBuffIter<'a> {
@@ -701,9 +717,13 @@ impl<'a> Iterator for DirBuffIter<'a> {
         let buffer = &self.buffer?[self.cursor..];
 
         // Get the name and next entry from the buffer.
-        // SAFETY: The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the
-        // last field (the file name) is unsized. So an offset has to be
-        // used to get the file name slice.
+        // SAFETY:
+        // - The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the last
+        //   field (the file name) is unsized. So an offset has to be used to
+        //   get the file name slice.
+        // - The OS has guaranteed initialization of the fields of
+        //   `FILE_ID_BOTH_DIR_INFO` and the trailing filename (for at least
+        //   `FileNameLength` bytes)
         let (name, is_directory, next_entry) = unsafe {
             let info = buffer.as_ptr().cast::<c::FILE_ID_BOTH_DIR_INFO>();
             // Guaranteed to be aligned in documentation for
@@ -1349,7 +1369,7 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
     let h = f.as_inner().as_raw_handle();
 
     unsafe {
-        let mut data = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
+        let mut data = Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
         let data_ptr = data.0.as_mut_ptr();
         let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
         let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
diff --git a/library/std/src/sys/windows/locks/mod.rs b/library/std/src/sys/windows/locks/mod.rs
index d412ff152a0..602a2d6231a 100644
--- a/library/std/src/sys/windows/locks/mod.rs
+++ b/library/std/src/sys/windows/locks/mod.rs
@@ -3,4 +3,4 @@ mod mutex;
 mod rwlock;
 pub use condvar::{Condvar, MovableCondvar};
 pub use mutex::{MovableMutex, Mutex};
-pub use rwlock::{MovableRwLock, RwLock};
+pub use rwlock::MovableRwLock;
diff --git a/library/std/src/sys/windows/locks/mutex.rs b/library/std/src/sys/windows/locks/mutex.rs
index f91e8f9f59a..91207f5f466 100644
--- a/library/std/src/sys/windows/locks/mutex.rs
+++ b/library/std/src/sys/windows/locks/mutex.rs
@@ -37,8 +37,6 @@ impl Mutex {
     pub const fn new() -> Mutex {
         Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) }
     }
-    #[inline]
-    pub unsafe fn init(&mut self) {}
 
     #[inline]
     pub unsafe fn lock(&self) {
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 340cae4066b..eab9b961279 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -48,7 +48,7 @@ cfg_if::cfg_if! {
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
     stack_overflow::init();
 
     // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index a0f82207099..beeca1917a9 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -198,14 +198,7 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
 
     match path.bytes().iter().position(|&x| separator(x)) {
         Some(separator_start) => {
-            let mut separator_end = separator_start + 1;
-
-            // a series of multiple separator characters is treated as a single separator,
-            // except in verbatim paths
-            while !verbatim && separator_end < path.len() && separator(path.bytes()[separator_end])
-            {
-                separator_end += 1;
-            }
+            let separator_end = separator_start + 1;
 
             let component = &path.bytes()[..separator_start];
 
diff --git a/library/std/src/sys/windows/path/tests.rs b/library/std/src/sys/windows/path/tests.rs
index 2f7ec433bf2..623c6236166 100644
--- a/library/std/src/sys/windows/path/tests.rs
+++ b/library/std/src/sys/windows/path/tests.rs
@@ -31,16 +31,6 @@ fn test_parse_next_component() {
         parse_next_component(OsStr::new(r"servershare"), false),
         (OsStr::new(r"servershare"), OsStr::new(""))
     );
-
-    assert_eq!(
-        parse_next_component(OsStr::new(r"server/\//\/\\\\/////\/share"), false),
-        (OsStr::new(r"server"), OsStr::new(r"share"))
-    );
-
-    assert_eq!(
-        parse_next_component(OsStr::new(r"server\\\\\\\\\\\\\\share"), true),
-        (OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share"))
-    );
 }
 
 #[test]
@@ -115,7 +105,7 @@ fn test_parse_prefix_verbatim_device() {
     assert_eq!(prefix, parse_prefix(r"\\?/C:\windows\system32\notepad.exe"));
 }
 
-// See #93586 for more infomation.
+// See #93586 for more information.
 #[test]
 fn test_windows_prefix_components() {
     use crate::path::Path;
@@ -126,3 +116,22 @@ fn test_windows_prefix_components() {
     assert_eq!(drive.as_os_str(), OsStr::new("C:"));
     assert_eq!(components.as_path(), Path::new(""));
 }
+
+/// See #101358.
+///
+/// Note that the exact behaviour here may change in the future.
+/// In which case this test will need to adjusted.
+#[test]
+fn broken_unc_path() {
+    use crate::path::Component;
+
+    let mut components = Path::new(r"\\foo\\bar\\").components();
+    assert_eq!(components.next(), Some(Component::RootDir));
+    assert_eq!(components.next(), Some(Component::Normal("foo".as_ref())));
+    assert_eq!(components.next(), Some(Component::Normal("bar".as_ref())));
+
+    let mut components = Path::new("//foo//bar//").components();
+    assert_eq!(components.next(), Some(Component::RootDir));
+    assert_eq!(components.next(), Some(Component::Normal("foo".as_ref())));
+    assert_eq!(components.next(), Some(Component::Normal("bar".as_ref())));
+}
diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs
index f8fd93a7398..b5a49489d3f 100644
--- a/library/std/src/sys/windows/rand.rs
+++ b/library/std/src/sys/windows/rand.rs
@@ -1,35 +1,106 @@
-use crate::io;
+//! # Random key generation
+//!
+//! This module wraps the RNG provided by the OS. There are a few different
+//! ways to interface with the OS RNG so it's worth exploring each of the options.
+//! Note that at the time of writing these all go through the (undocumented)
+//! `bcryptPrimitives.dll` but they use different route to get there.
+//!
+//! Originally we were using [`RtlGenRandom`], however that function is
+//! deprecated and warns it "may be altered or unavailable in subsequent versions".
+//!
+//! So we switched to [`BCryptGenRandom`] with the `BCRYPT_USE_SYSTEM_PREFERRED_RNG`
+//! flag to query and find the system configured RNG. However, this change caused a small
+//! but significant number of users to experience panics caused by a failure of
+//! this function. See [#94098].
+//!
+//! The current version falls back to using `BCryptOpenAlgorithmProvider` if
+//! `BCRYPT_USE_SYSTEM_PREFERRED_RNG` fails for any reason.
+//!
+//! [#94098]: https://github.com/rust-lang/rust/issues/94098
+//! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
+//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
 use crate::mem;
 use crate::ptr;
 use crate::sys::c;
 
+/// Generates high quality secure random keys for use by [`HashMap`].
+///
+/// This is used to seed the default [`RandomState`].
+///
+/// [`HashMap`]: crate::collections::HashMap
+/// [`RandomState`]: crate::collections::hash_map::RandomState
 pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut v = (0, 0);
-    let ret = unsafe {
-        c::BCryptGenRandom(
-            ptr::null_mut(),
-            &mut v as *mut _ as *mut u8,
-            mem::size_of_val(&v) as c::ULONG,
-            c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
-        )
-    };
-    if ret != 0 { fallback_rng() } else { v }
+    Rng::SYSTEM.gen_random_keys().unwrap_or_else(fallback_rng)
 }
 
-/// Generate random numbers using the fallback RNG function (RtlGenRandom)
-#[cfg(not(target_vendor = "uwp"))]
-#[inline(never)]
-fn fallback_rng() -> (u64, u64) {
-    let mut v = (0, 0);
-    let ret =
-        unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };
+struct Rng {
+    algorithm: c::BCRYPT_ALG_HANDLE,
+    flags: u32,
+}
+impl Rng {
+    const SYSTEM: Self = unsafe { Self::new(ptr::null_mut(), c::BCRYPT_USE_SYSTEM_PREFERRED_RNG) };
+
+    /// Create the RNG from an existing algorithm handle.
+    ///
+    /// # Safety
+    ///
+    /// The handle must either be null or a valid algorithm handle.
+    const unsafe fn new(algorithm: c::BCRYPT_ALG_HANDLE, flags: u32) -> Self {
+        Self { algorithm, flags }
+    }
+
+    /// Open a handle to the RNG algorithm.
+    fn open() -> Result<Self, c::NTSTATUS> {
+        use crate::sync::atomic::AtomicPtr;
+        use crate::sync::atomic::Ordering::{Acquire, Release};
+
+        // An atomic is used so we don't need to reopen the handle every time.
+        static HANDLE: AtomicPtr<crate::ffi::c_void> = AtomicPtr::new(ptr::null_mut());
+
+        let mut handle = HANDLE.load(Acquire);
+        if handle.is_null() {
+            let status = unsafe {
+                c::BCryptOpenAlgorithmProvider(
+                    &mut handle,
+                    c::BCRYPT_RNG_ALGORITHM.as_ptr(),
+                    ptr::null(),
+                    0,
+                )
+            };
+            if c::nt_success(status) {
+                // If another thread opens a handle first then use that handle instead.
+                let result = HANDLE.compare_exchange(ptr::null_mut(), handle, Release, Acquire);
+                if let Err(previous_handle) = result {
+                    // Close our handle and return the previous one.
+                    unsafe { c::BCryptCloseAlgorithmProvider(handle, 0) };
+                    handle = previous_handle;
+                }
+                Ok(unsafe { Self::new(handle, 0) })
+            } else {
+                Err(status)
+            }
+        } else {
+            Ok(unsafe { Self::new(handle, 0) })
+        }
+    }
 
-    if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) }
+    fn gen_random_keys(self) -> Result<(u64, u64), c::NTSTATUS> {
+        let mut v = (0, 0);
+        let status = unsafe {
+            let size = mem::size_of_val(&v).try_into().unwrap();
+            c::BCryptGenRandom(self.algorithm, ptr::addr_of_mut!(v).cast(), size, self.flags)
+        };
+        if c::nt_success(status) { Ok(v) } else { Err(status) }
+    }
 }
 
-/// We can't use RtlGenRandom with UWP, so there is no fallback
-#[cfg(target_vendor = "uwp")]
+/// Generate random numbers using the fallback RNG function
 #[inline(never)]
-fn fallback_rng() -> (u64, u64) {
-    panic!("fallback RNG broken: RtlGenRandom() not supported on UWP");
+fn fallback_rng(rng_status: c::NTSTATUS) -> (u64, u64) {
+    match Rng::open().and_then(|rng| rng.gen_random_keys()) {
+        Ok(keys) => keys,
+        Err(status) => {
+            panic!("RNG broken: {rng_status:#x}, fallback RNG broken: {status:#x}")
+        }
+    }
 }