From fc38388bc12716d987df1303aa52f1dc4884fc58 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Tue, 26 Apr 2022 00:58:51 -0600 Subject: [PATCH] Add functions to un-poison Mutex and RwLock See discussion at https://internals.rust-lang.org/t/unpoisoning-a-mutex/16521/3 --- library/std/src/sync/mutex.rs | 34 ++++++++++++++++++++++++++++++++++ library/std/src/sync/poison.rs | 5 +++++ library/std/src/sync/rwlock.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) 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 Mutex { 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 RwLock { 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