about summary refs log tree commit diff
path: root/library/std/src/sync
diff options
context:
space:
mode:
authorThayne McCombs <astrothayne@gmail.com>2022-04-26 00:58:51 -0600
committerThayne McCombs <astrothayne@gmail.com>2022-04-26 01:35:04 -0600
commitfc38388bc12716d987df1303aa52f1dc4884fc58 (patch)
tree5b592256b2303e798318bc2fa5851af923cecc3b /library/std/src/sync
parent9ea4d4127fa2c7e99d31a4a8a59227c9874d61dc (diff)
downloadrust-fc38388bc12716d987df1303aa52f1dc4884fc58.tar.gz
rust-fc38388bc12716d987df1303aa52f1dc4884fc58.zip
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.rs34
-rw-r--r--library/std/src/sync/poison.rs5
-rw-r--r--library/std/src/sync/rwlock.rs34
3 files changed, 73 insertions, 0 deletions
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 3ea0a6c3937..4d6916fba98 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -363,6 +363,40 @@ 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
+    /// with a mutex guard. 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();
+    ///
+    /// let guard = mutex.lock().unwrap_err().into_inner();
+    /// Mutex::clear_poison(&guard);
+    /// assert_eq!(mutex.is_poisoned(), false);
+    /// ```
+    #[inline]
+    #[unstable(feature = "mutex_unpoison", issue = "none")]
+    pub fn clear_poison(guard: &MutexGuard<'_, T>) {
+        guard.lock.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 ed62fa977be..b7a7186da13 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -366,6 +366,40 @@ 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
+    /// with a write guard. 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();
+    ///
+    /// let guard = lock.write().unwrap_err().into_inner();
+    /// RwLock::clear_poison(&guard);
+    /// assert_eq!(lock.is_poisoned(), false);
+    /// ```
+    #[inline]
+    #[unstable(feature = "mutex_unpoison", issue = "none")]
+    pub fn clear_poison(guard: &RwLockWriteGuard<'_, T>) {
+        guard.lock.poison.clear();
+    }
+
     /// Consumes this `RwLock`, returning the underlying data.
     ///
     /// # Errors