about summary refs log tree commit diff
path: root/library/std/src/sync
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-20 08:06:56 +0000
committerbors <bors@rust-lang.org>2022-05-20 08:06:56 +0000
commitcd73afadae5b0163f9285f1b5edbbd1c84fde410 (patch)
tree30c8e0091223a6c54e9623f38ef220430b03de7d /library/std/src/sync
parent52cc7795245347500ddf6dc959cf58a7abe2d935 (diff)
parenta65afd82d1020f15d347268c077d4b7220268abc (diff)
downloadrust-cd73afadae5b0163f9285f1b5edbbd1c84fde410.tar.gz
rust-cd73afadae5b0163f9285f1b5edbbd1c84fde410.zip
Auto merge of #96422 - tmccombs:mutex-unpoison, r=m-ou-se
Add functions to un-poison Mutex and RwLock

See discussion at https://internals.rust-lang.org/t/unpoisoning-a-mutex/16521/3
Diffstat (limited to 'library/std/src/sync')
-rw-r--r--library/std/src/sync/mutex.rs39
-rw-r--r--library/std/src/sync/poison.rs5
-rw-r--r--library/std/src/sync/rwlock.rs39
3 files changed, 83 insertions, 0 deletions
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index aacc893ba06..3d8281fe593 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -364,6 +364,45 @@ impl<T: ?Sized> Mutex<T> {
         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
+    ///
+    /// ```
+    /// #![feature(mutex_unpoison)]
+    ///
+    /// 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]
+    #[unstable(feature = "mutex_unpoison", issue = "96469")]
+    pub fn clear_poison(&self) {
+        self.poison.clear();
+    }
+
     /// Consumes this mutex, returning the underlying data.
     ///
     /// # Errors
diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs
index 07a90da449c..ba91fb0499f 100644
--- a/library/std/src/sync/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -40,6 +40,11 @@ impl Flag {
     pub fn get(&self) -> bool {
         self.failed.load(Ordering::Relaxed)
     }
+
+    #[inline]
+    pub fn clear(&self) {
+        self.failed.store(false, Ordering::Relaxed)
+    }
 }
 
 pub struct Guard {
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 9ec0903f037..4f1b4bedaab 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -368,6 +368,45 @@ impl<T: ?Sized> RwLock<T> {
         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 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
+    ///
+    /// ```
+    /// #![feature(mutex_unpoison)]
+    ///
+    /// 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 mutex 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]
+    #[unstable(feature = "mutex_unpoison", issue = "96469")]
+    pub fn clear_poison(&self) {
+        self.poison.clear();
+    }
+
     /// Consumes this `RwLock`, returning the underlying data.
     ///
     /// # Errors