about summary refs log tree commit diff
path: root/library/std/src/sync/poison
diff options
context:
space:
mode:
authorPavel Grigorenko <GrigorenkoPV@ya.ru>2024-12-23 19:36:41 +0300
committerPavel Grigorenko <GrigorenkoPV@ya.ru>2025-01-02 15:21:41 +0300
commitee2ad4dfb1b7d3a07604efc6d9eb618d0fe3bf7d (patch)
tree363fdace20c9ca422a1571a205e7b9bd4803c5af /library/std/src/sync/poison
parent41b579660c0af700d42abe5b71856098db007783 (diff)
downloadrust-ee2ad4dfb1b7d3a07604efc6d9eb618d0fe3bf7d.tar.gz
rust-ee2ad4dfb1b7d3a07604efc6d9eb618d0fe3bf7d.zip
Move some things to `std::sync::poison` and reexport them in `std::sync`
Diffstat (limited to 'library/std/src/sync/poison')
-rw-r--r--library/std/src/sync/poison/condvar.rs571
-rw-r--r--library/std/src/sync/poison/condvar/tests.rs190
-rw-r--r--library/std/src/sync/poison/mutex.rs849
-rw-r--r--library/std/src/sync/poison/mutex/tests.rs442
-rw-r--r--library/std/src/sync/poison/once.rs390
-rw-r--r--library/std/src/sync/poison/once/tests.rs162
-rw-r--r--library/std/src/sync/poison/rwlock.rs1205
-rw-r--r--library/std/src/sync/poison/rwlock/tests.rs729
8 files changed, 4538 insertions, 0 deletions
diff --git a/library/std/src/sync/poison/condvar.rs b/library/std/src/sync/poison/condvar.rs
new file mode 100644
index 00000000000..a6e2389c93b
--- /dev/null
+++ b/library/std/src/sync/poison/condvar.rs
@@ -0,0 +1,571 @@
+#[cfg(test)]
+mod tests;
+
+use crate::fmt;
+use crate::sync::poison::{self, LockResult, MutexGuard, PoisonError, mutex};
+use crate::sys::sync as sys;
+use crate::time::{Duration, Instant};
+
+/// A type indicating whether a timed wait on a condition variable returned
+/// due to a time out or not.
+///
+/// It is returned by the [`wait_timeout`] method.
+///
+/// [`wait_timeout`]: Condvar::wait_timeout
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+#[stable(feature = "wait_timeout", since = "1.5.0")]
+pub struct WaitTimeoutResult(bool);
+
+// FIXME(sync_nonpoison): `WaitTimeoutResult` is actually poisoning-agnostic, it seems.
+// Should we take advantage of this fact?
+impl WaitTimeoutResult {
+    /// Returns `true` if the wait was known to have timed out.
+    ///
+    /// # Examples
+    ///
+    /// This example spawns a thread which will sleep 20 milliseconds before
+    /// updating a boolean value and then notifying the condvar.
+    ///
+    /// The main thread will wait with a 10 millisecond timeout on the condvar
+    /// and will leave the loop upon timeout.
+    ///
+    /// ```
+    /// use std::sync::{Arc, Condvar, Mutex};
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = Arc::clone(&pair);
+    ///
+    /// # let handle =
+    /// thread::spawn(move || {
+    ///     let (lock, cvar) = &*pair2;
+    ///
+    ///     // Let's wait 20 milliseconds before notifying the condvar.
+    ///     thread::sleep(Duration::from_millis(20));
+    ///
+    ///     let mut started = lock.lock().unwrap();
+    ///     // We update the boolean value.
+    ///     *started = true;
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let (lock, cvar) = &*pair;
+    /// loop {
+    ///     // Let's put a timeout on the condvar's wait.
+    ///     let result = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(10)).unwrap();
+    ///     // 10 milliseconds have passed.
+    ///     if result.1.timed_out() {
+    ///         // timed out now and we can leave.
+    ///         break
+    ///     }
+    /// }
+    /// # // Prevent leaks for Miri.
+    /// # let _ = handle.join();
+    /// ```
+    #[must_use]
+    #[stable(feature = "wait_timeout", since = "1.5.0")]
+    pub fn timed_out(&self) -> bool {
+        self.0
+    }
+}
+
+/// A Condition Variable
+///
+/// Condition variables represent the ability to block a thread such that it
+/// consumes no CPU time while waiting for an event to occur. Condition
+/// variables are typically associated with a boolean predicate (a condition)
+/// and a mutex. The predicate is always verified inside of the mutex before
+/// determining that a thread must block.
+///
+/// Functions in this module will block the current **thread** of execution.
+/// Note that any attempt to use multiple mutexes on the same condition
+/// variable may result in a runtime panic.
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Arc, Mutex, Condvar};
+/// use std::thread;
+///
+/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+/// let pair2 = Arc::clone(&pair);
+///
+/// // Inside of our lock, spawn a new thread, and then wait for it to start.
+/// thread::spawn(move || {
+///     let (lock, cvar) = &*pair2;
+///     let mut started = lock.lock().unwrap();
+///     *started = true;
+///     // We notify the condvar that the value has changed.
+///     cvar.notify_one();
+/// });
+///
+/// // Wait for the thread to start up.
+/// let (lock, cvar) = &*pair;
+/// let mut started = lock.lock().unwrap();
+/// while !*started {
+///     started = cvar.wait(started).unwrap();
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Condvar {
+    inner: sys::Condvar,
+}
+
+impl Condvar {
+    /// Creates a new condition variable which is ready to be waited on and
+    /// notified.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Condvar;
+    ///
+    /// let condvar = Condvar::new();
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+    #[must_use]
+    #[inline]
+    pub const fn new() -> Condvar {
+        Condvar { inner: sys::Condvar::new() }
+    }
+
+    /// Blocks the current thread until this condition variable receives a
+    /// notification.
+    ///
+    /// This function will atomically unlock the mutex specified (represented by
+    /// `guard`) and block the current thread. This means that any calls
+    /// to [`notify_one`] or [`notify_all`] which happen logically after the
+    /// mutex is unlocked are candidates to wake this thread up. When this
+    /// function call returns, the lock specified will have been re-acquired.
+    ///
+    /// Note that this function is susceptible to spurious wakeups. Condition
+    /// variables normally have a boolean predicate associated with them, and
+    /// the predicate must always be checked each time this function returns to
+    /// protect against spurious wakeups.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the mutex being waited on is
+    /// poisoned when this thread re-acquires the lock. For more information,
+    /// see information about [poisoning] on the [`Mutex`] type.
+    ///
+    /// # Panics
+    ///
+    /// This function may [`panic!`] if it is used with more than one mutex
+    /// over time.
+    ///
+    /// [`notify_one`]: Self::notify_one
+    /// [`notify_all`]: Self::notify_all
+    /// [poisoning]: super::Mutex#poisoning
+    /// [`Mutex`]: super::Mutex
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = Arc::clone(&pair);
+    ///
+    /// thread::spawn(move || {
+    ///     let (lock, cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let (lock, cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
+    /// while !*started {
+    ///     started = cvar.wait(started).unwrap();
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> {
+        let poisoned = unsafe {
+            let lock = mutex::guard_lock(&guard);
+            self.inner.wait(lock);
+            mutex::guard_poison(&guard).get()
+        };
+        if poisoned { Err(PoisonError::new(guard)) } else { Ok(guard) }
+    }
+
+    /// Blocks the current thread until the provided condition becomes false.
+    ///
+    /// `condition` is checked immediately; if not met (returns `true`), this
+    /// will [`wait`] for the next notification then check again. This repeats
+    /// until `condition` returns `false`, in which case this function returns.
+    ///
+    /// This function will atomically unlock the mutex specified (represented by
+    /// `guard`) and block the current thread. This means that any calls
+    /// to [`notify_one`] or [`notify_all`] which happen logically after the
+    /// mutex is unlocked are candidates to wake this thread up. When this
+    /// function call returns, the lock specified will have been re-acquired.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the mutex being waited on is
+    /// poisoned when this thread re-acquires the lock. For more information,
+    /// see information about [poisoning] on the [`Mutex`] type.
+    ///
+    /// [`wait`]: Self::wait
+    /// [`notify_one`]: Self::notify_one
+    /// [`notify_all`]: Self::notify_all
+    /// [poisoning]: super::Mutex#poisoning
+    /// [`Mutex`]: super::Mutex
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
+    /// let pair2 = Arc::clone(&pair);
+    ///
+    /// thread::spawn(move || {
+    ///     let (lock, cvar) = &*pair2;
+    ///     let mut pending = lock.lock().unwrap();
+    ///     *pending = false;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let (lock, cvar) = &*pair;
+    /// // As long as the value inside the `Mutex<bool>` is `true`, we wait.
+    /// let _guard = cvar.wait_while(lock.lock().unwrap(), |pending| { *pending }).unwrap();
+    /// ```
+    #[stable(feature = "wait_until", since = "1.42.0")]
+    pub fn wait_while<'a, T, F>(
+        &self,
+        mut guard: MutexGuard<'a, T>,
+        mut condition: F,
+    ) -> LockResult<MutexGuard<'a, T>>
+    where
+        F: FnMut(&mut T) -> bool,
+    {
+        while condition(&mut *guard) {
+            guard = self.wait(guard)?;
+        }
+        Ok(guard)
+    }
+
+    /// Waits on this condition variable for a notification, timing out after a
+    /// specified duration.
+    ///
+    /// The semantics of this function are equivalent to [`wait`]
+    /// except that the thread will be blocked for roughly no longer
+    /// than `ms` milliseconds. This method should not be used for
+    /// precise timing due to anomalies such as preemption or platform
+    /// differences that might not cause the maximum amount of time
+    /// waited to be precisely `ms`.
+    ///
+    /// Note that the best effort is made to ensure that the time waited is
+    /// measured with a monotonic clock, and not affected by the changes made to
+    /// the system time.
+    ///
+    /// The returned boolean is `false` only if the timeout is known
+    /// to have elapsed.
+    ///
+    /// Like [`wait`], the lock specified will be re-acquired when this function
+    /// returns, regardless of whether the timeout elapsed or not.
+    ///
+    /// [`wait`]: Self::wait
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = Arc::clone(&pair);
+    ///
+    /// thread::spawn(move || {
+    ///     let (lock, cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let (lock, cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
+    /// loop {
+    ///     let result = cvar.wait_timeout_ms(started, 10).unwrap();
+    ///     // 10 milliseconds have passed, or maybe the value changed!
+    ///     started = result.0;
+    ///     if *started == true {
+    ///         // We received the notification and the value has been updated, we can leave.
+    ///         break
+    ///     }
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[deprecated(since = "1.6.0", note = "replaced by `std::sync::Condvar::wait_timeout`")]
+    pub fn wait_timeout_ms<'a, T>(
+        &self,
+        guard: MutexGuard<'a, T>,
+        ms: u32,
+    ) -> LockResult<(MutexGuard<'a, T>, bool)> {
+        let res = self.wait_timeout(guard, Duration::from_millis(ms as u64));
+        poison::map_result(res, |(a, b)| (a, !b.timed_out()))
+    }
+
+    /// Waits on this condition variable for a notification, timing out after a
+    /// specified duration.
+    ///
+    /// The semantics of this function are equivalent to [`wait`] except that
+    /// the thread will be blocked for roughly no longer than `dur`. This
+    /// method should not be used for precise timing due to anomalies such as
+    /// preemption or platform differences that might not cause the maximum
+    /// amount of time waited to be precisely `dur`.
+    ///
+    /// Note that the best effort is made to ensure that the time waited is
+    /// measured with a monotonic clock, and not affected by the changes made to
+    /// the system time. This function is susceptible to spurious wakeups.
+    /// Condition variables normally have a boolean predicate associated with
+    /// them, and the predicate must always be checked each time this function
+    /// returns to protect against spurious wakeups. Additionally, it is
+    /// typically desirable for the timeout to not exceed some duration in
+    /// spite of spurious wakes, thus the sleep-duration is decremented by the
+    /// amount slept. Alternatively, use the `wait_timeout_while` method
+    /// to wait with a timeout while a predicate is true.
+    ///
+    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
+    /// known to have elapsed.
+    ///
+    /// Like [`wait`], the lock specified will be re-acquired when this function
+    /// returns, regardless of whether the timeout elapsed or not.
+    ///
+    /// [`wait`]: Self::wait
+    /// [`wait_timeout_while`]: Self::wait_timeout_while
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = Arc::clone(&pair);
+    ///
+    /// thread::spawn(move || {
+    ///     let (lock, cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // wait for the thread to start up
+    /// let (lock, cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // as long as the value inside the `Mutex<bool>` is `false`, we wait
+    /// loop {
+    ///     let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
+    ///     // 10 milliseconds have passed, or maybe the value changed!
+    ///     started = result.0;
+    ///     if *started == true {
+    ///         // We received the notification and the value has been updated, we can leave.
+    ///         break
+    ///     }
+    /// }
+    /// ```
+    #[stable(feature = "wait_timeout", since = "1.5.0")]
+    pub fn wait_timeout<'a, T>(
+        &self,
+        guard: MutexGuard<'a, T>,
+        dur: Duration,
+    ) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
+        let (poisoned, result) = unsafe {
+            let lock = mutex::guard_lock(&guard);
+            let success = self.inner.wait_timeout(lock, dur);
+            (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
+        };
+        if poisoned { Err(PoisonError::new((guard, result))) } else { Ok((guard, result)) }
+    }
+
+    /// Waits on this condition variable for a notification, timing out after a
+    /// specified duration.
+    ///
+    /// The semantics of this function are equivalent to [`wait_while`] except
+    /// that the thread will be blocked for roughly no longer than `dur`. This
+    /// method should not be used for precise timing due to anomalies such as
+    /// preemption or platform differences that might not cause the maximum
+    /// amount of time waited to be precisely `dur`.
+    ///
+    /// Note that the best effort is made to ensure that the time waited is
+    /// measured with a monotonic clock, and not affected by the changes made to
+    /// the system time.
+    ///
+    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
+    /// known to have elapsed without the condition being met.
+    ///
+    /// Like [`wait_while`], the lock specified will be re-acquired when this
+    /// function returns, regardless of whether the timeout elapsed or not.
+    ///
+    /// [`wait_while`]: Self::wait_while
+    /// [`wait_timeout`]: Self::wait_timeout
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
+    /// let pair2 = Arc::clone(&pair);
+    ///
+    /// thread::spawn(move || {
+    ///     let (lock, cvar) = &*pair2;
+    ///     let mut pending = lock.lock().unwrap();
+    ///     *pending = false;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // wait for the thread to start up
+    /// let (lock, cvar) = &*pair;
+    /// let result = cvar.wait_timeout_while(
+    ///     lock.lock().unwrap(),
+    ///     Duration::from_millis(100),
+    ///     |&mut pending| pending,
+    /// ).unwrap();
+    /// if result.1.timed_out() {
+    ///     // timed-out without the condition ever evaluating to false.
+    /// }
+    /// // access the locked mutex via result.0
+    /// ```
+    #[stable(feature = "wait_timeout_until", since = "1.42.0")]
+    pub fn wait_timeout_while<'a, T, F>(
+        &self,
+        mut guard: MutexGuard<'a, T>,
+        dur: Duration,
+        mut condition: F,
+    ) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
+    where
+        F: FnMut(&mut T) -> bool,
+    {
+        let start = Instant::now();
+        loop {
+            if !condition(&mut *guard) {
+                return Ok((guard, WaitTimeoutResult(false)));
+            }
+            let timeout = match dur.checked_sub(start.elapsed()) {
+                Some(timeout) => timeout,
+                None => return Ok((guard, WaitTimeoutResult(true))),
+            };
+            guard = self.wait_timeout(guard, timeout)?.0;
+        }
+    }
+
+    /// Wakes up one blocked thread on this condvar.
+    ///
+    /// If there is a blocked thread on this condition variable, then it will
+    /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
+    /// `notify_one` are not buffered in any way.
+    ///
+    /// To wake up all threads, see [`notify_all`].
+    ///
+    /// [`wait`]: Self::wait
+    /// [`wait_timeout`]: Self::wait_timeout
+    /// [`notify_all`]: Self::notify_all
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = Arc::clone(&pair);
+    ///
+    /// thread::spawn(move || {
+    ///     let (lock, cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let (lock, cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
+    /// while !*started {
+    ///     started = cvar.wait(started).unwrap();
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn notify_one(&self) {
+        self.inner.notify_one()
+    }
+
+    /// Wakes up all blocked threads on this condvar.
+    ///
+    /// This method will ensure that any current waiters on the condition
+    /// variable are awoken. Calls to `notify_all()` are not buffered in any
+    /// way.
+    ///
+    /// To wake up only one thread, see [`notify_one`].
+    ///
+    /// [`notify_one`]: Self::notify_one
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = Arc::clone(&pair);
+    ///
+    /// thread::spawn(move || {
+    ///     let (lock, cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_all();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let (lock, cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
+    /// while !*started {
+    ///     started = cvar.wait(started).unwrap();
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn notify_all(&self) {
+        self.inner.notify_all()
+    }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Condvar {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Condvar").finish_non_exhaustive()
+    }
+}
+
+#[stable(feature = "condvar_default", since = "1.10.0")]
+impl Default for Condvar {
+    /// Creates a `Condvar` which is ready to be waited on and notified.
+    fn default() -> Condvar {
+        Condvar::new()
+    }
+}
diff --git a/library/std/src/sync/poison/condvar/tests.rs b/library/std/src/sync/poison/condvar/tests.rs
new file mode 100644
index 00000000000..f9e9066bc92
--- /dev/null
+++ b/library/std/src/sync/poison/condvar/tests.rs
@@ -0,0 +1,190 @@
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::mpsc::channel;
+use crate::sync::{Arc, Condvar, Mutex};
+use crate::thread;
+use crate::time::Duration;
+
+#[test]
+fn smoke() {
+    let c = Condvar::new();
+    c.notify_one();
+    c.notify_all();
+}
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+fn notify_one() {
+    let m = Arc::new(Mutex::new(()));
+    let m2 = m.clone();
+    let c = Arc::new(Condvar::new());
+    let c2 = c.clone();
+
+    let g = m.lock().unwrap();
+    let _t = thread::spawn(move || {
+        let _g = m2.lock().unwrap();
+        c2.notify_one();
+    });
+    let g = c.wait(g).unwrap();
+    drop(g);
+}
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+fn notify_all() {
+    const N: usize = 10;
+
+    let data = Arc::new((Mutex::new(0), Condvar::new()));
+    let (tx, rx) = channel();
+    for _ in 0..N {
+        let data = data.clone();
+        let tx = tx.clone();
+        thread::spawn(move || {
+            let &(ref lock, ref cond) = &*data;
+            let mut cnt = lock.lock().unwrap();
+            *cnt += 1;
+            if *cnt == N {
+                tx.send(()).unwrap();
+            }
+            while *cnt != 0 {
+                cnt = cond.wait(cnt).unwrap();
+            }
+            tx.send(()).unwrap();
+        });
+    }
+    drop(tx);
+
+    let &(ref lock, ref cond) = &*data;
+    rx.recv().unwrap();
+    let mut cnt = lock.lock().unwrap();
+    *cnt = 0;
+    cond.notify_all();
+    drop(cnt);
+
+    for _ in 0..N {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+fn wait_while() {
+    let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    let pair2 = pair.clone();
+
+    // Inside of our lock, spawn a new thread, and then wait for it to start.
+    thread::spawn(move || {
+        let &(ref lock, ref cvar) = &*pair2;
+        let mut started = lock.lock().unwrap();
+        *started = true;
+        // We notify the condvar that the value has changed.
+        cvar.notify_one();
+    });
+
+    // Wait for the thread to start up.
+    let &(ref lock, ref cvar) = &*pair;
+    let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started);
+    assert!(*guard.unwrap());
+}
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
+fn wait_timeout_wait() {
+    let m = Arc::new(Mutex::new(()));
+    let c = Arc::new(Condvar::new());
+
+    loop {
+        let g = m.lock().unwrap();
+        let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
+        // spurious wakeups mean this isn't necessarily true
+        // so execute test again, if not timeout
+        if !no_timeout.timed_out() {
+            continue;
+        }
+
+        break;
+    }
+}
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
+fn wait_timeout_while_wait() {
+    let m = Arc::new(Mutex::new(()));
+    let c = Arc::new(Condvar::new());
+
+    let g = m.lock().unwrap();
+    let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap();
+    // no spurious wakeups. ensure it timed-out
+    assert!(wait.timed_out());
+}
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
+fn wait_timeout_while_instant_satisfy() {
+    let m = Arc::new(Mutex::new(()));
+    let c = Arc::new(Condvar::new());
+
+    let g = m.lock().unwrap();
+    let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap();
+    // ensure it didn't time-out even if we were not given any time.
+    assert!(!wait.timed_out());
+}
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+fn wait_timeout_while_wake() {
+    let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    let pair_copy = pair.clone();
+
+    let &(ref m, ref c) = &*pair;
+    let g = m.lock().unwrap();
+    let _t = thread::spawn(move || {
+        let &(ref lock, ref cvar) = &*pair_copy;
+        let mut started = lock.lock().unwrap();
+        thread::sleep(Duration::from_millis(1));
+        *started = true;
+        cvar.notify_one();
+    });
+    let (g2, wait) = c
+        .wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified)
+        .unwrap();
+    // ensure it didn't time-out even if we were not given any time.
+    assert!(!wait.timed_out());
+    assert!(*g2);
+}
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+fn wait_timeout_wake() {
+    let m = Arc::new(Mutex::new(()));
+    let c = Arc::new(Condvar::new());
+
+    loop {
+        let g = m.lock().unwrap();
+
+        let c2 = c.clone();
+        let m2 = m.clone();
+
+        let notified = Arc::new(AtomicBool::new(false));
+        let notified_copy = notified.clone();
+
+        let t = thread::spawn(move || {
+            let _g = m2.lock().unwrap();
+            thread::sleep(Duration::from_millis(1));
+            notified_copy.store(true, Ordering::Relaxed);
+            c2.notify_one();
+        });
+        let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap();
+        assert!(!timeout_res.timed_out());
+        // spurious wakeups mean this isn't necessarily true
+        // so execute test again, if not notified
+        if !notified.load(Ordering::Relaxed) {
+            t.join().unwrap();
+            continue;
+        }
+        drop(g);
+
+        t.join().unwrap();
+
+        break;
+    }
+}
diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs
new file mode 100644
index 00000000000..e28c2090afe
--- /dev/null
+++ b/library/std/src/sync/poison/mutex.rs
@@ -0,0 +1,849 @@
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
+mod tests;
+
+use crate::cell::UnsafeCell;
+use crate::fmt;
+use crate::marker::PhantomData;
+use crate::mem::{self, ManuallyDrop};
+use crate::ops::{Deref, DerefMut};
+use crate::ptr::NonNull;
+use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison};
+use crate::sys::sync as sys;
+
+/// A mutual exclusion primitive useful for protecting shared data
+///
+/// This mutex will block threads waiting for the lock to become available. The
+/// mutex can be created via a [`new`] constructor. Each mutex has a type parameter
+/// which represents the data that it is protecting. The data can only be accessed
+/// through the RAII guards returned from [`lock`] and [`try_lock`], which
+/// guarantees that the data is only ever accessed when the mutex is locked.
+///
+/// # Poisoning
+///
+/// The mutexes in this module implement a strategy called "poisoning" where a
+/// mutex is considered poisoned whenever a thread panics while holding the
+/// mutex. Once a mutex is poisoned, all other threads are unable to access the
+/// data by default as it is likely tainted (some invariant is not being
+/// upheld).
+///
+/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a
+/// [`Result`] which indicates whether a mutex has been poisoned or not. Most
+/// usage of a mutex will simply [`unwrap()`] these results, propagating panics
+/// among threads to ensure that a possibly invalid invariant is not witnessed.
+///
+/// A poisoned mutex, however, does not prevent all access to the underlying
+/// data. The [`PoisonError`] type has an [`into_inner`] method which will return
+/// the guard that would have otherwise been returned on a successful lock. This
+/// allows access to the data, despite the lock being poisoned.
+///
+/// [`new`]: Self::new
+/// [`lock`]: Self::lock
+/// [`try_lock`]: Self::try_lock
+/// [`unwrap()`]: Result::unwrap
+/// [`PoisonError`]: super::PoisonError
+/// [`into_inner`]: super::PoisonError::into_inner
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Arc, Mutex};
+/// use std::thread;
+/// use std::sync::mpsc::channel;
+///
+/// const N: usize = 10;
+///
+/// // Spawn a few threads to increment a shared variable (non-atomically), and
+/// // let the main thread know once all increments are done.
+/// //
+/// // Here we're using an Arc to share memory among threads, and the data inside
+/// // the Arc is protected with a mutex.
+/// let data = Arc::new(Mutex::new(0));
+///
+/// let (tx, rx) = channel();
+/// for _ in 0..N {
+///     let (data, tx) = (Arc::clone(&data), tx.clone());
+///     thread::spawn(move || {
+///         // The shared state can only be accessed once the lock is held.
+///         // Our non-atomic increment is safe because we're the only thread
+///         // which can access the shared state when the lock is held.
+///         //
+///         // We unwrap() the return value to assert that we are not expecting
+///         // threads to ever fail while holding the lock.
+///         let mut data = data.lock().unwrap();
+///         *data += 1;
+///         if *data == N {
+///             tx.send(()).unwrap();
+///         }
+///         // the lock is unlocked here when `data` goes out of scope.
+///     });
+/// }
+///
+/// rx.recv().unwrap();
+/// ```
+///
+/// To recover from a poisoned mutex:
+///
+/// ```
+/// use std::sync::{Arc, Mutex};
+/// use std::thread;
+///
+/// let lock = Arc::new(Mutex::new(0_u32));
+/// let lock2 = Arc::clone(&lock);
+///
+/// let _ = thread::spawn(move || -> () {
+///     // This thread will acquire the mutex first, unwrapping the result of
+///     // `lock` because the lock has not been poisoned.
+///     let _guard = lock2.lock().unwrap();
+///
+///     // This panic while holding the lock (`_guard` is in scope) will poison
+///     // the mutex.
+///     panic!();
+/// }).join();
+///
+/// // The lock is poisoned by this point, but the returned result can be
+/// // pattern matched on to return the underlying guard on both branches.
+/// let mut guard = match lock.lock() {
+///     Ok(guard) => guard,
+///     Err(poisoned) => poisoned.into_inner(),
+/// };
+///
+/// *guard += 1;
+/// ```
+///
+/// To unlock a mutex guard sooner than the end of the enclosing scope,
+/// either create an inner scope or drop the guard manually.
+///
+/// ```
+/// use std::sync::{Arc, Mutex};
+/// use std::thread;
+///
+/// const N: usize = 3;
+///
+/// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
+/// let res_mutex = Arc::new(Mutex::new(0));
+///
+/// let mut threads = Vec::with_capacity(N);
+/// (0..N).for_each(|_| {
+///     let data_mutex_clone = Arc::clone(&data_mutex);
+///     let res_mutex_clone = Arc::clone(&res_mutex);
+///
+///     threads.push(thread::spawn(move || {
+///         // Here we use a block to limit the lifetime of the lock guard.
+///         let result = {
+///             let mut data = data_mutex_clone.lock().unwrap();
+///             // This is the result of some important and long-ish work.
+///             let result = data.iter().fold(0, |acc, x| acc + x * 2);
+///             data.push(result);
+///             result
+///             // The mutex guard gets dropped here, together with any other values
+///             // created in the critical section.
+///         };
+///         // The guard created here is a temporary dropped at the end of the statement, i.e.
+///         // the lock would not remain being held even if the thread did some additional work.
+///         *res_mutex_clone.lock().unwrap() += result;
+///     }));
+/// });
+///
+/// let mut data = data_mutex.lock().unwrap();
+/// // This is the result of some important and long-ish work.
+/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
+/// data.push(result);
+/// // We drop the `data` explicitly because it's not necessary anymore and the
+/// // thread still has work to do. This allows other threads to start working on
+/// // the data immediately, without waiting for the rest of the unrelated work
+/// // to be done here.
+/// //
+/// // It's even more important here than in the threads because we `.join` the
+/// // threads after that. If we had not dropped the mutex guard, a thread could
+/// // be waiting forever for it, causing a deadlock.
+/// // As in the threads, a block could have been used instead of calling the
+/// // `drop` function.
+/// drop(data);
+/// // Here the mutex guard is not assigned to a variable and so, even if the
+/// // scope does not end after this line, the mutex is still released: there is
+/// // no deadlock.
+/// *res_mutex.lock().unwrap() += result;
+///
+/// threads.into_iter().for_each(|thread| {
+///     thread
+///         .join()
+///         .expect("The thread creating or execution failed !")
+/// });
+///
+/// assert_eq!(*res_mutex.lock().unwrap(), 800);
+/// ```
+///
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")]
+pub struct Mutex<T: ?Sized> {
+    inner: sys::Mutex,
+    poison: poison::Flag,
+    data: UnsafeCell<T>,
+}
+
+// these are the only places where `T: Send` matters; all other
+// functionality works fine on a single thread.
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
+
+/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
+/// dropped (falls out of scope), the lock will be unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// [`Deref`] and [`DerefMut`] implementations.
+///
+/// This structure is created by the [`lock`] and [`try_lock`] methods on
+/// [`Mutex`].
+///
+/// [`lock`]: Mutex::lock
+/// [`try_lock`]: Mutex::try_lock
+#[must_use = "if unused the Mutex will immediately unlock"]
+#[must_not_suspend = "holding a MutexGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Futures to not implement `Send`"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "MutexGuard")]
+pub struct MutexGuard<'a, T: ?Sized + 'a> {
+    lock: &'a Mutex<T>,
+    poison: poison::Guard,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
+#[stable(feature = "mutexguard", since = "1.19.0")]
+unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
+
+/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a
+/// subfield of the protected data. When this structure is dropped (falls out
+/// of scope), the lock will be unlocked.
+///
+/// The main difference between `MappedMutexGuard` and [`MutexGuard`] is that the
+/// former cannot be used with [`Condvar`], since that
+/// could introduce soundness issues if the locked object is modified by another
+/// thread while the `Mutex` is unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// [`Deref`] and [`DerefMut`] implementations.
+///
+/// This structure is created by the [`map`] and [`try_map`] methods on
+/// [`MutexGuard`].
+///
+/// [`map`]: MutexGuard::map
+/// [`try_map`]: MutexGuard::try_map
+/// [`Condvar`]: crate::sync::Condvar
+#[must_use = "if unused the Mutex will immediately unlock"]
+#[must_not_suspend = "holding a MappedMutexGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Futures to not implement `Send`"]
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+#[clippy::has_significant_drop]
+pub struct MappedMutexGuard<'a, T: ?Sized + 'a> {
+    // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a
+    // `MappedMutexGuard` argument doesn't hold uniqueness for its whole scope, only until it drops.
+    // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field
+    // below for the correct variance over `T` (invariance).
+    data: NonNull<T>,
+    inner: &'a sys::Mutex,
+    poison_flag: &'a poison::Flag,
+    poison: poison::Guard,
+    _variance: PhantomData<&'a mut T>,
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> !Send for MappedMutexGuard<'_, T> {}
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+unsafe impl<T: ?Sized + Sync> Sync for MappedMutexGuard<'_, T> {}
+
+impl<T> Mutex<T> {
+    /// Creates a new mutex in an unlocked state ready for use.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Mutex;
+    ///
+    /// let mutex = Mutex::new(0);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+    #[inline]
+    pub const fn new(t: T) -> Mutex<T> {
+        Mutex { inner: sys::Mutex::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
+    }
+
+    /// Returns the contained value by cloning it.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return an error instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(7);
+    ///
+    /// assert_eq!(mutex.get_cloned().unwrap(), 7);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn get_cloned(&self) -> Result<T, PoisonError<()>>
+    where
+        T: Clone,
+    {
+        match self.lock() {
+            Ok(guard) => Ok((*guard).clone()),
+            Err(_) => Err(PoisonError::new(())),
+        }
+    }
+
+    /// Sets the contained value.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return an error containing the provided `value` instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(7);
+    ///
+    /// assert_eq!(mutex.get_cloned().unwrap(), 7);
+    /// mutex.set(11).unwrap();
+    /// assert_eq!(mutex.get_cloned().unwrap(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn set(&self, value: T) -> Result<(), PoisonError<T>> {
+        if mem::needs_drop::<T>() {
+            // If the contained value has non-trivial destructor, we
+            // call that destructor after the lock being released.
+            self.replace(value).map(drop)
+        } else {
+            match self.lock() {
+                Ok(mut guard) => {
+                    *guard = value;
+
+                    Ok(())
+                }
+                Err(_) => Err(PoisonError::new(value)),
+            }
+        }
+    }
+
+    /// Replaces the contained value with `value`, and returns the old contained value.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return an error containing the provided `value` instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(7);
+    ///
+    /// assert_eq!(mutex.replace(11).unwrap(), 7);
+    /// assert_eq!(mutex.get_cloned().unwrap(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn replace(&self, value: T) -> LockResult<T> {
+        match self.lock() {
+            Ok(mut guard) => Ok(mem::replace(&mut *guard, value)),
+            Err(_) => Err(PoisonError::new(value)),
+        }
+    }
+}
+
+impl<T: ?Sized> Mutex<T> {
+    /// Acquires a mutex, blocking the current thread until it is able to do so.
+    ///
+    /// This function will block the local thread until it is available to acquire
+    /// the mutex. Upon returning, the thread is the only thread with the lock
+    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
+    /// the guard goes out of scope, the mutex will be unlocked.
+    ///
+    /// The exact behavior on locking a mutex in the thread which already holds
+    /// the lock is left unspecified. However, this function will not return on
+    /// the second call (it might panic or deadlock, for example).
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return an error once the mutex is acquired. The acquired
+    /// mutex guard will be contained in the returned error.
+    ///
+    /// # Panics
+    ///
+    /// This function might panic when called if the lock is already held by
+    /// the current thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex};
+    /// use std::thread;
+    ///
+    /// let mutex = Arc::new(Mutex::new(0));
+    /// let c_mutex = Arc::clone(&mutex);
+    ///
+    /// thread::spawn(move || {
+    ///     *c_mutex.lock().unwrap() = 10;
+    /// }).join().expect("thread::spawn failed");
+    /// assert_eq!(*mutex.lock().unwrap(), 10);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
+        unsafe {
+            self.inner.lock();
+            MutexGuard::new(self)
+        }
+    }
+
+    /// Attempts to acquire this lock.
+    ///
+    /// If the lock could not be acquired at this time, then [`Err`] is returned.
+    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
+    /// guard is dropped.
+    ///
+    /// This function does not block.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return the [`Poisoned`] error if the mutex would
+    /// otherwise be acquired. An acquired lock guard will be contained
+    /// in the returned error.
+    ///
+    /// If the mutex could not be acquired because it is already locked, then
+    /// this call will return the [`WouldBlock`] error.
+    ///
+    /// [`Poisoned`]: TryLockError::Poisoned
+    /// [`WouldBlock`]: TryLockError::WouldBlock
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex};
+    /// use std::thread;
+    ///
+    /// let mutex = Arc::new(Mutex::new(0));
+    /// let c_mutex = Arc::clone(&mutex);
+    ///
+    /// thread::spawn(move || {
+    ///     let mut lock = c_mutex.try_lock();
+    ///     if let Ok(ref mut mutex) = lock {
+    ///         **mutex = 10;
+    ///     } else {
+    ///         println!("try_lock failed");
+    ///     }
+    /// }).join().expect("thread::spawn failed");
+    /// assert_eq!(*mutex.lock().unwrap(), 10);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
+        unsafe {
+            if self.inner.try_lock() {
+                Ok(MutexGuard::new(self)?)
+            } else {
+                Err(TryLockError::WouldBlock)
+            }
+        }
+    }
+
+    /// Determines whether the mutex is poisoned.
+    ///
+    /// If another thread is active, the mutex can still become poisoned at any
+    /// time. You should not trust a `false` value for program correctness
+    /// without additional synchronization.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex};
+    /// use std::thread;
+    ///
+    /// let mutex = Arc::new(Mutex::new(0));
+    /// let c_mutex = Arc::clone(&mutex);
+    ///
+    /// let _ = thread::spawn(move || {
+    ///     let _lock = c_mutex.lock().unwrap();
+    ///     panic!(); // the mutex gets poisoned
+    /// }).join();
+    /// assert_eq!(mutex.is_poisoned(), true);
+    /// ```
+    #[inline]
+    #[stable(feature = "sync_poison", since = "1.2.0")]
+    pub fn is_poisoned(&self) -> bool {
+        self.poison.get()
+    }
+
+    /// Clear the poisoned state from a mutex.
+    ///
+    /// If the mutex is poisoned, it will remain poisoned until this function is called. This
+    /// allows recovering from a poisoned state and marking that it has recovered. For example, if
+    /// the value is overwritten by a known-good value, then the mutex can be marked as
+    /// un-poisoned. Or possibly, the value could be inspected to determine if it is in a
+    /// consistent state, and if so the poison is removed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex};
+    /// use std::thread;
+    ///
+    /// let mutex = Arc::new(Mutex::new(0));
+    /// let c_mutex = Arc::clone(&mutex);
+    ///
+    /// let _ = thread::spawn(move || {
+    ///     let _lock = c_mutex.lock().unwrap();
+    ///     panic!(); // the mutex gets poisoned
+    /// }).join();
+    ///
+    /// assert_eq!(mutex.is_poisoned(), true);
+    /// let x = mutex.lock().unwrap_or_else(|mut e| {
+    ///     **e.get_mut() = 1;
+    ///     mutex.clear_poison();
+    ///     e.into_inner()
+    /// });
+    /// assert_eq!(mutex.is_poisoned(), false);
+    /// assert_eq!(*x, 1);
+    /// ```
+    #[inline]
+    #[stable(feature = "mutex_unpoison", since = "1.77.0")]
+    pub fn clear_poison(&self) {
+        self.poison.clear();
+    }
+
+    /// Consumes this mutex, returning the underlying data.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return an error containing the the underlying data
+    /// instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Mutex;
+    ///
+    /// let mutex = Mutex::new(0);
+    /// assert_eq!(mutex.into_inner().unwrap(), 0);
+    /// ```
+    #[stable(feature = "mutex_into_inner", since = "1.6.0")]
+    pub fn into_inner(self) -> LockResult<T>
+    where
+        T: Sized,
+    {
+        let data = self.data.into_inner();
+        poison::map_result(self.poison.borrow(), |()| data)
+    }
+
+    /// Returns a mutable reference to the underlying data.
+    ///
+    /// Since this call borrows the `Mutex` mutably, no actual locking needs to
+    /// take place -- the mutable borrow statically guarantees no locks exist.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return an error containing a mutable reference to the
+    /// underlying data instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(0);
+    /// *mutex.get_mut().unwrap() = 10;
+    /// assert_eq!(*mutex.lock().unwrap(), 10);
+    /// ```
+    #[stable(feature = "mutex_get_mut", since = "1.6.0")]
+    pub fn get_mut(&mut self) -> LockResult<&mut T> {
+        let data = self.data.get_mut();
+        poison::map_result(self.poison.borrow(), |()| data)
+    }
+}
+
+#[stable(feature = "mutex_from", since = "1.24.0")]
+impl<T> From<T> for Mutex<T> {
+    /// Creates a new mutex in an unlocked state ready for use.
+    /// This is equivalent to [`Mutex::new`].
+    fn from(t: T) -> Self {
+        Mutex::new(t)
+    }
+}
+
+#[stable(feature = "mutex_default", since = "1.10.0")]
+impl<T: ?Sized + Default> Default for Mutex<T> {
+    /// Creates a `Mutex<T>`, with the `Default` value for T.
+    fn default() -> Mutex<T> {
+        Mutex::new(Default::default())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut d = f.debug_struct("Mutex");
+        match self.try_lock() {
+            Ok(guard) => {
+                d.field("data", &&*guard);
+            }
+            Err(TryLockError::Poisoned(err)) => {
+                d.field("data", &&**err.get_ref());
+            }
+            Err(TryLockError::WouldBlock) => {
+                d.field("data", &format_args!("<locked>"));
+            }
+        }
+        d.field("poisoned", &self.poison.get());
+        d.finish_non_exhaustive()
+    }
+}
+
+impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
+    unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> {
+        poison::map_result(lock.poison.guard(), |guard| MutexGuard { lock, poison: guard })
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Deref for MutexGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe { &*self.lock.data.get() }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe { &mut *self.lock.data.get() }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Drop for MutexGuard<'_, T> {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.lock.poison.done(&self.poison);
+            self.lock.inner.unlock();
+        }
+    }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+#[stable(feature = "std_guard_impls", since = "1.20.0")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
+    &guard.lock.inner
+}
+
+pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
+    &guard.lock.poison
+}
+
+impl<'a, T: ?Sized> MutexGuard<'a, T> {
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MutexGuard::map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedMutexGuard {
+            data,
+            inner: &orig.lock.inner,
+            poison_flag: &orig.lock.poison,
+            poison: orig.poison.clone(),
+            _variance: PhantomData,
+        }
+    }
+
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MutexGuard::try_map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { &mut *orig.lock.data.get() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedMutexGuard {
+                    data,
+                    inner: &orig.lock.inner,
+                    poison_flag: &orig.lock.poison,
+                    poison: orig.poison.clone(),
+                    _variance: PhantomData,
+                })
+            }
+            None => Err(orig),
+        }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Deref for MappedMutexGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe { self.data.as_ref() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> DerefMut for MappedMutexGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe { self.data.as_mut() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Drop for MappedMutexGuard<'_, T> {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.poison_flag.done(&self.poison);
+            self.inner.unlock();
+        }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedMutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MappedMutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedMutexGuard::map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedMutexGuard {
+            data,
+            inner: orig.inner,
+            poison_flag: orig.poison_flag,
+            poison: orig.poison.clone(),
+            _variance: PhantomData,
+        }
+    }
+
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedMutexGuard::try_map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { orig.data.as_mut() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedMutexGuard {
+                    data,
+                    inner: orig.inner,
+                    poison_flag: orig.poison_flag,
+                    poison: orig.poison.clone(),
+                    _variance: PhantomData,
+                })
+            }
+            None => Err(orig),
+        }
+    }
+}
diff --git a/library/std/src/sync/poison/mutex/tests.rs b/library/std/src/sync/poison/mutex/tests.rs
new file mode 100644
index 00000000000..395c8aada08
--- /dev/null
+++ b/library/std/src/sync/poison/mutex/tests.rs
@@ -0,0 +1,442 @@
+use crate::fmt::Debug;
+use crate::ops::FnMut;
+use crate::panic::{self, AssertUnwindSafe};
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::mpsc::channel;
+use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError};
+use crate::{hint, mem, thread};
+
+struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+
+#[derive(Eq, PartialEq, Debug)]
+struct NonCopy(i32);
+
+#[derive(Eq, PartialEq, Debug)]
+struct NonCopyNeedsDrop(i32);
+
+impl Drop for NonCopyNeedsDrop {
+    fn drop(&mut self) {
+        hint::black_box(());
+    }
+}
+
+#[test]
+fn test_needs_drop() {
+    assert!(!mem::needs_drop::<NonCopy>());
+    assert!(mem::needs_drop::<NonCopyNeedsDrop>());
+}
+
+#[derive(Clone, Eq, PartialEq, Debug)]
+struct Cloneable(i32);
+
+#[test]
+fn smoke() {
+    let m = Mutex::new(());
+    drop(m.lock().unwrap());
+    drop(m.lock().unwrap());
+}
+
+#[test]
+fn lots_and_lots() {
+    const J: u32 = 1000;
+    const K: u32 = 3;
+
+    let m = Arc::new(Mutex::new(0));
+
+    fn inc(m: &Mutex<u32>) {
+        for _ in 0..J {
+            *m.lock().unwrap() += 1;
+        }
+    }
+
+    let (tx, rx) = channel();
+    for _ in 0..K {
+        let tx2 = tx.clone();
+        let m2 = m.clone();
+        thread::spawn(move || {
+            inc(&m2);
+            tx2.send(()).unwrap();
+        });
+        let tx2 = tx.clone();
+        let m2 = m.clone();
+        thread::spawn(move || {
+            inc(&m2);
+            tx2.send(()).unwrap();
+        });
+    }
+
+    drop(tx);
+    for _ in 0..2 * K {
+        rx.recv().unwrap();
+    }
+    assert_eq!(*m.lock().unwrap(), J * K * 2);
+}
+
+#[test]
+fn try_lock() {
+    let m = Mutex::new(());
+    *m.try_lock().unwrap() = ();
+}
+
+fn new_poisoned_mutex<T>(value: T) -> Mutex<T> {
+    let mutex = Mutex::new(value);
+
+    let catch_unwind_result = panic::catch_unwind(AssertUnwindSafe(|| {
+        let _guard = mutex.lock().unwrap();
+
+        panic!("test panic to poison mutex");
+    }));
+
+    assert!(catch_unwind_result.is_err());
+    assert!(mutex.is_poisoned());
+
+    mutex
+}
+
+#[test]
+fn test_into_inner() {
+    let m = Mutex::new(NonCopy(10));
+    assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+}
+
+#[test]
+fn test_into_inner_drop() {
+    struct Foo(Arc<AtomicUsize>);
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            self.0.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+    let num_drops = Arc::new(AtomicUsize::new(0));
+    let m = Mutex::new(Foo(num_drops.clone()));
+    assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+    {
+        let _inner = m.into_inner().unwrap();
+        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+    }
+    assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+}
+
+#[test]
+fn test_into_inner_poison() {
+    let m = new_poisoned_mutex(NonCopy(10));
+
+    match m.into_inner() {
+        Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+        Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {x:?}"),
+    }
+}
+
+#[test]
+fn test_get_cloned() {
+    let m = Mutex::new(Cloneable(10));
+
+    assert_eq!(m.get_cloned().unwrap(), Cloneable(10));
+}
+
+#[test]
+fn test_get_cloned_poison() {
+    let m = new_poisoned_mutex(Cloneable(10));
+
+    match m.get_cloned() {
+        Err(e) => assert_eq!(e.into_inner(), ()),
+        Ok(x) => panic!("get of poisoned Mutex is Ok: {x:?}"),
+    }
+}
+
+#[test]
+fn test_get_mut() {
+    let mut m = Mutex::new(NonCopy(10));
+    *m.get_mut().unwrap() = NonCopy(20);
+    assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+}
+
+#[test]
+fn test_get_mut_poison() {
+    let mut m = new_poisoned_mutex(NonCopy(10));
+
+    match m.get_mut() {
+        Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+        Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {x:?}"),
+    }
+}
+
+#[test]
+fn test_set() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = Mutex::new(init());
+
+        assert_eq!(*m.lock().unwrap(), init());
+        m.set(value()).unwrap();
+        assert_eq!(*m.lock().unwrap(), value());
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_set_poison() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = new_poisoned_mutex(init());
+
+        match m.set(value()) {
+            Err(e) => {
+                assert_eq!(e.into_inner(), value());
+                assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
+            }
+            Ok(x) => panic!("set of poisoned Mutex is Ok: {x:?}"),
+        }
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_replace() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = Mutex::new(init());
+
+        assert_eq!(*m.lock().unwrap(), init());
+        assert_eq!(m.replace(value()).unwrap(), init());
+        assert_eq!(*m.lock().unwrap(), value());
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_replace_poison() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = new_poisoned_mutex(init());
+
+        match m.replace(value()) {
+            Err(e) => {
+                assert_eq!(e.into_inner(), value());
+                assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
+            }
+            Ok(x) => panic!("replace of poisoned Mutex is Ok: {x:?}"),
+        }
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_mutex_arc_condvar() {
+    let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
+    let packet2 = Packet(packet.0.clone());
+    let (tx, rx) = channel();
+    let _t = thread::spawn(move || {
+        // wait until parent gets in
+        rx.recv().unwrap();
+        let &(ref lock, ref cvar) = &*packet2.0;
+        let mut lock = lock.lock().unwrap();
+        *lock = true;
+        cvar.notify_one();
+    });
+
+    let &(ref lock, ref cvar) = &*packet.0;
+    let mut lock = lock.lock().unwrap();
+    tx.send(()).unwrap();
+    assert!(!*lock);
+    while !*lock {
+        lock = cvar.wait(lock).unwrap();
+    }
+}
+
+#[test]
+fn test_arc_condvar_poison() {
+    let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
+    let packet2 = Packet(packet.0.clone());
+    let (tx, rx) = channel();
+
+    let _t = thread::spawn(move || -> () {
+        rx.recv().unwrap();
+        let &(ref lock, ref cvar) = &*packet2.0;
+        let _g = lock.lock().unwrap();
+        cvar.notify_one();
+        // Parent should fail when it wakes up.
+        panic!();
+    });
+
+    let &(ref lock, ref cvar) = &*packet.0;
+    let mut lock = lock.lock().unwrap();
+    tx.send(()).unwrap();
+    while *lock == 1 {
+        match cvar.wait(lock) {
+            Ok(l) => {
+                lock = l;
+                assert_eq!(*lock, 1);
+            }
+            Err(..) => break,
+        }
+    }
+}
+
+#[test]
+fn test_mutex_arc_poison() {
+    let arc = Arc::new(Mutex::new(1));
+    assert!(!arc.is_poisoned());
+    let arc2 = arc.clone();
+    let _ = thread::spawn(move || {
+        let lock = arc2.lock().unwrap();
+        assert_eq!(*lock, 2); // deliberate assertion failure to poison the mutex
+    })
+    .join();
+    assert!(arc.lock().is_err());
+    assert!(arc.is_poisoned());
+}
+
+#[test]
+fn test_mutex_arc_poison_mapped() {
+    let arc = Arc::new(Mutex::new(1));
+    assert!(!arc.is_poisoned());
+    let arc2 = arc.clone();
+    let _ = thread::spawn(move || {
+        let lock = arc2.lock().unwrap();
+        let lock = MutexGuard::map(lock, |val| val);
+        assert_eq!(*lock, 2); // deliberate assertion failure to poison the mutex
+    })
+    .join();
+    assert!(arc.lock().is_err());
+    assert!(arc.is_poisoned());
+}
+
+#[test]
+fn test_mutex_arc_nested() {
+    // Tests nested mutexes and access
+    // to underlying data.
+    let arc = Arc::new(Mutex::new(1));
+    let arc2 = Arc::new(Mutex::new(arc));
+    let (tx, rx) = channel();
+    let _t = thread::spawn(move || {
+        let lock = arc2.lock().unwrap();
+        let lock2 = lock.lock().unwrap();
+        assert_eq!(*lock2, 1);
+        tx.send(()).unwrap();
+    });
+    rx.recv().unwrap();
+}
+
+#[test]
+fn test_mutex_arc_access_in_unwind() {
+    let arc = Arc::new(Mutex::new(1));
+    let arc2 = arc.clone();
+    let _ = thread::spawn(move || -> () {
+        struct Unwinder {
+            i: Arc<Mutex<i32>>,
+        }
+        impl Drop for Unwinder {
+            fn drop(&mut self) {
+                *self.i.lock().unwrap() += 1;
+            }
+        }
+        let _u = Unwinder { i: arc2 };
+        panic!();
+    })
+    .join();
+    let lock = arc.lock().unwrap();
+    assert_eq!(*lock, 2);
+}
+
+#[test]
+fn test_mutex_unsized() {
+    let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
+    {
+        let b = &mut *mutex.lock().unwrap();
+        b[0] = 4;
+        b[2] = 5;
+    }
+    let comp: &[i32] = &[4, 2, 5];
+    assert_eq!(&*mutex.lock().unwrap(), comp);
+}
+
+#[test]
+fn test_mapping_mapped_guard() {
+    let arr = [0; 4];
+    let mut lock = Mutex::new(arr);
+    let guard = lock.lock().unwrap();
+    let guard = MutexGuard::map(guard, |arr| &mut arr[..2]);
+    let mut guard = MappedMutexGuard::map(guard, |slice| &mut slice[1..]);
+    assert_eq!(guard.len(), 1);
+    guard[0] = 42;
+    drop(guard);
+    assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
+}
+
+#[test]
+fn panic_while_mapping_unlocked_poison() {
+    let lock = Mutex::new(());
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.lock().unwrap();
+        let _guard = MutexGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_lock() {
+        Ok(_) => panic!("panicking in a MutexGuard::map closure should poison the Mutex"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MutexGuard::map closure should unlock the mutex")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.lock().unwrap();
+        let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_lock() {
+        Ok(_) => panic!("panicking in a MutexGuard::try_map closure should poison the Mutex"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MutexGuard::try_map closure should unlock the mutex")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.lock().unwrap();
+        let guard = MutexGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedMutexGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_lock() {
+        Ok(_) => panic!("panicking in a MappedMutexGuard::map closure should poison the Mutex"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MappedMutexGuard::map closure should unlock the mutex")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.lock().unwrap();
+        let guard = MutexGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_lock() {
+        Ok(_) => panic!("panicking in a MappedMutexGuard::try_map closure should poison the Mutex"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MappedMutexGuard::try_map closure should unlock the mutex")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    drop(lock);
+}
diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs
new file mode 100644
index 00000000000..27db4b634fb
--- /dev/null
+++ b/library/std/src/sync/poison/once.rs
@@ -0,0 +1,390 @@
+//! A "once initialization" primitive
+//!
+//! This primitive is meant to be used to run one-time initialization. An
+//! example use case would be for initializing an FFI library.
+
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
+mod tests;
+
+use crate::fmt;
+use crate::panic::{RefUnwindSafe, UnwindSafe};
+use crate::sys::sync as sys;
+
+/// A low-level synchronization primitive for one-time global execution.
+///
+/// Previously this was the only "execute once" synchronization in `std`.
+/// Other libraries implemented novel synchronizing types with `Once`, like
+/// [`OnceLock<T>`] or [`LazyLock<T, F>`], before those were added to `std`.
+/// `OnceLock<T>` in particular supersedes `Once` in functionality and should
+/// be preferred for the common case where the `Once` is associated with data.
+///
+/// This type can only be constructed with [`Once::new()`].
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::Once;
+///
+/// static START: Once = Once::new();
+///
+/// START.call_once(|| {
+///     // run initialization here
+/// });
+/// ```
+///
+/// [`OnceLock<T>`]: crate::sync::OnceLock
+/// [`LazyLock<T, F>`]: crate::sync::LazyLock
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Once {
+    inner: sys::Once,
+}
+
+#[stable(feature = "sync_once_unwind_safe", since = "1.59.0")]
+impl UnwindSafe for Once {}
+
+#[stable(feature = "sync_once_unwind_safe", since = "1.59.0")]
+impl RefUnwindSafe for Once {}
+
+/// State yielded to [`Once::call_once_force()`]’s closure parameter. The state
+/// can be used to query the poison status of the [`Once`].
+#[stable(feature = "once_poison", since = "1.51.0")]
+pub struct OnceState {
+    pub(crate) inner: sys::OnceState,
+}
+
+pub(crate) enum ExclusiveState {
+    Incomplete,
+    Poisoned,
+    Complete,
+}
+
+/// Initialization value for static [`Once`] values.
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::{Once, ONCE_INIT};
+///
+/// static START: Once = ONCE_INIT;
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(
+    since = "1.38.0",
+    note = "the `Once::new()` function is now preferred",
+    suggestion = "Once::new()"
+)]
+pub const ONCE_INIT: Once = Once::new();
+
+impl Once {
+    /// Creates a new `Once` value.
+    #[inline]
+    #[stable(feature = "once_new", since = "1.2.0")]
+    #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
+    #[must_use]
+    pub const fn new() -> Once {
+        Once { inner: sys::Once::new() }
+    }
+
+    /// Performs an initialization routine once and only once. The given closure
+    /// will be executed if this is the first time `call_once` has been called,
+    /// and otherwise the routine will *not* be invoked.
+    ///
+    /// This method will block the calling thread if another initialization
+    /// routine is currently running.
+    ///
+    /// When this function returns, it is guaranteed that some initialization
+    /// has run and completed (it might not be the closure specified). It is also
+    /// guaranteed that any memory writes performed by the executed closure can
+    /// be reliably observed by other threads at this point (there is a
+    /// happens-before relation between the closure and code executing after the
+    /// return).
+    ///
+    /// If the given closure recursively invokes `call_once` on the same [`Once`]
+    /// instance, the exact behavior is not specified: allowed outcomes are
+    /// a panic or a deadlock.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Once;
+    ///
+    /// static mut VAL: usize = 0;
+    /// static INIT: Once = Once::new();
+    ///
+    /// // Accessing a `static mut` is unsafe much of the time, but if we do so
+    /// // in a synchronized fashion (e.g., write once or read all) then we're
+    /// // good to go!
+    /// //
+    /// // This function will only call `expensive_computation` once, and will
+    /// // otherwise always return the value returned from the first invocation.
+    /// fn get_cached_val() -> usize {
+    ///     unsafe {
+    ///         INIT.call_once(|| {
+    ///             VAL = expensive_computation();
+    ///         });
+    ///         VAL
+    ///     }
+    /// }
+    ///
+    /// fn expensive_computation() -> usize {
+    ///     // ...
+    /// # 2
+    /// }
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// The closure `f` will only be executed once even if this is called
+    /// concurrently amongst many threads. If that closure panics, however, then
+    /// it will *poison* this [`Once`] instance, causing all future invocations of
+    /// `call_once` to also panic.
+    ///
+    /// This is similar to [poisoning with mutexes][poison].
+    ///
+    /// [poison]: struct.Mutex.html#poisoning
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[track_caller]
+    pub fn call_once<F>(&self, f: F)
+    where
+        F: FnOnce(),
+    {
+        // Fast path check
+        if self.inner.is_completed() {
+            return;
+        }
+
+        let mut f = Some(f);
+        self.inner.call(false, &mut |_| f.take().unwrap()());
+    }
+
+    /// Performs the same function as [`call_once()`] except ignores poisoning.
+    ///
+    /// Unlike [`call_once()`], if this [`Once`] has been poisoned (i.e., a previous
+    /// call to [`call_once()`] or [`call_once_force()`] caused a panic), calling
+    /// [`call_once_force()`] will still invoke the closure `f` and will _not_
+    /// result in an immediate panic. If `f` panics, the [`Once`] will remain
+    /// in a poison state. If `f` does _not_ panic, the [`Once`] will no
+    /// longer be in a poison state and all future calls to [`call_once()`] or
+    /// [`call_once_force()`] will be no-ops.
+    ///
+    /// The closure `f` is yielded a [`OnceState`] structure which can be used
+    /// to query the poison status of the [`Once`].
+    ///
+    /// [`call_once()`]: Once::call_once
+    /// [`call_once_force()`]: Once::call_once_force
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Once;
+    /// use std::thread;
+    ///
+    /// static INIT: Once = Once::new();
+    ///
+    /// // poison the once
+    /// let handle = thread::spawn(|| {
+    ///     INIT.call_once(|| panic!());
+    /// });
+    /// assert!(handle.join().is_err());
+    ///
+    /// // poisoning propagates
+    /// let handle = thread::spawn(|| {
+    ///     INIT.call_once(|| {});
+    /// });
+    /// assert!(handle.join().is_err());
+    ///
+    /// // call_once_force will still run and reset the poisoned state
+    /// INIT.call_once_force(|state| {
+    ///     assert!(state.is_poisoned());
+    /// });
+    ///
+    /// // once any success happens, we stop propagating the poison
+    /// INIT.call_once(|| {});
+    /// ```
+    #[inline]
+    #[stable(feature = "once_poison", since = "1.51.0")]
+    pub fn call_once_force<F>(&self, f: F)
+    where
+        F: FnOnce(&OnceState),
+    {
+        // Fast path check
+        if self.inner.is_completed() {
+            return;
+        }
+
+        let mut f = Some(f);
+        self.inner.call(true, &mut |p| f.take().unwrap()(p));
+    }
+
+    /// Returns `true` if some [`call_once()`] call has completed
+    /// successfully. Specifically, `is_completed` will return false in
+    /// the following situations:
+    ///   * [`call_once()`] was not called at all,
+    ///   * [`call_once()`] was called, but has not yet completed,
+    ///   * the [`Once`] instance is poisoned
+    ///
+    /// This function returning `false` does not mean that [`Once`] has not been
+    /// executed. For example, it may have been executed in the time between
+    /// when `is_completed` starts executing and when it returns, in which case
+    /// the `false` return value would be stale (but still permissible).
+    ///
+    /// [`call_once()`]: Once::call_once
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Once;
+    ///
+    /// static INIT: Once = Once::new();
+    ///
+    /// assert_eq!(INIT.is_completed(), false);
+    /// INIT.call_once(|| {
+    ///     assert_eq!(INIT.is_completed(), false);
+    /// });
+    /// assert_eq!(INIT.is_completed(), true);
+    /// ```
+    ///
+    /// ```
+    /// use std::sync::Once;
+    /// use std::thread;
+    ///
+    /// static INIT: Once = Once::new();
+    ///
+    /// assert_eq!(INIT.is_completed(), false);
+    /// let handle = thread::spawn(|| {
+    ///     INIT.call_once(|| panic!());
+    /// });
+    /// assert!(handle.join().is_err());
+    /// assert_eq!(INIT.is_completed(), false);
+    /// ```
+    #[stable(feature = "once_is_completed", since = "1.43.0")]
+    #[inline]
+    pub fn is_completed(&self) -> bool {
+        self.inner.is_completed()
+    }
+
+    /// Blocks the current thread until initialization has completed.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// #![feature(once_wait)]
+    ///
+    /// use std::sync::Once;
+    /// use std::thread;
+    ///
+    /// static READY: Once = Once::new();
+    ///
+    /// let thread = thread::spawn(|| {
+    ///     READY.wait();
+    ///     println!("everything is ready");
+    /// });
+    ///
+    /// READY.call_once(|| println!("performing setup"));
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// If this [`Once`] has been poisoned because an initialization closure has
+    /// panicked, this method will also panic. Use [`wait_force`](Self::wait_force)
+    /// if this behavior is not desired.
+    #[unstable(feature = "once_wait", issue = "127527")]
+    pub fn wait(&self) {
+        if !self.inner.is_completed() {
+            self.inner.wait(false);
+        }
+    }
+
+    /// Blocks the current thread until initialization has completed, ignoring
+    /// poisoning.
+    #[unstable(feature = "once_wait", issue = "127527")]
+    pub fn wait_force(&self) {
+        if !self.inner.is_completed() {
+            self.inner.wait(true);
+        }
+    }
+
+    /// Returns the current state of the `Once` instance.
+    ///
+    /// Since this takes a mutable reference, no initialization can currently
+    /// be running, so the state must be either "incomplete", "poisoned" or
+    /// "complete".
+    #[inline]
+    pub(crate) fn state(&mut self) -> ExclusiveState {
+        self.inner.state()
+    }
+
+    /// Sets current state of the `Once` instance.
+    ///
+    /// Since this takes a mutable reference, no initialization can currently
+    /// be running, so the state must be either "incomplete", "poisoned" or
+    /// "complete".
+    #[inline]
+    pub(crate) fn set_state(&mut self, new_state: ExclusiveState) {
+        self.inner.set_state(new_state);
+    }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Once {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Once").finish_non_exhaustive()
+    }
+}
+
+impl OnceState {
+    /// Returns `true` if the associated [`Once`] was poisoned prior to the
+    /// invocation of the closure passed to [`Once::call_once_force()`].
+    ///
+    /// # Examples
+    ///
+    /// A poisoned [`Once`]:
+    ///
+    /// ```
+    /// use std::sync::Once;
+    /// use std::thread;
+    ///
+    /// static INIT: Once = Once::new();
+    ///
+    /// // poison the once
+    /// let handle = thread::spawn(|| {
+    ///     INIT.call_once(|| panic!());
+    /// });
+    /// assert!(handle.join().is_err());
+    ///
+    /// INIT.call_once_force(|state| {
+    ///     assert!(state.is_poisoned());
+    /// });
+    /// ```
+    ///
+    /// An unpoisoned [`Once`]:
+    ///
+    /// ```
+    /// use std::sync::Once;
+    ///
+    /// static INIT: Once = Once::new();
+    ///
+    /// INIT.call_once_force(|state| {
+    ///     assert!(!state.is_poisoned());
+    /// });
+    #[stable(feature = "once_poison", since = "1.51.0")]
+    #[inline]
+    pub fn is_poisoned(&self) -> bool {
+        self.inner.is_poisoned()
+    }
+
+    /// Poison the associated [`Once`] without explicitly panicking.
+    // NOTE: This is currently only exposed for `OnceLock`.
+    #[inline]
+    pub(crate) fn poison(&self) {
+        self.inner.poison();
+    }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for OnceState {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OnceState").field("poisoned", &self.is_poisoned()).finish()
+    }
+}
diff --git a/library/std/src/sync/poison/once/tests.rs b/library/std/src/sync/poison/once/tests.rs
new file mode 100644
index 00000000000..ce96468aeb6
--- /dev/null
+++ b/library/std/src/sync/poison/once/tests.rs
@@ -0,0 +1,162 @@
+use super::Once;
+use crate::sync::atomic::AtomicBool;
+use crate::sync::atomic::Ordering::Relaxed;
+use crate::sync::mpsc::channel;
+use crate::time::Duration;
+use crate::{panic, thread};
+
+#[test]
+fn smoke_once() {
+    static O: Once = Once::new();
+    let mut a = 0;
+    O.call_once(|| a += 1);
+    assert_eq!(a, 1);
+    O.call_once(|| a += 1);
+    assert_eq!(a, 1);
+}
+
+#[test]
+fn stampede_once() {
+    static O: Once = Once::new();
+    static mut RUN: bool = false;
+
+    let (tx, rx) = channel();
+    for _ in 0..10 {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            for _ in 0..4 {
+                thread::yield_now()
+            }
+            unsafe {
+                O.call_once(|| {
+                    assert!(!RUN);
+                    RUN = true;
+                });
+                assert!(RUN);
+            }
+            tx.send(()).unwrap();
+        });
+    }
+
+    unsafe {
+        O.call_once(|| {
+            assert!(!RUN);
+            RUN = true;
+        });
+        assert!(RUN);
+    }
+
+    for _ in 0..10 {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn poison_bad() {
+    static O: Once = Once::new();
+
+    // poison the once
+    let t = panic::catch_unwind(|| {
+        O.call_once(|| panic!());
+    });
+    assert!(t.is_err());
+
+    // poisoning propagates
+    let t = panic::catch_unwind(|| {
+        O.call_once(|| {});
+    });
+    assert!(t.is_err());
+
+    // we can subvert poisoning, however
+    let mut called = false;
+    O.call_once_force(|p| {
+        called = true;
+        assert!(p.is_poisoned())
+    });
+    assert!(called);
+
+    // once any success happens, we stop propagating the poison
+    O.call_once(|| {});
+}
+
+#[test]
+fn wait_for_force_to_finish() {
+    static O: Once = Once::new();
+
+    // poison the once
+    let t = panic::catch_unwind(|| {
+        O.call_once(|| panic!());
+    });
+    assert!(t.is_err());
+
+    // make sure someone's waiting inside the once via a force
+    let (tx1, rx1) = channel();
+    let (tx2, rx2) = channel();
+    let t1 = thread::spawn(move || {
+        O.call_once_force(|p| {
+            assert!(p.is_poisoned());
+            tx1.send(()).unwrap();
+            rx2.recv().unwrap();
+        });
+    });
+
+    rx1.recv().unwrap();
+
+    // put another waiter on the once
+    let t2 = thread::spawn(|| {
+        let mut called = false;
+        O.call_once(|| {
+            called = true;
+        });
+        assert!(!called);
+    });
+
+    tx2.send(()).unwrap();
+
+    assert!(t1.join().is_ok());
+    assert!(t2.join().is_ok());
+}
+
+#[test]
+fn wait() {
+    for _ in 0..50 {
+        let val = AtomicBool::new(false);
+        let once = Once::new();
+
+        thread::scope(|s| {
+            for _ in 0..4 {
+                s.spawn(|| {
+                    once.wait();
+                    assert!(val.load(Relaxed));
+                });
+            }
+
+            once.call_once(|| val.store(true, Relaxed));
+        });
+    }
+}
+
+#[test]
+fn wait_on_poisoned() {
+    let once = Once::new();
+
+    panic::catch_unwind(|| once.call_once(|| panic!())).unwrap_err();
+    panic::catch_unwind(|| once.wait()).unwrap_err();
+}
+
+#[test]
+fn wait_force_on_poisoned() {
+    let once = Once::new();
+
+    thread::scope(|s| {
+        panic::catch_unwind(|| once.call_once(|| panic!())).unwrap_err();
+
+        s.spawn(|| {
+            thread::sleep(Duration::from_millis(100));
+
+            once.call_once_force(|_| {});
+        });
+
+        once.wait_force();
+    })
+}
diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs
new file mode 100644
index 00000000000..1519baf99a8
--- /dev/null
+++ b/library/std/src/sync/poison/rwlock.rs
@@ -0,0 +1,1205 @@
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
+mod tests;
+
+use crate::cell::UnsafeCell;
+use crate::fmt;
+use crate::marker::PhantomData;
+use crate::mem::{self, ManuallyDrop, forget};
+use crate::ops::{Deref, DerefMut};
+use crate::ptr::NonNull;
+use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison};
+use crate::sys::sync as sys;
+
+/// A reader-writer lock
+///
+/// This type of lock allows a number of readers or at most one writer at any
+/// point in time. The write portion of this lock typically allows modification
+/// of the underlying data (exclusive access) and the read portion of this lock
+/// typically allows for read-only access (shared access).
+///
+/// In comparison, a [`Mutex`] does not distinguish between readers or writers
+/// that acquire the lock, therefore blocking any threads waiting for the lock to
+/// become available. An `RwLock` will allow any number of readers to acquire the
+/// lock as long as a writer is not holding the lock.
+///
+/// The priority policy of the lock is dependent on the underlying operating
+/// system's implementation, and this type does not guarantee that any
+/// particular policy will be used. In particular, a writer which is waiting to
+/// acquire the lock in `write` might or might not block concurrent calls to
+/// `read`, e.g.:
+///
+/// <details><summary>Potential deadlock example</summary>
+///
+/// ```text
+/// // Thread 1              |  // Thread 2
+/// let _rg1 = lock.read();  |
+///                          |  // will block
+///                          |  let _wg = lock.write();
+/// // may deadlock          |
+/// let _rg2 = lock.read();  |
+/// ```
+///
+/// </details>
+///
+/// The type parameter `T` represents the data that this lock protects. It is
+/// required that `T` satisfies [`Send`] to be shared across threads and
+/// [`Sync`] to allow concurrent access through readers. The RAII guards
+/// returned from the locking methods implement [`Deref`] (and [`DerefMut`]
+/// for the `write` methods) to allow access to the content of the lock.
+///
+/// # Poisoning
+///
+/// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however,
+/// that an `RwLock` may only be poisoned if a panic occurs while it is locked
+/// exclusively (write mode). If a panic occurs in any reader, then the lock
+/// will not be poisoned.
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::RwLock;
+///
+/// let lock = RwLock::new(5);
+///
+/// // many reader locks can be held at once
+/// {
+///     let r1 = lock.read().unwrap();
+///     let r2 = lock.read().unwrap();
+///     assert_eq!(*r1, 5);
+///     assert_eq!(*r2, 5);
+/// } // read locks are dropped at this point
+///
+/// // only one write lock may be held, however
+/// {
+///     let mut w = lock.write().unwrap();
+///     *w += 1;
+///     assert_eq!(*w, 6);
+/// } // write lock is dropped here
+/// ```
+///
+/// [`Mutex`]: super::Mutex
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "RwLock")]
+pub struct RwLock<T: ?Sized> {
+    inner: sys::RwLock,
+    poison: poison::Flag,
+    data: UnsafeCell<T>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
+
+/// RAII structure used to release the shared read access of a lock when
+/// dropped.
+///
+/// This structure is created by the [`read`] and [`try_read`] methods on
+/// [`RwLock`].
+///
+/// [`read`]: RwLock::read
+/// [`try_read`]: RwLock::try_read
+#[must_use = "if unused the RwLock will immediately unlock"]
+#[must_not_suspend = "holding a RwLockReadGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Futures to not implement `Send`"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")]
+pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
+    // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
+    // `RwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops.
+    // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
+    // is preferable over `const* T` to allow for niche optimization.
+    data: NonNull<T>,
+    inner_lock: &'a sys::RwLock,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> !Send for RwLockReadGuard<'_, T> {}
+
+#[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
+unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
+
+/// RAII structure used to release the exclusive write access of a lock when
+/// dropped.
+///
+/// This structure is created by the [`write`] and [`try_write`] methods
+/// on [`RwLock`].
+///
+/// [`write`]: RwLock::write
+/// [`try_write`]: RwLock::try_write
+#[must_use = "if unused the RwLock will immediately unlock"]
+#[must_not_suspend = "holding a RwLockWriteGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Future's to not implement `Send`"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockWriteGuard")]
+pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
+    lock: &'a RwLock<T>,
+    poison: poison::Guard,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {}
+
+#[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
+unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {}
+
+/// RAII structure used to release the shared read access of a lock when
+/// dropped, which can point to a subfield of the protected data.
+///
+/// This structure is created by the [`map`] and [`try_map`] methods
+/// on [`RwLockReadGuard`].
+///
+/// [`map`]: RwLockReadGuard::map
+/// [`try_map`]: RwLockReadGuard::try_map
+#[must_use = "if unused the RwLock will immediately unlock"]
+#[must_not_suspend = "holding a MappedRwLockReadGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Futures to not implement `Send`"]
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+#[clippy::has_significant_drop]
+pub struct MappedRwLockReadGuard<'a, T: ?Sized + 'a> {
+    // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
+    // `MappedRwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops.
+    // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
+    // is preferable over `const* T` to allow for niche optimization.
+    data: NonNull<T>,
+    inner_lock: &'a sys::RwLock,
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> !Send for MappedRwLockReadGuard<'_, T> {}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockReadGuard<'_, T> {}
+
+/// RAII structure used to release the exclusive write access of a lock when
+/// dropped, which can point to a subfield of the protected data.
+///
+/// This structure is created by the [`map`] and [`try_map`] methods
+/// on [`RwLockWriteGuard`].
+///
+/// [`map`]: RwLockWriteGuard::map
+/// [`try_map`]: RwLockWriteGuard::try_map
+#[must_use = "if unused the RwLock will immediately unlock"]
+#[must_not_suspend = "holding a MappedRwLockWriteGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Future's to not implement `Send`"]
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+#[clippy::has_significant_drop]
+pub struct MappedRwLockWriteGuard<'a, T: ?Sized + 'a> {
+    // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a
+    // `MappedRwLockWriteGuard` argument doesn't hold uniqueness for its whole scope, only until it drops.
+    // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field
+    // below for the correct variance over `T` (invariance).
+    data: NonNull<T>,
+    inner_lock: &'a sys::RwLock,
+    poison_flag: &'a poison::Flag,
+    poison: poison::Guard,
+    _variance: PhantomData<&'a mut T>,
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> !Send for MappedRwLockWriteGuard<'_, T> {}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockWriteGuard<'_, T> {}
+
+impl<T> RwLock<T> {
+    /// Creates a new instance of an `RwLock<T>` which is unlocked.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::RwLock;
+    ///
+    /// let lock = RwLock::new(5);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+    #[inline]
+    pub const fn new(t: T) -> RwLock<T> {
+        RwLock { inner: sys::RwLock::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
+    }
+
+    /// Returns the contained value by cloning it.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the `RwLock` is poisoned. An
+    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
+    /// lock.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::RwLock;
+    ///
+    /// let mut lock = RwLock::new(7);
+    ///
+    /// assert_eq!(lock.get_cloned().unwrap(), 7);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn get_cloned(&self) -> Result<T, PoisonError<()>>
+    where
+        T: Clone,
+    {
+        match self.read() {
+            Ok(guard) => Ok((*guard).clone()),
+            Err(_) => Err(PoisonError::new(())),
+        }
+    }
+
+    /// Sets the contained value.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error containing the provided `value` if
+    /// the `RwLock` is poisoned. An `RwLock` is poisoned whenever a writer
+    /// panics while holding an exclusive lock.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::RwLock;
+    ///
+    /// let mut lock = RwLock::new(7);
+    ///
+    /// assert_eq!(lock.get_cloned().unwrap(), 7);
+    /// lock.set(11).unwrap();
+    /// assert_eq!(lock.get_cloned().unwrap(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn set(&self, value: T) -> Result<(), PoisonError<T>> {
+        if mem::needs_drop::<T>() {
+            // If the contained value has non-trivial destructor, we
+            // call that destructor after the lock being released.
+            self.replace(value).map(drop)
+        } else {
+            match self.write() {
+                Ok(mut guard) => {
+                    *guard = value;
+
+                    Ok(())
+                }
+                Err(_) => Err(PoisonError::new(value)),
+            }
+        }
+    }
+
+    /// Replaces the contained value with `value`, and returns the old contained value.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error containing the provided `value` if
+    /// the `RwLock` is poisoned. An `RwLock` is poisoned whenever a writer
+    /// panics while holding an exclusive lock.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::RwLock;
+    ///
+    /// let mut lock = RwLock::new(7);
+    ///
+    /// assert_eq!(lock.replace(11).unwrap(), 7);
+    /// assert_eq!(lock.get_cloned().unwrap(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    pub fn replace(&self, value: T) -> LockResult<T> {
+        match self.write() {
+            Ok(mut guard) => Ok(mem::replace(&mut *guard, value)),
+            Err(_) => Err(PoisonError::new(value)),
+        }
+    }
+}
+
+impl<T: ?Sized> RwLock<T> {
+    /// Locks this `RwLock` with shared read access, blocking the current thread
+    /// until it can be acquired.
+    ///
+    /// The calling thread will be blocked until there are no more writers which
+    /// hold the lock. There may be other readers currently inside the lock when
+    /// this method returns. This method does not provide any guarantees with
+    /// respect to the ordering of whether contentious readers or writers will
+    /// acquire the lock first.
+    ///
+    /// Returns an RAII guard which will release this thread's shared access
+    /// once it is dropped.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the `RwLock` is poisoned. An
+    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
+    /// lock. The failure will occur immediately after the lock has been
+    /// acquired. The acquired lock guard will be contained in the returned
+    /// error.
+    ///
+    /// # Panics
+    ///
+    /// This function might panic when called if the lock is already held by the current thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, RwLock};
+    /// use std::thread;
+    ///
+    /// let lock = Arc::new(RwLock::new(1));
+    /// let c_lock = Arc::clone(&lock);
+    ///
+    /// let n = lock.read().unwrap();
+    /// assert_eq!(*n, 1);
+    ///
+    /// thread::spawn(move || {
+    ///     let r = c_lock.read();
+    ///     assert!(r.is_ok());
+    /// }).join().unwrap();
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
+        unsafe {
+            self.inner.read();
+            RwLockReadGuard::new(self)
+        }
+    }
+
+    /// Attempts to acquire this `RwLock` with shared read access.
+    ///
+    /// If the access could not be granted at this time, then `Err` is returned.
+    /// Otherwise, an RAII guard is returned which will release the shared access
+    /// when it is dropped.
+    ///
+    /// This function does not block.
+    ///
+    /// This function does not provide any guarantees with respect to the ordering
+    /// of whether contentious readers or writers will acquire the lock first.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the [`Poisoned`] error if the `RwLock` is
+    /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding
+    /// an exclusive lock. `Poisoned` will only be returned if the lock would
+    /// have otherwise been acquired. An acquired lock guard will be contained
+    /// in the returned error.
+    ///
+    /// This function will return the [`WouldBlock`] error if the `RwLock` could
+    /// not be acquired because it was already locked exclusively.
+    ///
+    /// [`Poisoned`]: TryLockError::Poisoned
+    /// [`WouldBlock`]: TryLockError::WouldBlock
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::RwLock;
+    ///
+    /// let lock = RwLock::new(1);
+    ///
+    /// match lock.try_read() {
+    ///     Ok(n) => assert_eq!(*n, 1),
+    ///     Err(_) => unreachable!(),
+    /// };
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> {
+        unsafe {
+            if self.inner.try_read() {
+                Ok(RwLockReadGuard::new(self)?)
+            } else {
+                Err(TryLockError::WouldBlock)
+            }
+        }
+    }
+
+    /// Locks this `RwLock` with exclusive write access, blocking the current
+    /// thread until it can be acquired.
+    ///
+    /// This function will not return while other writers or other readers
+    /// currently have access to the lock.
+    ///
+    /// Returns an RAII guard which will drop the write access of this `RwLock`
+    /// when dropped.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the `RwLock` is poisoned. An
+    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
+    /// lock. An error will be returned when the lock is acquired. The acquired
+    /// lock guard will be contained in the returned error.
+    ///
+    /// # Panics
+    ///
+    /// This function might panic when called if the lock is already held by the current thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::RwLock;
+    ///
+    /// let lock = RwLock::new(1);
+    ///
+    /// let mut n = lock.write().unwrap();
+    /// *n = 2;
+    ///
+    /// assert!(lock.try_read().is_err());
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
+        unsafe {
+            self.inner.write();
+            RwLockWriteGuard::new(self)
+        }
+    }
+
+    /// Attempts to lock this `RwLock` with exclusive write access.
+    ///
+    /// If the lock could not be acquired at this time, then `Err` is returned.
+    /// Otherwise, an RAII guard is returned which will release the lock when
+    /// it is dropped.
+    ///
+    /// This function does not block.
+    ///
+    /// This function does not provide any guarantees with respect to the ordering
+    /// of whether contentious readers or writers will acquire the lock first.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the [`Poisoned`] error if the `RwLock` is
+    /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding
+    /// an exclusive lock. `Poisoned` will only be returned if the lock would
+    /// have otherwise been acquired. An acquired lock guard will be contained
+    /// in the returned error.
+    ///
+    /// This function will return the [`WouldBlock`] error if the `RwLock` could
+    /// not be acquired because it was already locked exclusively.
+    ///
+    /// [`Poisoned`]: TryLockError::Poisoned
+    /// [`WouldBlock`]: TryLockError::WouldBlock
+    ///
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::RwLock;
+    ///
+    /// let lock = RwLock::new(1);
+    ///
+    /// let n = lock.read().unwrap();
+    /// assert_eq!(*n, 1);
+    ///
+    /// assert!(lock.try_write().is_err());
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> {
+        unsafe {
+            if self.inner.try_write() {
+                Ok(RwLockWriteGuard::new(self)?)
+            } else {
+                Err(TryLockError::WouldBlock)
+            }
+        }
+    }
+
+    /// Determines whether the lock is poisoned.
+    ///
+    /// If another thread is active, the lock can still become poisoned at any
+    /// time. You should not trust a `false` value for program correctness
+    /// without additional synchronization.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, RwLock};
+    /// use std::thread;
+    ///
+    /// let lock = Arc::new(RwLock::new(0));
+    /// let c_lock = Arc::clone(&lock);
+    ///
+    /// let _ = thread::spawn(move || {
+    ///     let _lock = c_lock.write().unwrap();
+    ///     panic!(); // the lock gets poisoned
+    /// }).join();
+    /// assert_eq!(lock.is_poisoned(), true);
+    /// ```
+    #[inline]
+    #[stable(feature = "sync_poison", since = "1.2.0")]
+    pub fn is_poisoned(&self) -> bool {
+        self.poison.get()
+    }
+
+    /// Clear the poisoned state from a lock.
+    ///
+    /// If the lock is poisoned, it will remain poisoned until this function is called. This allows
+    /// recovering from a poisoned state and marking that it has recovered. For example, if the
+    /// value is overwritten by a known-good value, then the lock can be marked as un-poisoned. Or
+    /// possibly, the value could be inspected to determine if it is in a consistent state, and if
+    /// so the poison is removed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, RwLock};
+    /// use std::thread;
+    ///
+    /// let lock = Arc::new(RwLock::new(0));
+    /// let c_lock = Arc::clone(&lock);
+    ///
+    /// let _ = thread::spawn(move || {
+    ///     let _lock = c_lock.write().unwrap();
+    ///     panic!(); // the lock gets poisoned
+    /// }).join();
+    ///
+    /// assert_eq!(lock.is_poisoned(), true);
+    /// let guard = lock.write().unwrap_or_else(|mut e| {
+    ///     **e.get_mut() = 1;
+    ///     lock.clear_poison();
+    ///     e.into_inner()
+    /// });
+    /// assert_eq!(lock.is_poisoned(), false);
+    /// assert_eq!(*guard, 1);
+    /// ```
+    #[inline]
+    #[stable(feature = "mutex_unpoison", since = "1.77.0")]
+    pub fn clear_poison(&self) {
+        self.poison.clear();
+    }
+
+    /// Consumes this `RwLock`, returning the underlying data.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error containing the underlying data if
+    /// the `RwLock` is poisoned. An `RwLock` is poisoned whenever a writer
+    /// panics while holding an exclusive lock. An error will only be returned
+    /// if the lock would have otherwise been acquired.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::RwLock;
+    ///
+    /// let lock = RwLock::new(String::new());
+    /// {
+    ///     let mut s = lock.write().unwrap();
+    ///     *s = "modified".to_owned();
+    /// }
+    /// assert_eq!(lock.into_inner().unwrap(), "modified");
+    /// ```
+    #[stable(feature = "rwlock_into_inner", since = "1.6.0")]
+    pub fn into_inner(self) -> LockResult<T>
+    where
+        T: Sized,
+    {
+        let data = self.data.into_inner();
+        poison::map_result(self.poison.borrow(), |()| data)
+    }
+
+    /// Returns a mutable reference to the underlying data.
+    ///
+    /// Since this call borrows the `RwLock` mutably, no actual locking needs to
+    /// take place -- the mutable borrow statically guarantees no locks exist.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error containing a mutable reference to
+    /// the underlying data if the `RwLock` is poisoned. An `RwLock` is
+    /// poisoned whenever a writer panics while holding an exclusive lock.
+    /// An error will only be returned if the lock would have otherwise been
+    /// acquired.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::RwLock;
+    ///
+    /// let mut lock = RwLock::new(0);
+    /// *lock.get_mut().unwrap() = 10;
+    /// assert_eq!(*lock.read().unwrap(), 10);
+    /// ```
+    #[stable(feature = "rwlock_get_mut", since = "1.6.0")]
+    pub fn get_mut(&mut self) -> LockResult<&mut T> {
+        let data = self.data.get_mut();
+        poison::map_result(self.poison.borrow(), |()| data)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut d = f.debug_struct("RwLock");
+        match self.try_read() {
+            Ok(guard) => {
+                d.field("data", &&*guard);
+            }
+            Err(TryLockError::Poisoned(err)) => {
+                d.field("data", &&**err.get_ref());
+            }
+            Err(TryLockError::WouldBlock) => {
+                d.field("data", &format_args!("<locked>"));
+            }
+        }
+        d.field("poisoned", &self.poison.get());
+        d.finish_non_exhaustive()
+    }
+}
+
+#[stable(feature = "rw_lock_default", since = "1.10.0")]
+impl<T: Default> Default for RwLock<T> {
+    /// Creates a new `RwLock<T>`, with the `Default` value for T.
+    fn default() -> RwLock<T> {
+        RwLock::new(Default::default())
+    }
+}
+
+#[stable(feature = "rw_lock_from", since = "1.24.0")]
+impl<T> From<T> for RwLock<T> {
+    /// Creates a new instance of an `RwLock<T>` which is unlocked.
+    /// This is equivalent to [`RwLock::new`].
+    fn from(t: T) -> Self {
+        RwLock::new(t)
+    }
+}
+
+impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
+    /// Creates a new instance of `RwLockReadGuard<T>` from a `RwLock<T>`.
+    ///
+    /// # Safety
+    ///
+    /// This function is safe if and only if the same thread has successfully and safely called
+    /// `lock.inner.read()`, `lock.inner.try_read()`, or `lock.inner.downgrade()` before
+    /// instantiating this object.
+    unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> {
+        poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard {
+            data: unsafe { NonNull::new_unchecked(lock.data.get()) },
+            inner_lock: &lock.inner,
+        })
+    }
+}
+
+impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
+    /// Creates a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`.
+    // SAFETY: if and only if `lock.inner.write()` (or `lock.inner.try_write()`) has been
+    // successfully called from the same thread before instantiating this object.
+    unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> {
+        poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard })
+    }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[stable(feature = "std_guard_impls", since = "1.20.0")]
+impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[stable(feature = "std_guard_impls", since = "1.20.0")]
+impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created.
+        unsafe { self.data.as_ref() }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created.
+        unsafe { &*self.lock.data.get() }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created.
+        unsafe { &mut *self.lock.data.get() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe { self.data.as_ref() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe { self.data.as_ref() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe { self.data.as_mut() }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created.
+        unsafe {
+            self.inner_lock.read_unlock();
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
+    fn drop(&mut self) {
+        self.lock.poison.done(&self.poison);
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created.
+        unsafe {
+            self.lock.inner.write_unlock();
+        }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe {
+            self.inner_lock.read_unlock();
+        }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> {
+    fn drop(&mut self) {
+        self.poison_flag.done(&self.poison);
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe {
+            self.inner_lock.write_unlock();
+        }
+    }
+}
+
+impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
+    /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `RwLock` is already locked for reading, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `RwLockReadGuard::map(...)`. A method would interfere with methods of
+    /// the same name on the contents of the `RwLockReadGuard` used through
+    /// `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U>
+    where
+        F: FnOnce(&T) -> &U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { orig.data.as_ref() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }
+    }
+
+    /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RwLock` is already locked for reading, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `RwLockReadGuard::try_map(...)`. A method would interfere with methods
+    /// of the same name on the contents of the `RwLockReadGuard` used through
+    /// `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self>
+    where
+        F: FnOnce(&T) -> Option<&U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { orig.data.as_ref() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock })
+            }
+            None => Err(orig),
+        }
+    }
+}
+
+impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> {
+    /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data,
+    /// e.g. an enum variant.
+    ///
+    /// The `RwLock` is already locked for reading, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedRwLockReadGuard::map(...)`. A method would interfere with
+    /// methods of the same name on the contents of the `MappedRwLockReadGuard`
+    /// used through `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U>
+    where
+        F: FnOnce(&T) -> &U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { orig.data.as_ref() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }
+    }
+
+    /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data.
+    /// The original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RwLock` is already locked for reading, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedRwLockReadGuard::try_map(...)`. A method would interfere with
+    /// methods of the same name on the contents of the `MappedRwLockReadGuard`
+    /// used through `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self>
+    where
+        F: FnOnce(&T) -> Option<&U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { orig.data.as_ref() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock })
+            }
+            None => Err(orig),
+        }
+    }
+}
+
+impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> {
+    /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `RwLock` is already locked for writing, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `RwLockWriteGuard::map(...)`. A method would interfere with methods of
+    /// the same name on the contents of the `RwLockWriteGuard` used through
+    /// `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedRwLockWriteGuard {
+            data,
+            inner_lock: &orig.lock.inner,
+            poison_flag: &orig.lock.poison,
+            poison: orig.poison.clone(),
+            _variance: PhantomData,
+        }
+    }
+
+    /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RwLock` is already locked for writing, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `RwLockWriteGuard::try_map(...)`. A method would interfere with methods
+    /// of the same name on the contents of the `RwLockWriteGuard` used through
+    /// `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { &mut *orig.lock.data.get() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedRwLockWriteGuard {
+                    data,
+                    inner_lock: &orig.lock.inner,
+                    poison_flag: &orig.lock.poison,
+                    poison: orig.poison.clone(),
+                    _variance: PhantomData,
+                })
+            }
+            None => Err(orig),
+        }
+    }
+
+    /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`].
+    ///
+    /// This method will atomically change the state of the [`RwLock`] from exclusive mode into
+    /// shared mode. This means that it is impossible for a writing thread to get in between a
+    /// thread calling `downgrade` and the same thread reading whatever it wrote while it had the
+    /// [`RwLock`] in write mode.
+    ///
+    /// Note that since we have the `RwLockWriteGuard`, we know that the [`RwLock`] is already
+    /// locked for writing, so this method cannot fail.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(rwlock_downgrade)]
+    /// use std::sync::{Arc, RwLock, RwLockWriteGuard};
+    ///
+    /// // The inner value starts as 0.
+    /// let rw = Arc::new(RwLock::new(0));
+    ///
+    /// // Put the lock in write mode.
+    /// let mut main_write_guard = rw.write().unwrap();
+    ///
+    /// let evil = rw.clone();
+    /// let handle = std::thread::spawn(move || {
+    ///     // This will not return until the main thread drops the `main_read_guard`.
+    ///     let mut evil_guard = evil.write().unwrap();
+    ///
+    ///     assert_eq!(*evil_guard, 1);
+    ///     *evil_guard = 2;
+    /// });
+    ///
+    /// // After spawning the writer thread, set the inner value to 1.
+    /// *main_write_guard = 1;
+    ///
+    /// // Atomically downgrade the write guard into a read guard.
+    /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard);
+    ///
+    /// // Since `downgrade` is atomic, the writer thread cannot have set the inner value to 2.
+    /// assert_eq!(*main_read_guard, 1, "`downgrade` was not atomic");
+    ///
+    /// // Clean up everything now
+    /// drop(main_read_guard);
+    /// handle.join().unwrap();
+    ///
+    /// let final_check = rw.read().unwrap();
+    /// assert_eq!(*final_check, 2);
+    /// ```
+    #[unstable(feature = "rwlock_downgrade", issue = "128203")]
+    pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> {
+        let lock = s.lock;
+
+        // We don't want to call the destructor since that calls `write_unlock`.
+        forget(s);
+
+        // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write
+        // mode, satisfying the `downgrade` contract.
+        unsafe { lock.inner.downgrade() };
+
+        // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract.
+        unsafe { RwLockReadGuard::new(lock).unwrap_or_else(PoisonError::into_inner) }
+    }
+}
+
+impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> {
+    /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data,
+    /// e.g. an enum variant.
+    ///
+    /// The `RwLock` is already locked for writing, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedRwLockWriteGuard::map(...)`. A method would interfere with
+    /// methods of the same name on the contents of the `MappedRwLockWriteGuard`
+    /// used through `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(mut orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedRwLockWriteGuard {
+            data,
+            inner_lock: orig.inner_lock,
+            poison_flag: orig.poison_flag,
+            poison: orig.poison.clone(),
+            _variance: PhantomData,
+        }
+    }
+
+    /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data.
+    /// The original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RwLock` is already locked for writing, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedRwLockWriteGuard::try_map(...)`. A method would interfere with
+    /// methods of the same name on the contents of the `MappedRwLockWriteGuard`
+    /// used through `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { orig.data.as_mut() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedRwLockWriteGuard {
+                    data,
+                    inner_lock: orig.inner_lock,
+                    poison_flag: orig.poison_flag,
+                    poison: orig.poison.clone(),
+                    _variance: PhantomData,
+                })
+            }
+            None => Err(orig),
+        }
+    }
+}
diff --git a/library/std/src/sync/poison/rwlock/tests.rs b/library/std/src/sync/poison/rwlock/tests.rs
new file mode 100644
index 00000000000..057c2f1a5d7
--- /dev/null
+++ b/library/std/src/sync/poison/rwlock/tests.rs
@@ -0,0 +1,729 @@
+use rand::Rng;
+
+use crate::fmt::Debug;
+use crate::ops::FnMut;
+use crate::panic::{self, AssertUnwindSafe};
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::mpsc::channel;
+use crate::sync::{
+    Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
+    TryLockError,
+};
+use crate::{hint, mem, thread};
+
+#[derive(Eq, PartialEq, Debug)]
+struct NonCopy(i32);
+
+#[derive(Eq, PartialEq, Debug)]
+struct NonCopyNeedsDrop(i32);
+
+impl Drop for NonCopyNeedsDrop {
+    fn drop(&mut self) {
+        hint::black_box(());
+    }
+}
+
+#[test]
+fn test_needs_drop() {
+    assert!(!mem::needs_drop::<NonCopy>());
+    assert!(mem::needs_drop::<NonCopyNeedsDrop>());
+}
+
+#[derive(Clone, Eq, PartialEq, Debug)]
+struct Cloneable(i32);
+
+#[test]
+fn smoke() {
+    let l = RwLock::new(());
+    drop(l.read().unwrap());
+    drop(l.write().unwrap());
+    drop((l.read().unwrap(), l.read().unwrap()));
+    drop(l.write().unwrap());
+}
+
+#[test]
+// FIXME: On macOS we use a provenance-incorrect implementation and Miri
+// catches that issue with a chance of around 1/1000.
+// See <https://github.com/rust-lang/rust/issues/121950> for details.
+#[cfg_attr(all(miri, target_os = "macos"), ignore)]
+fn frob() {
+    const N: u32 = 10;
+    const M: usize = if cfg!(miri) { 100 } else { 1000 };
+
+    let r = Arc::new(RwLock::new(()));
+
+    let (tx, rx) = channel::<()>();
+    for _ in 0..N {
+        let tx = tx.clone();
+        let r = r.clone();
+        thread::spawn(move || {
+            let mut rng = crate::test_helpers::test_rng();
+            for _ in 0..M {
+                if rng.gen_bool(1.0 / (N as f64)) {
+                    drop(r.write().unwrap());
+                } else {
+                    drop(r.read().unwrap());
+                }
+            }
+            drop(tx);
+        });
+    }
+    drop(tx);
+    let _ = rx.recv();
+}
+
+#[test]
+fn test_rw_arc_poison_wr() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let _lock = arc2.write().unwrap();
+        panic!();
+    })
+    .join();
+    assert!(arc.read().is_err());
+}
+
+#[test]
+fn test_rw_arc_poison_mapped_w_r() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let lock = arc2.write().unwrap();
+        let _lock = RwLockWriteGuard::map(lock, |val| val);
+        panic!();
+    })
+    .join();
+    assert!(arc.read().is_err());
+}
+
+#[test]
+fn test_rw_arc_poison_ww() {
+    let arc = Arc::new(RwLock::new(1));
+    assert!(!arc.is_poisoned());
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let _lock = arc2.write().unwrap();
+        panic!();
+    })
+    .join();
+    assert!(arc.write().is_err());
+    assert!(arc.is_poisoned());
+}
+
+#[test]
+fn test_rw_arc_poison_mapped_w_w() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let lock = arc2.write().unwrap();
+        let _lock = RwLockWriteGuard::map(lock, |val| val);
+        panic!();
+    })
+    .join();
+    assert!(arc.write().is_err());
+    assert!(arc.is_poisoned());
+}
+
+#[test]
+fn test_rw_arc_no_poison_rr() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let _lock = arc2.read().unwrap();
+        panic!();
+    })
+    .join();
+    let lock = arc.read().unwrap();
+    assert_eq!(*lock, 1);
+}
+
+#[test]
+fn test_rw_arc_no_poison_mapped_r_r() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let lock = arc2.read().unwrap();
+        let _lock = RwLockReadGuard::map(lock, |val| val);
+        panic!();
+    })
+    .join();
+    let lock = arc.read().unwrap();
+    assert_eq!(*lock, 1);
+}
+
+#[test]
+fn test_rw_arc_no_poison_rw() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let _lock = arc2.read().unwrap();
+        panic!()
+    })
+    .join();
+    let lock = arc.write().unwrap();
+    assert_eq!(*lock, 1);
+}
+
+#[test]
+fn test_rw_arc_no_poison_mapped_r_w() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let lock = arc2.read().unwrap();
+        let _lock = RwLockReadGuard::map(lock, |val| val);
+        panic!();
+    })
+    .join();
+    let lock = arc.write().unwrap();
+    assert_eq!(*lock, 1);
+}
+
+#[test]
+fn test_rw_arc() {
+    let arc = Arc::new(RwLock::new(0));
+    let arc2 = arc.clone();
+    let (tx, rx) = channel();
+
+    thread::spawn(move || {
+        let mut lock = arc2.write().unwrap();
+        for _ in 0..10 {
+            let tmp = *lock;
+            *lock = -1;
+            thread::yield_now();
+            *lock = tmp + 1;
+        }
+        tx.send(()).unwrap();
+    });
+
+    // Readers try to catch the writer in the act
+    let mut children = Vec::new();
+    for _ in 0..5 {
+        let arc3 = arc.clone();
+        children.push(thread::spawn(move || {
+            let lock = arc3.read().unwrap();
+            assert!(*lock >= 0);
+        }));
+    }
+
+    // Wait for children to pass their asserts
+    for r in children {
+        assert!(r.join().is_ok());
+    }
+
+    // Wait for writer to finish
+    rx.recv().unwrap();
+    let lock = arc.read().unwrap();
+    assert_eq!(*lock, 10);
+}
+
+#[test]
+fn test_rw_arc_access_in_unwind() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _ = thread::spawn(move || -> () {
+        struct Unwinder {
+            i: Arc<RwLock<isize>>,
+        }
+        impl Drop for Unwinder {
+            fn drop(&mut self) {
+                let mut lock = self.i.write().unwrap();
+                *lock += 1;
+            }
+        }
+        let _u = Unwinder { i: arc2 };
+        panic!();
+    })
+    .join();
+    let lock = arc.read().unwrap();
+    assert_eq!(*lock, 2);
+}
+
+#[test]
+fn test_rwlock_unsized() {
+    let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
+    {
+        let b = &mut *rw.write().unwrap();
+        b[0] = 4;
+        b[2] = 5;
+    }
+    let comp: &[i32] = &[4, 2, 5];
+    assert_eq!(&*rw.read().unwrap(), comp);
+}
+
+#[test]
+fn test_rwlock_try_write() {
+    let lock = RwLock::new(0isize);
+    let read_guard = lock.read().unwrap();
+
+    let write_result = lock.try_write();
+    match write_result {
+        Err(TryLockError::WouldBlock) => (),
+        Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"),
+        Err(_) => assert!(false, "unexpected error"),
+    }
+
+    drop(read_guard);
+    let mapped_read_guard = RwLockReadGuard::map(lock.read().unwrap(), |_| &());
+
+    let write_result = lock.try_write();
+    match write_result {
+        Err(TryLockError::WouldBlock) => (),
+        Ok(_) => assert!(false, "try_write should not succeed while mapped_read_guard is in scope"),
+        Err(_) => assert!(false, "unexpected error"),
+    }
+
+    drop(mapped_read_guard);
+}
+
+fn new_poisoned_rwlock<T>(value: T) -> RwLock<T> {
+    let lock = RwLock::new(value);
+
+    let catch_unwind_result = panic::catch_unwind(AssertUnwindSafe(|| {
+        let _guard = lock.write().unwrap();
+
+        panic!("test panic to poison RwLock");
+    }));
+
+    assert!(catch_unwind_result.is_err());
+    assert!(lock.is_poisoned());
+
+    lock
+}
+
+#[test]
+fn test_into_inner() {
+    let m = RwLock::new(NonCopy(10));
+    assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+}
+
+#[test]
+fn test_into_inner_drop() {
+    struct Foo(Arc<AtomicUsize>);
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            self.0.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+    let num_drops = Arc::new(AtomicUsize::new(0));
+    let m = RwLock::new(Foo(num_drops.clone()));
+    assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+    {
+        let _inner = m.into_inner().unwrap();
+        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+    }
+    assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+}
+
+#[test]
+fn test_into_inner_poison() {
+    let m = new_poisoned_rwlock(NonCopy(10));
+
+    match m.into_inner() {
+        Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+        Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {x:?}"),
+    }
+}
+
+#[test]
+fn test_get_cloned() {
+    let m = RwLock::new(Cloneable(10));
+
+    assert_eq!(m.get_cloned().unwrap(), Cloneable(10));
+}
+
+#[test]
+fn test_get_cloned_poison() {
+    let m = new_poisoned_rwlock(Cloneable(10));
+
+    match m.get_cloned() {
+        Err(e) => assert_eq!(e.into_inner(), ()),
+        Ok(x) => panic!("get of poisoned RwLock is Ok: {x:?}"),
+    }
+}
+
+#[test]
+fn test_get_mut() {
+    let mut m = RwLock::new(NonCopy(10));
+    *m.get_mut().unwrap() = NonCopy(20);
+    assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+}
+
+#[test]
+fn test_get_mut_poison() {
+    let mut m = new_poisoned_rwlock(NonCopy(10));
+
+    match m.get_mut() {
+        Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+        Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"),
+    }
+}
+
+#[test]
+fn test_set() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = RwLock::new(init());
+
+        assert_eq!(*m.read().unwrap(), init());
+        m.set(value()).unwrap();
+        assert_eq!(*m.read().unwrap(), value());
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_set_poison() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = new_poisoned_rwlock(init());
+
+        match m.set(value()) {
+            Err(e) => {
+                assert_eq!(e.into_inner(), value());
+                assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
+            }
+            Ok(x) => panic!("set of poisoned RwLock is Ok: {x:?}"),
+        }
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_replace() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = RwLock::new(init());
+
+        assert_eq!(*m.read().unwrap(), init());
+        assert_eq!(m.replace(value()).unwrap(), init());
+        assert_eq!(*m.read().unwrap(), value());
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_replace_poison() {
+    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+    where
+        T: Debug + Eq,
+    {
+        let m = new_poisoned_rwlock(init());
+
+        match m.replace(value()) {
+            Err(e) => {
+                assert_eq!(e.into_inner(), value());
+                assert_eq!(m.into_inner().unwrap_err().into_inner(), init());
+            }
+            Ok(x) => panic!("replace of poisoned RwLock is Ok: {x:?}"),
+        }
+    }
+
+    inner(|| NonCopy(10), || NonCopy(20));
+    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+}
+
+#[test]
+fn test_read_guard_covariance() {
+    fn do_stuff<'a>(_: RwLockReadGuard<'_, &'a i32>, _: &'a i32) {}
+    let j: i32 = 5;
+    let lock = RwLock::new(&j);
+    {
+        let i = 6;
+        do_stuff(lock.read().unwrap(), &i);
+    }
+    drop(lock);
+}
+
+#[test]
+fn test_mapped_read_guard_covariance() {
+    fn do_stuff<'a>(_: MappedRwLockReadGuard<'_, &'a i32>, _: &'a i32) {}
+    let j: i32 = 5;
+    let lock = RwLock::new((&j, &j));
+    {
+        let i = 6;
+        let guard = lock.read().unwrap();
+        let guard = RwLockReadGuard::map(guard, |(val, _val)| val);
+        do_stuff(guard, &i);
+    }
+    drop(lock);
+}
+
+#[test]
+fn test_mapping_mapped_guard() {
+    let arr = [0; 4];
+    let mut lock = RwLock::new(arr);
+    let guard = lock.write().unwrap();
+    let guard = RwLockWriteGuard::map(guard, |arr| &mut arr[..2]);
+    let mut guard = MappedRwLockWriteGuard::map(guard, |slice| &mut slice[1..]);
+    assert_eq!(guard.len(), 1);
+    guard[0] = 42;
+    drop(guard);
+    assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
+
+    let guard = lock.read().unwrap();
+    let guard = RwLockReadGuard::map(guard, |arr| &arr[..2]);
+    let guard = MappedRwLockReadGuard::map(guard, |slice| &slice[1..]);
+    assert_eq!(*guard, [42]);
+    drop(guard);
+    assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
+}
+
+#[test]
+fn panic_while_mapping_read_unlocked_no_poison() {
+    let lock = RwLock::new(());
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.read().unwrap();
+        let _guard = RwLockReadGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {}
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a RwLockReadGuard::map closure should release the read lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {
+            panic!("panicking in a RwLockReadGuard::map closure should not poison the RwLock")
+        }
+    }
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.read().unwrap();
+        let _guard = RwLockReadGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {}
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a RwLockReadGuard::try_map closure should release the read lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {
+            panic!("panicking in a RwLockReadGuard::try_map closure should not poison the RwLock")
+        }
+    }
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.read().unwrap();
+        let guard = RwLockReadGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedRwLockReadGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {}
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MappedRwLockReadGuard::map closure should release the read lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {
+            panic!("panicking in a MappedRwLockReadGuard::map closure should not poison the RwLock")
+        }
+    }
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.read().unwrap();
+        let guard = RwLockReadGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedRwLockReadGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {}
+        Err(TryLockError::WouldBlock) => panic!(
+            "panicking in a MappedRwLockReadGuard::try_map closure should release the read lock"
+        ),
+        Err(TryLockError::Poisoned(_)) => panic!(
+            "panicking in a MappedRwLockReadGuard::try_map closure should not poison the RwLock"
+        ),
+    }
+
+    drop(lock);
+}
+
+#[test]
+fn panic_while_mapping_write_unlocked_poison() {
+    let lock = RwLock::new(());
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.write().unwrap();
+        let _guard = RwLockWriteGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => panic!("panicking in a RwLockWriteGuard::map closure should poison the RwLock"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a RwLockWriteGuard::map closure should release the write lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.write().unwrap();
+        let _guard = RwLockWriteGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {
+            panic!("panicking in a RwLockWriteGuard::try_map closure should poison the RwLock")
+        }
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a RwLockWriteGuard::try_map closure should release the write lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.write().unwrap();
+        let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedRwLockWriteGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {
+            panic!("panicking in a MappedRwLockWriteGuard::map closure should poison the RwLock")
+        }
+        Err(TryLockError::WouldBlock) => panic!(
+            "panicking in a MappedRwLockWriteGuard::map closure should release the write lock"
+        ),
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = panic::catch_unwind(|| {
+        let guard = lock.write().unwrap();
+        let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedRwLockWriteGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => panic!(
+            "panicking in a MappedRwLockWriteGuard::try_map closure should poison the RwLock"
+        ),
+        Err(TryLockError::WouldBlock) => panic!(
+            "panicking in a MappedRwLockWriteGuard::try_map closure should release the write lock"
+        ),
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    drop(lock);
+}
+
+#[test]
+fn test_downgrade_basic() {
+    let r = RwLock::new(());
+
+    let write_guard = r.write().unwrap();
+    let _read_guard = RwLockWriteGuard::downgrade(write_guard);
+}
+
+#[test]
+// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
+// See <https://github.com/rust-lang/rust/issues/121950> for details.
+#[cfg_attr(all(miri, target_os = "macos"), ignore)]
+fn test_downgrade_observe() {
+    // Taken from the test `test_rwlock_downgrade` from:
+    // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs
+
+    const W: usize = 20;
+    const N: usize = if cfg!(miri) { 40 } else { 100 };
+
+    // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring
+    // that the value they wrote has not changed after downgrading.
+
+    let rw = Arc::new(RwLock::new(0));
+
+    // Spawn the writers that will do `W * N` operations and checks.
+    let handles: Vec<_> = (0..W)
+        .map(|_| {
+            let rw = rw.clone();
+            thread::spawn(move || {
+                for _ in 0..N {
+                    // Increment the counter.
+                    let mut write_guard = rw.write().unwrap();
+                    *write_guard += 1;
+                    let cur_val = *write_guard;
+
+                    // Downgrade the lock to read mode, where the value protected cannot be modified.
+                    let read_guard = RwLockWriteGuard::downgrade(write_guard);
+                    assert_eq!(cur_val, *read_guard);
+                }
+            })
+        })
+        .collect();
+
+    for handle in handles {
+        handle.join().unwrap();
+    }
+
+    assert_eq!(*rw.read().unwrap(), W * N);
+}
+
+#[test]
+// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
+// See <https://github.com/rust-lang/rust/issues/121950> for details.
+#[cfg_attr(all(miri, target_os = "macos"), ignore)]
+fn test_downgrade_atomic() {
+    const NEW_VALUE: i32 = -1;
+
+    // This test checks that `downgrade` is atomic, meaning as soon as a write lock has been
+    // downgraded, the lock must be in read mode and no other threads can take the write lock to
+    // modify the protected value.
+
+    // `W` is the number of evil writer threads.
+    const W: usize = 20;
+    let rwlock = Arc::new(RwLock::new(0));
+
+    // Spawns many evil writer threads that will try and write to the locked value before the
+    // initial writer (who has the exclusive lock) can read after it downgrades.
+    // If the `RwLock` behaves correctly, then the initial writer should read the value it wrote
+    // itself as no other thread should be able to mutate the protected value.
+
+    // Put the lock in write mode, causing all future threads trying to access this go to sleep.
+    let mut main_write_guard = rwlock.write().unwrap();
+
+    // Spawn all of the evil writer threads. They will each increment the protected value by 1.
+    let handles: Vec<_> = (0..W)
+        .map(|_| {
+            let rwlock = rwlock.clone();
+            thread::spawn(move || {
+                // Will go to sleep since the main thread initially has the write lock.
+                let mut evil_guard = rwlock.write().unwrap();
+                *evil_guard += 1;
+            })
+        })
+        .collect();
+
+    // Wait for a good amount of time so that evil threads go to sleep.
+    // Note: this is not strictly necessary...
+    let eternity = crate::time::Duration::from_millis(42);
+    thread::sleep(eternity);
+
+    // Once everyone is asleep, set the value to `NEW_VALUE`.
+    *main_write_guard = NEW_VALUE;
+
+    // Atomically downgrade the write guard into a read guard.
+    let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard);
+
+    // If the above is not atomic, then it would be possible for an evil thread to get in front of
+    // this read and change the value to be non-negative.
+    assert_eq!(*main_read_guard, NEW_VALUE, "`downgrade` was not atomic");
+
+    // Drop the main read guard and allow the evil writer threads to start incrementing.
+    drop(main_read_guard);
+
+    for handle in handles {
+        handle.join().unwrap();
+    }
+
+    let final_check = rwlock.read().unwrap();
+    assert_eq!(*final_check, W as i32 + NEW_VALUE);
+}