From f347b3e7ca771f11a21d2f6e54c0d97796174d37 Mon Sep 17 00:00:00 2001 From: Mica White Date: Wed, 12 Mar 2025 22:19:38 -0400 Subject: Add unwind handling for scoped locks --- src/rwlock/rwlock.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 9 deletions(-) (limited to 'src/rwlock/rwlock.rs') diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs index 5f407d1..f1cdca5 100644 --- a/src/rwlock/rwlock.rs +++ b/src/rwlock/rwlock.rs @@ -5,7 +5,6 @@ use std::panic::AssertUnwindSafe; use lock_api::RawRwLock; -use crate::collection::utils; use crate::handle_unwind::handle_unwind; use crate::lockable::{ Lockable, LockableGetMut, LockableIntoInner, OwnedLockable, RawLock, Sharable, @@ -118,9 +117,9 @@ unsafe impl Sharable for RwLock { } } -unsafe impl OwnedLockable for RwLock {} +unsafe impl OwnedLockable for RwLock {} -impl LockableIntoInner for RwLock { +impl LockableIntoInner for RwLock { type Inner = T; fn into_inner(self) -> Self::Inner { @@ -128,7 +127,7 @@ impl LockableIntoInner for RwLock { } } -impl LockableGetMut for RwLock { +impl LockableGetMut for RwLock { type Inner<'a> = &'a mut T where @@ -248,9 +247,26 @@ impl RwLock { } } -impl RwLock { +impl RwLock { pub fn scoped_read<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a T) -> Ret) -> Ret { - utils::scoped_read(self, key, f) + unsafe { + // safety: we have the key + self.raw_read(); + + // safety: the data has been locked + let r = handle_unwind( + || f(self.data.get().as_ref().unwrap_unchecked()), + || self.raw_unlock_read(), + ); + + // ensures the key is held long enough + drop(key); + + // safety: the mutex is still locked + self.raw_unlock_read(); + + r + } } pub fn scoped_try_read<'a, Key: Keyable, Ret>( @@ -258,11 +274,47 @@ impl RwLock { key: Key, f: impl Fn(&'a T) -> Ret, ) -> Result { - utils::scoped_try_read(self, key, f) + unsafe { + // safety: we have the key + if !self.raw_try_read() { + return Err(key); + } + + // safety: the data has been locked + let r = handle_unwind( + || f(self.data.get().as_ref().unwrap_unchecked()), + || self.raw_unlock_read(), + ); + + // ensures the key is held long enough + drop(key); + + // safety: the mutex is still locked + self.raw_unlock_read(); + + Ok(r) + } } pub fn scoped_write<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a mut T) -> Ret) -> Ret { - utils::scoped_write(self, key, f) + unsafe { + // safety: we have the key + self.raw_write(); + + // safety: the data has been locked + let r = handle_unwind( + || f(self.data.get().as_mut().unwrap_unchecked()), + || self.raw_unlock_write(), + ); + + // ensures the key is held long enough + drop(key); + + // safety: the mutex is still locked + self.raw_unlock_write(); + + r + } } pub fn scoped_try_write<'a, Key: Keyable, Ret>( @@ -270,7 +322,26 @@ impl RwLock { key: Key, f: impl Fn(&'a mut T) -> Ret, ) -> Result { - utils::scoped_try_write(self, key, f) + unsafe { + // safety: we have the key + if !self.raw_try_write() { + return Err(key); + } + + // safety: the data has been locked + let r = handle_unwind( + || f(self.data.get().as_mut().unwrap_unchecked()), + || self.raw_unlock_write(), + ); + + // ensures the key is held long enough + drop(key); + + // safety: the mutex is still locked + self.raw_unlock_write(); + + Ok(r) + } } /// Locks this `RwLock` with shared read access, blocking the current -- cgit v1.2.3