From fc38388bc12716d987df1303aa52f1dc4884fc58 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Tue, 26 Apr 2022 00:58:51 -0600 Subject: [PATCH 1/4] 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 3ea0a6c393760..4d6916fba9870 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 07a90da449c9d..ba91fb0499ff0 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 ed62fa977beca..b7a7186da1393 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 From f7ac8e7aeffa796ac5f19b66c0c59b20312ac520 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Wed, 27 Apr 2022 00:05:34 -0600 Subject: [PATCH 2/4] Add tracking issue number for mutex_unpoison --- library/std/src/sync/mutex.rs | 2 +- library/std/src/sync/rwlock.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 4d6916fba9870..c9fbdd1270be0 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -392,7 +392,7 @@ impl Mutex { /// assert_eq!(mutex.is_poisoned(), false); /// ``` #[inline] - #[unstable(feature = "mutex_unpoison", issue = "none")] + #[unstable(feature = "mutex_unpoison", issue = "96469")] pub fn clear_poison(guard: &MutexGuard<'_, T>) { guard.lock.poison.clear(); } diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index b7a7186da1393..d068b15dbcab3 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -395,7 +395,7 @@ impl RwLock { /// assert_eq!(lock.is_poisoned(), false); /// ``` #[inline] - #[unstable(feature = "mutex_unpoison", issue = "none")] + #[unstable(feature = "mutex_unpoison", issue = "96469")] pub fn clear_poison(guard: &RwLockWriteGuard<'_, T>) { guard.lock.poison.clear(); } From 66d88c9a184e4a93a1ce5383a7bec75b435bc423 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Thu, 19 May 2022 01:53:41 -0600 Subject: [PATCH 3/4] Change clear_poison to take the lock instead of a guard --- library/std/src/sync/mutex.rs | 13 +++++++++---- library/std/src/sync/rwlock.rs | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index c9fbdd1270be0..9c305f517ef37 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -387,14 +387,19 @@ impl Mutex { /// panic!(); // the mutex gets poisoned /// }).join(); /// - /// let guard = mutex.lock().unwrap_err().into_inner(); - /// Mutex::clear_poison(&guard); + /// 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(guard: &MutexGuard<'_, T>) { - guard.lock.poison.clear(); + pub fn clear_poison(&self) { + self.poison.clear(); } /// Consumes this mutex, returning the underlying data. diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index d068b15dbcab3..c0cd02708a733 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -390,14 +390,19 @@ impl RwLock { /// panic!(); // the mutex gets poisoned /// }).join(); /// - /// let guard = lock.write().unwrap_err().into_inner(); - /// RwLock::clear_poison(&guard); + /// 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(guard: &RwLockWriteGuard<'_, T>) { - guard.lock.poison.clear(); + pub fn clear_poison(&self) { + self.poison.clear(); } /// Consumes this `RwLock`, returning the underlying data. From a65afd82d1020f15d347268c077d4b7220268abc Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Fri, 20 May 2022 00:15:26 -0600 Subject: [PATCH 4/4] Remove references to guards in documentation for clear_poison --- library/std/src/sync/mutex.rs | 10 +++++----- library/std/src/sync/rwlock.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 9c305f517ef37..b5832c5f7d523 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -365,11 +365,11 @@ impl Mutex { /// 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. + /// 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 /// diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index c0cd02708a733..8d772a87bff2e 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -368,11 +368,11 @@ impl RwLock { /// 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. + /// 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 ///