diff options
Diffstat (limited to 'src/mutex')
| -rw-r--r-- | src/mutex/guard.rs | 39 | ||||
| -rw-r--r-- | src/mutex/mutex.rs | 208 | ||||
| -rw-r--r-- | src/mutex/mutex_ref.rs | 33 |
3 files changed, 280 insertions, 0 deletions
diff --git a/src/mutex/guard.rs b/src/mutex/guard.rs new file mode 100644 index 0000000..b4005e1 --- /dev/null +++ b/src/mutex/guard.rs @@ -0,0 +1,39 @@ +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; + +use lock_api::RawMutex; + +use crate::key::Keyable; + +use super::{Mutex, MutexGuard, MutexRef}; + +impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> Deref + for MutexGuard<'a, 'key, T, Key, R> +{ + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.mutex + } +} + +impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> DerefMut + for MutexGuard<'a, 'key, T, Key, R> +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.mutex + } +} + +impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> MutexGuard<'a, 'key, T, Key, R> { + /// Create a guard to the given mutex. Undefined if multiple guards to the + /// same mutex exist at once. + #[must_use] + pub(super) const unsafe fn new(mutex: &'a Mutex<T, R>, thread_key: Key) -> Self { + Self { + mutex: MutexRef(mutex), + thread_key, + _phantom: PhantomData, + } + } +} diff --git a/src/mutex/mutex.rs b/src/mutex/mutex.rs new file mode 100644 index 0000000..ce93cae --- /dev/null +++ b/src/mutex/mutex.rs @@ -0,0 +1,208 @@ +use std::cell::UnsafeCell; +use std::fmt::Debug; + +use lock_api::RawMutex; + +use crate::key::Keyable; + +use super::{Mutex, MutexGuard, MutexRef}; + +impl<T, R: RawMutex> Mutex<T, R> { + /// Create a new unlocked `Mutex`. + /// + /// # Examples + /// + /// ``` + /// use happylock::Mutex; + /// + /// let mutex = Mutex::new(0); + /// ``` + #[must_use] + pub const fn new(value: T) -> Self { + Self { + raw: R::INIT, + value: UnsafeCell::new(value), + } + } +} + +impl<T: ?Sized, R> Debug for Mutex<T, R> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&format!("Mutex<{}>", std::any::type_name::<T>())) + } +} + +impl<T, R: RawMutex> From<T> for Mutex<T, R> { + fn from(value: T) -> Self { + Self::new(value) + } +} + +impl<T: ?Sized, R> AsMut<T> for Mutex<T, R> { + fn as_mut(&mut self) -> &mut T { + self.get_mut() + } +} + +impl<T, R> Mutex<T, R> { + /// Consumes this mutex, returning the underlying data. + /// + /// # Examples + /// + /// ``` + /// use happylock::Mutex; + /// + /// let mutex = Mutex::new(0); + /// assert_eq!(mutex.into_inner(), 0); + /// ``` + #[must_use] + pub fn into_inner(self) -> T { + self.value.into_inner() + } +} + +impl<T: ?Sized, R> Mutex<T, R> { + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows `Mutex` mutably, no actual locking is taking + /// place. The mutable borrow statically guarantees that no locks exist. + /// + /// # Examples + /// + /// ``` + /// use happylock::{ThreadKey, Mutex}; + /// + /// let key = ThreadKey::lock().unwrap(); + /// let mut mutex = Mutex::new(0); + /// *mutex.get_mut() = 10; + /// assert_eq!(*mutex.lock(key), 10); + /// ``` + #[must_use] + pub fn get_mut(&mut self) -> &mut T { + self.value.get_mut() + } +} + +impl<T: ?Sized, R: RawMutex> Mutex<T, R> { + /// Block the thread until this mutex can be locked, and lock it. + /// + /// Upon returning, the thread is the only thread with a lock on the + /// `Mutex`. A [`MutexGuard`] is returned to allow a scoped unlock of this + /// `Mutex`. When the guard is dropped, this `Mutex` will unlock. + /// + /// # Examples + /// + /// ``` + /// use std::{thread, sync::Arc}; + /// use happylock::{Mutex, ThreadKey}; + /// + /// let mutex = Arc::new(Mutex::new(0)); + /// let c_mutex = Arc::clone(&mutex); + /// + /// thread::spawn(move || { + /// let key = ThreadKey::lock().unwrap(); + /// *c_mutex.lock(key) = 10; + /// }).join().expect("thread::spawn failed"); + /// + /// let key = ThreadKey::lock().unwrap(); + /// assert_eq!(*mutex.lock(key), 10); + /// ``` + pub fn lock<'s, 'k: 's, Key: Keyable>(&'s self, key: Key) -> MutexGuard<'_, 'k, T, Key, R> { + unsafe { + self.raw.lock(); + + // safety: we just locked the mutex + MutexGuard::new(self, key) + } + } + + /// Lock without a [`ThreadKey`]. You must exclusively own the + /// [`ThreadKey`] as long as the [`MutexRef`] is alive. This may cause + /// deadlock if called multiple times without unlocking first. + pub(crate) unsafe fn lock_no_key(&self) -> MutexRef<'_, T, R> { + self.raw.lock(); + + MutexRef(self) + } + + /// Attempts to lock the `Mutex` without blocking. + /// + /// # Errors + /// + /// Returns [`Err`] if the `Mutex` cannot be locked without blocking. + /// + /// # Examples + /// + /// ``` + /// use std::{thread, sync::Arc}; + /// use happylock::{Mutex, ThreadKey}; + /// + /// let mutex = Arc::new(Mutex::new(0)); + /// let c_mutex = Arc::clone(&mutex); + /// + /// thread::spawn(move || { + /// let key = ThreadKey::lock().unwrap(); + /// let mut lock = c_mutex.try_lock(key); + /// if let Some(mut lock) = lock { + /// *lock = 10; + /// } else { + /// println!("try_lock failed"); + /// } + /// }).join().expect("thread::spawn failed"); + /// + /// let key = ThreadKey::lock().unwrap(); + /// assert_eq!(*mutex.lock(key), 10); + /// ``` + pub fn try_lock<'s, 'a: 's, 'k: 'a, Key: Keyable>( + &'s self, + key: Key, + ) -> Option<MutexGuard<'_, 'k, T, Key, R>> { + if self.raw.try_lock() { + // safety: we just locked the mutex + Some(unsafe { MutexGuard::new(self, key) }) + } else { + None + } + } + + /// Lock without a [`ThreadKey`]. It is undefined behavior to do this without + /// owning the [`ThreadKey`]. + pub(crate) unsafe fn try_lock_no_key(&self) -> Option<MutexRef<'_, T, R>> { + self.raw.try_lock().then_some(MutexRef(self)) + } + + /// Forcibly unlocks the `Lock`. + /// + /// # Safety + /// + /// This should only be called if there are no references to any + /// [`MutexGuard`]s for this mutex in the program. + pub(super) unsafe fn force_unlock(&self) { + self.raw.unlock(); + } + + /// Consumes the [`MutexGuard`], and consequently unlocks its `Mutex`. + /// + /// # Examples + /// + /// ``` + /// use happylock::{ThreadKey, Mutex}; + /// + /// let key = ThreadKey::lock().unwrap(); + /// let mutex = Mutex::new(0); + /// + /// let mut guard = mutex.lock(key); + /// *guard += 20; + /// + /// let key = Mutex::unlock(guard); + /// ``` + pub fn unlock<'a, 'k: 'a, Key: Keyable + 'k>(guard: MutexGuard<'a, 'k, T, Key, R>) -> Key { + unsafe { + guard.mutex.0.force_unlock(); + } + guard.thread_key + } +} + +unsafe impl<R: RawMutex + Send, T: ?Sized + Send> Send for Mutex<T, R> {} +unsafe impl<R: RawMutex + Sync, T: ?Sized + Send + Sync> Sync for Mutex<T, R> {} diff --git a/src/mutex/mutex_ref.rs b/src/mutex/mutex_ref.rs new file mode 100644 index 0000000..5222719 --- /dev/null +++ b/src/mutex/mutex_ref.rs @@ -0,0 +1,33 @@ +use std::ops::{Deref, DerefMut}; + +use lock_api::RawMutex; + +use super::MutexRef; + +impl<'a, T: ?Sized + 'a, R: RawMutex> Drop for MutexRef<'a, T, R> { + fn drop(&mut self) { + // safety: this guard is being destroyed, so the data cannot be + // accessed without locking again + unsafe { self.0.force_unlock() } + } +} + +impl<'a, T: ?Sized + 'a, R: RawMutex> Deref for MutexRef<'a, T, R> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // 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() } + } +} + +impl<'a, T: ?Sized + 'a, R: RawMutex> DerefMut for MutexRef<'a, T, R> { + fn deref_mut(&mut self) -> &mut Self::Target { + // 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() } + } +} |
