From 7b7dcb5a77061cb69d368de263a02b5ad26fbf51 Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 26 Oct 2026 04:20:52 +0100 Subject: unify lock logic --- src/locks.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/locks.rs (limited to 'src/locks.rs') diff --git a/src/locks.rs b/src/locks.rs new file mode 100644 index 0000000..ad66e6f --- /dev/null +++ b/src/locks.rs @@ -0,0 +1,53 @@ +//! Std locks without poisoning. A panic while one is held leaves its data as it was, and +//! every lock of this kind here guards counters, tables or caches that stay usable: so +//! the next user takes the data as it is instead of panicking too. (The tokio locks +//! around the document and the peers don't poison.) + +use std::sync::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; + +pub(crate) trait MutexExt { + /// Locks, recovering from a poisoned mutex. + fn lock_or_recover(&self) -> MutexGuard<'_, T>; +} + +impl MutexExt for Mutex { + fn lock_or_recover(&self) -> MutexGuard<'_, T> { + self.lock().unwrap_or_else(|poisoned| poisoned.into_inner()) + } +} + +pub(crate) trait RwLockExt { + /// Locks for reading, recovering from a poisoned lock. + fn read_or_recover(&self) -> RwLockReadGuard<'_, T>; + /// Locks for writing, recovering from a poisoned lock. + fn write_or_recover(&self) -> RwLockWriteGuard<'_, T>; +} + +impl RwLockExt for RwLock { + fn read_or_recover(&self) -> RwLockReadGuard<'_, T> { + self.read().unwrap_or_else(|poisoned| poisoned.into_inner()) + } + + fn write_or_recover(&self) -> RwLockWriteGuard<'_, T> { + self.write() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn a_panic_while_locked_doesnt_spread() { + let mutex = std::sync::Arc::new(Mutex::new(1)); + let poisoner = std::sync::Arc::clone(&mutex); + let _ = std::thread::spawn(move || { + let _guard = poisoner.lock().unwrap(); + panic!("while holding the lock"); + }) + .join(); + assert!(mutex.is_poisoned()); + assert_eq!(*mutex.lock_or_recover(), 1); + } +} -- cgit v1.3.1