mirror of
https://github.com/emilk/egui.git
synced 2026-06-27 15:13:12 -04:00
Add single-threaded deadlock detection to RwMutex (#1619)
This commit is contained in:
@@ -111,6 +111,7 @@ mod mutex_impl {
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(not(feature = "deadlock_detection"))]
|
||||
mod rw_lock_impl {
|
||||
/// The lock you get from [`RwLock::read`].
|
||||
pub use parking_lot::MappedRwLockReadGuard as RwLockReadGuard;
|
||||
@@ -142,6 +143,81 @@ mod rw_lock_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
mod rw_lock_impl {
|
||||
/// The lock you get from [`RwLock::read`].
|
||||
pub use parking_lot::MappedRwLockReadGuard as RwLockReadGuard;
|
||||
|
||||
/// The lock you get from [`RwLock::write`].
|
||||
pub use parking_lot::MappedRwLockWriteGuard as RwLockWriteGuard;
|
||||
|
||||
/// Provides interior mutability.
|
||||
///
|
||||
/// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets.
|
||||
#[derive(Default)]
|
||||
pub struct RwLock<T> {
|
||||
lock: parking_lot::RwLock<T>,
|
||||
last_lock: parking_lot::Mutex<backtrace::Backtrace>,
|
||||
}
|
||||
|
||||
impl<T> RwLock<T> {
|
||||
pub fn new(val: T) -> Self {
|
||||
Self {
|
||||
lock: parking_lot::RwLock::new(val),
|
||||
last_lock: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self) -> RwLockReadGuard<'_, T> {
|
||||
if self.lock.is_locked_exclusive() {
|
||||
panic!(
|
||||
"{} DEAD-LOCK DETECTED! Previous lock held at:\n{}\n\n",
|
||||
std::any::type_name::<Self>(),
|
||||
format_backtrace(&mut self.last_lock.lock())
|
||||
);
|
||||
}
|
||||
*self.last_lock.lock() = make_backtrace();
|
||||
parking_lot::RwLockReadGuard::map(self.lock.read(), |v| v)
|
||||
}
|
||||
|
||||
pub fn write(&self) -> RwLockWriteGuard<'_, T> {
|
||||
if self.lock.is_locked() {
|
||||
panic!(
|
||||
"{} DEAD-LOCK DETECTED! Previous lock held at:\n{}\n\n",
|
||||
std::any::type_name::<Self>(),
|
||||
format_backtrace(&mut self.last_lock.lock())
|
||||
);
|
||||
}
|
||||
*self.last_lock.lock() = make_backtrace();
|
||||
parking_lot::RwLockWriteGuard::map(self.lock.write(), |v| v)
|
||||
}
|
||||
}
|
||||
|
||||
fn make_backtrace() -> backtrace::Backtrace {
|
||||
backtrace::Backtrace::new_unresolved()
|
||||
}
|
||||
|
||||
fn format_backtrace(backtrace: &mut backtrace::Backtrace) -> String {
|
||||
backtrace.resolve();
|
||||
|
||||
let stacktrace = format!("{:?}", backtrace);
|
||||
|
||||
// Remove irrelevant parts of the stacktrace:
|
||||
let end_offset = stacktrace
|
||||
.find("std::sys_common::backtrace::__rust_begin_short_backtrace")
|
||||
.unwrap_or(stacktrace.len());
|
||||
let stacktrace = &stacktrace[..end_offset];
|
||||
|
||||
let first_interesting_function = "epaint::mutex::rw_lock_impl::make_backtrace\n";
|
||||
if let Some(start_offset) = stacktrace.find(first_interesting_function) {
|
||||
stacktrace[start_offset + first_interesting_function.len()..].to_owned()
|
||||
} else {
|
||||
stacktrace.to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
||||
Reference in New Issue
Block a user