diff options
| author | Mica White <botahamec@outlook.com> | 2024-03-11 16:33:26 -0400 |
|---|---|---|
| committer | Mica White <botahamec@outlook.com> | 2024-03-11 16:33:26 -0400 |
| commit | 462fc2d9aab8f0cba680caec344e4c388e9901b1 (patch) | |
| tree | 6b401c5ed4920c2ec8093d5c49976fe0b72573c2 /src/rwlock | |
| parent | 5eaa4fe1d3bfcda696122ba3d6b4914dba19ef96 (diff) | |
Documentation
Diffstat (limited to 'src/rwlock')
| -rw-r--r-- | src/rwlock/read_guard.rs | 2 | ||||
| -rw-r--r-- | src/rwlock/read_lock.rs | 40 | ||||
| -rw-r--r-- | src/rwlock/rwlock.rs | 166 | ||||
| -rw-r--r-- | src/rwlock/write_guard.rs | 4 | ||||
| -rw-r--r-- | src/rwlock/write_lock.rs | 19 |
5 files changed, 222 insertions, 9 deletions
diff --git a/src/rwlock/read_guard.rs b/src/rwlock/read_guard.rs index e967420..d8db9b9 100644 --- a/src/rwlock/read_guard.rs +++ b/src/rwlock/read_guard.rs @@ -14,7 +14,7 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockReadRef<'a, T, R> { // safety: this is the only type that can use `value`, and there's // a reference to this type, so there cannot be any mutable // references to this value. - unsafe { &*self.0.value.get() } + unsafe { &*self.0.data.get() } } } diff --git a/src/rwlock/read_lock.rs b/src/rwlock/read_lock.rs index dbab8de..176fc01 100644 --- a/src/rwlock/read_lock.rs +++ b/src/rwlock/read_lock.rs @@ -6,9 +6,25 @@ use crate::key::Keyable; use super::{ReadLock, RwLock, RwLockReadGuard, RwLockReadRef}; -impl<'a, T: ?Sized, R> Debug for ReadLock<'a, T, R> { +impl<'a, T: ?Sized + Debug, R: RawRwLock> Debug for ReadLock<'a, T, R> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&format!("ReadLock<{}>", std::any::type_name::<T>())) + // safety: this is just a try lock, and the value is dropped + // immediately after, so there's no risk of blocking ourselves + // or any other threads + if let Some(value) = unsafe { self.try_lock_no_key() } { + f.debug_struct("ReadLock").field("data", &&*value).finish() + } else { + struct LockedPlaceholder; + impl Debug for LockedPlaceholder { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("<locked>") + } + } + + f.debug_struct("ReadLock") + .field("data", &LockedPlaceholder) + .finish() + } } } @@ -25,6 +41,16 @@ impl<'a, T: ?Sized, R> AsRef<RwLock<T, R>> for ReadLock<'a, T, R> { } impl<'a, T: ?Sized, R> ReadLock<'a, T, R> { + /// Creates a new `ReadLock` which accesses the given [`RwLock`] + /// + /// # Examples + /// + /// ``` + /// use happylock::{rwlock::ReadLock, RwLock}; + /// + /// let lock = RwLock::new(5); + /// let read_lock = ReadLock::new(&lock); + /// ``` #[must_use] pub const fn new(rwlock: &'a RwLock<T, R>) -> Self { Self(rwlock) @@ -32,6 +58,8 @@ impl<'a, T: ?Sized, R> ReadLock<'a, T, R> { } impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> { + /// Locks the underlying [`RwLock`] with shared read access, blocking the + /// current thread until it can be acquired. pub fn lock<'s, 'key: 's, Key: Keyable + 'key>( &'s self, key: Key, @@ -39,10 +67,14 @@ impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> { self.0.read(key) } + /// Creates a shared lock without a key. Locking this without exclusive + /// access to the key is undefined behavior. pub(crate) unsafe fn lock_no_key(&self) -> RwLockReadRef<'_, T, R> { self.0.read_no_key() } + /// Attempts to acquire the underlying [`RwLock`] with shared read access + /// without blocking. pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>( &'s self, key: Key, @@ -50,10 +82,14 @@ impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> { self.0.try_read(key) } + /// Attempts to create an exclusive lock without a key. Locking this + /// without exclusive access to the key is undefined behavior. pub(crate) unsafe fn try_lock_no_key(&self) -> Option<RwLockReadRef<'_, T, R>> { self.0.try_read_no_key() } + /// Immediately drops the guard, and consequentlyreleases the shared lock + /// on the underlying [`RwLock`]. pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockReadGuard<'_, 'key, T, Key, R>) -> Key { RwLock::unlock_read(guard) } diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs index c1d1792..556d6bf 100644 --- a/src/rwlock/rwlock.rs +++ b/src/rwlock/rwlock.rs @@ -8,10 +8,19 @@ use crate::key::Keyable; use super::{RwLock, RwLockReadGuard, RwLockReadRef, RwLockWriteGuard, RwLockWriteRef}; impl<T, R: RawRwLock> RwLock<T, R> { + /// Creates a new instance of an `RwLock<T>` which is unlocked. + /// + /// # Examples + /// + /// ``` + /// use happylock::RwLock; + /// + /// let lock = RwLock::new(5); + /// ``` #[must_use] - pub const fn new(value: T) -> Self { + pub const fn new(data: T) -> Self { Self { - value: UnsafeCell::new(value), + data: UnsafeCell::new(data), raw: R::INIT, } } @@ -59,17 +68,51 @@ impl<T: ?Sized, R> AsMut<T> for RwLock<T, R> { impl<T, R> RwLock<T, R> { pub fn into_inner(self) -> T { - self.value.into_inner() + self.data.into_inner() } } impl<T: ?Sized, R> RwLock<T, R> { pub fn get_mut(&mut self) -> &mut T { - self.value.get_mut() + self.data.get_mut() } } impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { + /// Locks this `RwLock` with shared read access, blocking the current + /// thread until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers + /// which hold the lock. There may be other readers currently inside the + /// lock when this method returns. + /// + /// Returns an RAII guard which will release this thread's shared access + /// once it is dropped. + /// + /// Because this method takes a [`ThreadKey`], it's not possible for this + /// method to cause a deadlock. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// use std::thread; + /// use happylock::{RwLock, ThreadKey}; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = Arc::new(RwLock::new(1)); + /// let c_lock = Arc::clone(&lock); + /// + /// let n = lock.read(key); + /// assert_eq!(*n, 1); + /// + /// thread::spawn(move || { + /// let key = ThreadKey::get().unwrap(); + /// let r = c_lock.read(key); + /// }).join().unwrap(); + /// ``` + /// + /// [`ThreadKey`]: `crate::ThreadKey` pub fn read<'s, 'key: 's, Key: Keyable>( &'s self, key: Key, @@ -82,6 +125,8 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { } } + /// Creates a shared lock without a key. Locking this without exclusive + /// access to the key is undefined behavior. pub(crate) unsafe fn read_no_key(&self) -> RwLockReadRef<'_, T, R> { self.raw.lock_shared(); @@ -89,6 +134,26 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { RwLockReadRef(self) } + /// Attempts to acquire this `RwLock` with shared read access without + /// blocking. + /// + /// If the access could not be granted at this time, then `None` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// shared access when it is dropped. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(1); + /// + /// match lock.try_read(key) { + /// Some(n) => assert_eq!(*n, 1), + /// None => unreachable!(), + /// }; + /// ``` pub fn try_read<'s, 'key: 's, Key: Keyable>( &'s self, key: Key, @@ -103,6 +168,8 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { } } + /// Attempts to create a shared lock without a key. Locking this without + /// exclusive access to the key is undefined behavior. pub(crate) unsafe fn try_read_no_key(&self) -> Option<RwLockReadRef<'_, T, R>> { if self.raw.try_lock_shared() { // safety: the lock is locked first @@ -112,6 +179,31 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { } } + /// Locks this `RwLock` with exclusive write access, blocking the current + /// until it can be acquired. + /// + /// This function will not return while other writers or readers currently + /// have access to the lock. + /// + /// Returns an RAII guard which will drop the write access of this `RwLock` + /// when dropped. + /// + /// Because this method takes a [`ThreadKey`], it's not possible for this + /// method to cause a deadlock. + /// + /// # Examples + /// + /// ``` + /// use happylock::{ThreadKey, RwLock}; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(1); + /// + /// let mut n = lock.write(key); + /// *n += 2; + /// ``` + /// + /// [`ThreadKey`]: `crate::ThreadKey` pub fn write<'s, 'key: 's, Key: Keyable>( &'s self, key: Key, @@ -124,6 +216,8 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { } } + /// Creates an exclusive lock without a key. Locking this without exclusive + /// access to the key is undefined behavior. pub(crate) unsafe fn write_no_key(&self) -> RwLockWriteRef<'_, T, R> { self.raw.lock_exclusive(); @@ -131,6 +225,27 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { RwLockWriteRef(self) } + /// Attempts to lock this `RwLock` with exclusive write access. + /// + /// This function does not block. If the lock could not be acquired at this + /// time, then `None` is returned. Otherwise an RAII guard is returned + /// which will release the lock when it is dropped. + /// + /// This function does not provide any guarantees with respect to the + /// ordering of whether contentious readers or writers will acquire the + /// lock first. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(1); + /// + /// let n = lock.read(key); + /// assert_eq!(*n, 1); + /// ``` pub fn try_write<'s, 'key: 's, Key: Keyable>( &'s self, key: Key, @@ -145,6 +260,8 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { } } + /// Attempts to create an exclusive lock without a key. Locking this + /// without exclusive access to the key is undefined behavior. pub(crate) unsafe fn try_write_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> { if self.raw.try_lock_exclusive() { // safety: the lock is locked first @@ -154,14 +271,36 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { } } + /// Unlocks shared access on the `RwLock`. This is undefined behavior is + /// the data is still accessible. pub(super) unsafe fn force_unlock_read(&self) { self.raw.unlock_shared(); } + /// Unlocks exclusive access on the `RwLock`. This is undefined behavior is + /// the data is still accessible. pub(super) unsafe fn force_unlock_write(&self) { self.raw.unlock_exclusive(); } + /// Immediately drops the guard, and consequently releases the shared lock. + /// + /// This function is equivalent to calling [`drop`] on the guard, except + /// that it returns the key that was used to create it. Alternately, the + /// guard will be automatically dropped when it goes out of scope. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(0); + /// + /// let mut guard = lock.read(key); + /// assert_eq!(*guard, 0); + /// let key = RwLock::unlock_read(guard); + /// ``` pub fn unlock_read<'key, Key: Keyable + 'key>( guard: RwLockReadGuard<'_, 'key, T, Key, R>, ) -> Key { @@ -171,6 +310,25 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { guard.thread_key } + /// Immediately drops the guard, and consequently releases the exclusive + /// lock. + /// + /// This function is equivalent to calling [`drop`] on the guard, except + /// that it returns the key that was used to create it. Alternately, the + /// guard will be automatically dropped when it goes out of scope. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(0); + /// + /// let mut guard = lock.write(key); + /// *guard += 20; + /// let key = RwLock::unlock_write(guard); + /// ``` pub fn unlock_write<'key, Key: Keyable + 'key>( guard: RwLockWriteGuard<'_, 'key, T, Key, R>, ) -> Key { diff --git a/src/rwlock/write_guard.rs b/src/rwlock/write_guard.rs index 8f5feb4..dd168bf 100644 --- a/src/rwlock/write_guard.rs +++ b/src/rwlock/write_guard.rs @@ -14,7 +14,7 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockWriteRef<'a, T, R> { // safety: this is the only type that can use `value`, and there's // a reference to this type, so there cannot be any mutable // references to this value. - unsafe { &*self.0.value.get() } + unsafe { &*self.0.data.get() } } } @@ -23,7 +23,7 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> DerefMut for RwLockWriteRef<'a, T, R> { // safety: this is the only type that can use `value`, and we have a // mutable reference to this type, so there cannot be any other // references to this value. - unsafe { &mut *self.0.value.get() } + unsafe { &mut *self.0.data.get() } } } diff --git a/src/rwlock/write_lock.rs b/src/rwlock/write_lock.rs index dd204f5..0275a70 100644 --- a/src/rwlock/write_lock.rs +++ b/src/rwlock/write_lock.rs @@ -25,6 +25,16 @@ impl<'a, T: ?Sized, R> AsRef<RwLock<T, R>> for WriteLock<'a, T, R> { } impl<'a, T: ?Sized, R> WriteLock<'a, T, R> { + /// Creates a new `WriteLock` which accesses the given [`RwLock`] + /// + /// # Examples + /// + /// ``` + /// use happylock::{rwlock::WriteLock, RwLock}; + /// + /// let lock = RwLock::new(5); + /// let write_lock = WriteLock::new(&lock); + /// ``` #[must_use] pub const fn new(rwlock: &'a RwLock<T, R>) -> Self { Self(rwlock) @@ -32,6 +42,8 @@ impl<'a, T: ?Sized, R> WriteLock<'a, T, R> { } impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> { + /// Locks the underlying [`RwLock`] with exclusive write access, blocking + /// the current until it can be acquired. pub fn lock<'s, 'key: 's, Key: Keyable + 'key>( &'s self, key: Key, @@ -39,10 +51,13 @@ impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> { self.0.write(key) } + /// Creates an exclusive lock without a key. Locking this without exclusive + /// access to the key is undefined behavior. pub(crate) unsafe fn lock_no_key(&self) -> RwLockWriteRef<'_, T, R> { self.0.write_no_key() } + /// Attempts to lock the underlying [`RwLock`] with exclusive write access. pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>( &'s self, key: Key, @@ -50,10 +65,14 @@ impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> { self.0.try_write(key) } + /// Attempts to create an exclusive lock without a key. Locking this + /// without exclusive access to the key is undefined behavior. pub(crate) unsafe fn try_lock_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> { self.0.try_write_no_key() } + /// Immediately drops the guard, and consequently releases the exclusive + /// lock. pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockWriteGuard<'_, 'key, T, Key, R>) -> Key { RwLock::unlock_write(guard) } |
