Skip to content

Commit 233d1b5

Browse files
committed
Auto merge of rust-lang#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
2 parents b8774af + 77c35e2 commit 233d1b5

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

std/src/sync/mutex.rs

+39
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,45 @@ impl<T: ?Sized> Mutex<T> {
364364
self.poison.get()
365365
}
366366

367+
/// Clear the poisoned state from a mutex
368+
///
369+
/// If the mutex is poisoned, it will remain poisoned until this function is called. This
370+
/// allows recovering from a poisoned state and marking that it has recovered. For example, if
371+
/// the value is overwritten by a known-good value, then the mutex can be marked as
372+
/// un-poisoned. Or possibly, the value could be inspected to determine if it is in a
373+
/// consistent state, and if so the poison is removed.
374+
///
375+
/// # Examples
376+
///
377+
/// ```
378+
/// #![feature(mutex_unpoison)]
379+
///
380+
/// use std::sync::{Arc, Mutex};
381+
/// use std::thread;
382+
///
383+
/// let mutex = Arc::new(Mutex::new(0));
384+
/// let c_mutex = Arc::clone(&mutex);
385+
///
386+
/// let _ = thread::spawn(move || {
387+
/// let _lock = c_mutex.lock().unwrap();
388+
/// panic!(); // the mutex gets poisoned
389+
/// }).join();
390+
///
391+
/// assert_eq!(mutex.is_poisoned(), true);
392+
/// let x = mutex.lock().unwrap_or_else(|mut e| {
393+
/// **e.get_mut() = 1;
394+
/// mutex.clear_poison();
395+
/// e.into_inner()
396+
/// });
397+
/// assert_eq!(mutex.is_poisoned(), false);
398+
/// assert_eq!(*x, 1);
399+
/// ```
400+
#[inline]
401+
#[unstable(feature = "mutex_unpoison", issue = "96469")]
402+
pub fn clear_poison(&self) {
403+
self.poison.clear();
404+
}
405+
367406
/// Consumes this mutex, returning the underlying data.
368407
///
369408
/// # Errors

std/src/sync/poison.rs

+5
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ impl Flag {
4040
pub fn get(&self) -> bool {
4141
self.failed.load(Ordering::Relaxed)
4242
}
43+
44+
#[inline]
45+
pub fn clear(&self) {
46+
self.failed.store(false, Ordering::Relaxed)
47+
}
4348
}
4449

4550
pub struct Guard {

std/src/sync/rwlock.rs

+39
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,45 @@ impl<T: ?Sized> RwLock<T> {
368368
self.poison.get()
369369
}
370370

371+
/// Clear the poisoned state from a lock
372+
///
373+
/// If the lock is poisoned, it will remain poisoned until this function is called. This allows
374+
/// recovering from a poisoned state and marking that it has recovered. For example, if the
375+
/// value is overwritten by a known-good value, then the mutex can be marked as un-poisoned. Or
376+
/// possibly, the value could be inspected to determine if it is in a consistent state, and if
377+
/// so the poison is removed.
378+
///
379+
/// # Examples
380+
///
381+
/// ```
382+
/// #![feature(mutex_unpoison)]
383+
///
384+
/// use std::sync::{Arc, RwLock};
385+
/// use std::thread;
386+
///
387+
/// let lock = Arc::new(RwLock::new(0));
388+
/// let c_lock = Arc::clone(&lock);
389+
///
390+
/// let _ = thread::spawn(move || {
391+
/// let _lock = c_lock.write().unwrap();
392+
/// panic!(); // the mutex gets poisoned
393+
/// }).join();
394+
///
395+
/// assert_eq!(lock.is_poisoned(), true);
396+
/// let guard = lock.write().unwrap_or_else(|mut e| {
397+
/// **e.get_mut() = 1;
398+
/// lock.clear_poison();
399+
/// e.into_inner()
400+
/// });
401+
/// assert_eq!(lock.is_poisoned(), false);
402+
/// assert_eq!(*guard, 1);
403+
/// ```
404+
#[inline]
405+
#[unstable(feature = "mutex_unpoison", issue = "96469")]
406+
pub fn clear_poison(&self) {
407+
self.poison.clear();
408+
}
409+
371410
/// Consumes this `RwLock`, returning the underlying data.
372411
///
373412
/// # Errors

0 commit comments

Comments
 (0)