Skip to content

Add functions to un-poison Mutex and RwLock #96422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions library/std/src/sync/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,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
Expand Down
5 changes: 5 additions & 0 deletions library/std/src/sync/poison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
39 changes: 39 additions & 0 deletions library/std/src/sync/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,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
Expand Down