|
|
@ -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")] |
|
|
|