From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Mon, 8 Jan 2024 01:21:28 +0400 Subject: Initial vendor packages Signed-off-by: Valentin Popov --- vendor/lock_api/src/lib.rs | 116 ++ vendor/lock_api/src/mutex.rs | 960 +++++++++++++ vendor/lock_api/src/remutex.rs | 1051 +++++++++++++++ vendor/lock_api/src/rwlock.rs | 2883 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 5010 insertions(+) create mode 100644 vendor/lock_api/src/lib.rs create mode 100644 vendor/lock_api/src/mutex.rs create mode 100644 vendor/lock_api/src/remutex.rs create mode 100644 vendor/lock_api/src/rwlock.rs (limited to 'vendor/lock_api/src') diff --git a/vendor/lock_api/src/lib.rs b/vendor/lock_api/src/lib.rs new file mode 100644 index 0000000..3ea417a --- /dev/null +++ b/vendor/lock_api/src/lib.rs @@ -0,0 +1,116 @@ +// Copyright 2018 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +//! This library provides type-safe and fully-featured `Mutex` and `RwLock` +//! types which wrap a simple raw mutex or rwlock type. This has several +//! benefits: not only does it eliminate a large portion of the work in +//! implementing custom lock types, it also allows users to write code which is +//! generic with regards to different lock implementations. +//! +//! Basic usage of this crate is very straightforward: +//! +//! 1. Create a raw lock type. This should only contain the lock state, not any +//! data protected by the lock. +//! 2. Implement the `RawMutex` trait for your custom lock type. +//! 3. Export your mutex as a type alias for `lock_api::Mutex`, and +//! your mutex guard as a type alias for `lock_api::MutexGuard`. +//! See the [example](#example) below for details. +//! +//! This process is similar for RwLocks, except that two guards need to be +//! exported instead of one. (Or 3 guards if your type supports upgradable read +//! locks, see [extension traits](#extension-traits) below for details) +//! +//! # Example +//! +//! ``` +//! use lock_api::{RawMutex, Mutex, GuardSend}; +//! use std::sync::atomic::{AtomicBool, Ordering}; +//! +//! // 1. Define our raw lock type +//! pub struct RawSpinlock(AtomicBool); +//! +//! // 2. Implement RawMutex for this type +//! unsafe impl RawMutex for RawSpinlock { +//! const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false)); +//! +//! // A spinlock guard can be sent to another thread and unlocked there +//! type GuardMarker = GuardSend; +//! +//! fn lock(&self) { +//! // Note: This isn't the best way of implementing a spinlock, but it +//! // suffices for the sake of this example. +//! while !self.try_lock() {} +//! } +//! +//! fn try_lock(&self) -> bool { +//! self.0 +//! .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) +//! .is_ok() +//! } +//! +//! unsafe fn unlock(&self) { +//! self.0.store(false, Ordering::Release); +//! } +//! } +//! +//! // 3. Export the wrappers. This are the types that your users will actually use. +//! pub type Spinlock = lock_api::Mutex; +//! pub type SpinlockGuard<'a, T> = lock_api::MutexGuard<'a, RawSpinlock, T>; +//! ``` +//! +//! # Extension traits +//! +//! In addition to basic locking & unlocking functionality, you have the option +//! of exposing additional functionality in your lock types by implementing +//! additional traits for it. Examples of extension features include: +//! +//! - Fair unlocking (`RawMutexFair`, `RawRwLockFair`) +//! - Lock timeouts (`RawMutexTimed`, `RawRwLockTimed`) +//! - Downgradable write locks (`RawRwLockDowngradable`) +//! - Recursive read locks (`RawRwLockRecursive`) +//! - Upgradable read locks (`RawRwLockUpgrade`) +//! +//! The `Mutex` and `RwLock` wrappers will automatically expose this additional +//! functionality if the raw lock type implements these extension traits. +//! +//! # Cargo features +//! +//! This crate supports three cargo features: +//! +//! - `owning_ref`: Allows your lock types to be used with the `owning_ref` crate. +//! - `arc_lock`: Enables locking from an `Arc`. This enables types such as `ArcMutexGuard`. Note that this +//! requires the `alloc` crate to be present. + +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![warn(missing_docs)] +#![warn(rust_2018_idioms)] + +#[macro_use] +extern crate scopeguard; + +#[cfg(feature = "arc_lock")] +extern crate alloc; + +/// Marker type which indicates that the Guard type for a lock is `Send`. +pub struct GuardSend(()); + +/// Marker type which indicates that the Guard type for a lock is not `Send`. +pub struct GuardNoSend(*mut ()); + +unsafe impl Sync for GuardNoSend {} + +mod mutex; +pub use crate::mutex::*; + +#[cfg(feature = "atomic_usize")] +mod remutex; +#[cfg(feature = "atomic_usize")] +pub use crate::remutex::*; + +mod rwlock; +pub use crate::rwlock::*; diff --git a/vendor/lock_api/src/mutex.rs b/vendor/lock_api/src/mutex.rs new file mode 100644 index 0000000..80eadfa --- /dev/null +++ b/vendor/lock_api/src/mutex.rs @@ -0,0 +1,960 @@ +// Copyright 2018 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use core::cell::UnsafeCell; +use core::fmt; +use core::marker::PhantomData; +use core::mem; +use core::ops::{Deref, DerefMut}; + +#[cfg(feature = "arc_lock")] +use alloc::sync::Arc; +#[cfg(feature = "arc_lock")] +use core::mem::ManuallyDrop; +#[cfg(feature = "arc_lock")] +use core::ptr; + +#[cfg(feature = "owning_ref")] +use owning_ref::StableAddress; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// Basic operations for a mutex. +/// +/// Types implementing this trait can be used by `Mutex` to form a safe and +/// fully-functioning mutex type. +/// +/// # Safety +/// +/// Implementations of this trait must ensure that the mutex is actually +/// exclusive: a lock can't be acquired while the mutex is already locked. +pub unsafe trait RawMutex { + /// Initial value for an unlocked mutex. + // A “non-constant” const item is a legacy way to supply an initialized value to downstream + // static items. Can hopefully be replaced with `const fn new() -> Self` at some point. + #[allow(clippy::declare_interior_mutable_const)] + const INIT: Self; + + /// Marker type which determines whether a lock guard should be `Send`. Use + /// one of the `GuardSend` or `GuardNoSend` helper types here. + type GuardMarker; + + /// Acquires this mutex, blocking the current thread until it is able to do so. + fn lock(&self); + + /// Attempts to acquire this mutex without blocking. Returns `true` + /// if the lock was successfully acquired and `false` otherwise. + fn try_lock(&self) -> bool; + + /// Unlocks this mutex. + /// + /// # Safety + /// + /// This method may only be called if the mutex is held in the current context, i.e. it must + /// be paired with a successful call to [`lock`], [`try_lock`], [`try_lock_for`] or [`try_lock_until`]. + /// + /// [`lock`]: #tymethod.lock + /// [`try_lock`]: #tymethod.try_lock + /// [`try_lock_for`]: trait.RawMutexTimed.html#tymethod.try_lock_for + /// [`try_lock_until`]: trait.RawMutexTimed.html#tymethod.try_lock_until + unsafe fn unlock(&self); + + /// Checks whether the mutex is currently locked. + #[inline] + fn is_locked(&self) -> bool { + let acquired_lock = self.try_lock(); + if acquired_lock { + // Safety: The lock has been successfully acquired above. + unsafe { + self.unlock(); + } + } + !acquired_lock + } +} + +/// Additional methods for mutexes which support fair unlocking. +/// +/// Fair unlocking means that a lock is handed directly over to the next waiting +/// thread if there is one, without giving other threads the opportunity to +/// "steal" the lock in the meantime. This is typically slower than unfair +/// unlocking, but may be necessary in certain circumstances. +pub unsafe trait RawMutexFair: RawMutex { + /// Unlocks this mutex using a fair unlock protocol. + /// + /// # Safety + /// + /// This method may only be called if the mutex is held in the current context, see + /// the documentation of [`unlock`]. + /// + /// [`unlock`]: trait.RawMutex.html#tymethod.unlock + unsafe fn unlock_fair(&self); + + /// Temporarily yields the mutex to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_fair` followed + /// by `lock`, however it can be much more efficient in the case where there + /// are no waiting threads. + /// + /// # Safety + /// + /// This method may only be called if the mutex is held in the current context, see + /// the documentation of [`unlock`]. + /// + /// [`unlock`]: trait.RawMutex.html#tymethod.unlock + unsafe fn bump(&self) { + self.unlock_fair(); + self.lock(); + } +} + +/// Additional methods for mutexes which support locking with timeouts. +/// +/// The `Duration` and `Instant` types are specified as associated types so that +/// this trait is usable even in `no_std` environments. +pub unsafe trait RawMutexTimed: RawMutex { + /// Duration type used for `try_lock_for`. + type Duration; + + /// Instant type used for `try_lock_until`. + type Instant; + + /// Attempts to acquire this lock until a timeout is reached. + fn try_lock_for(&self, timeout: Self::Duration) -> bool; + + /// Attempts to acquire this lock until a timeout is reached. + fn try_lock_until(&self, timeout: Self::Instant) -> bool; +} + +/// A mutual exclusion primitive useful for protecting shared data +/// +/// This mutex will block threads waiting for the lock to become available. The +/// mutex can also be statically initialized or created via a `new` +/// constructor. Each mutex has a type parameter which represents the data that +/// it is protecting. The data can only be accessed through the RAII guards +/// returned from `lock` and `try_lock`, which guarantees that the data is only +/// ever accessed when the mutex is locked. +pub struct Mutex { + raw: R, + data: UnsafeCell, +} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +impl Mutex { + /// Creates a new mutex in an unlocked state ready for use. + #[cfg(has_const_fn_trait_bound)] + #[inline] + pub const fn new(val: T) -> Mutex { + Mutex { + raw: R::INIT, + data: UnsafeCell::new(val), + } + } + + /// Creates a new mutex in an unlocked state ready for use. + #[cfg(not(has_const_fn_trait_bound))] + #[inline] + pub fn new(val: T) -> Mutex { + Mutex { + raw: R::INIT, + data: UnsafeCell::new(val), + } + } + + /// Consumes this mutex, returning the underlying data. + #[inline] + pub fn into_inner(self) -> T { + self.data.into_inner() + } +} + +impl Mutex { + /// Creates a new mutex based on a pre-existing raw mutex. + /// + /// This allows creating a mutex in a constant context on stable Rust. + #[inline] + pub const fn const_new(raw_mutex: R, val: T) -> Mutex { + Mutex { + raw: raw_mutex, + data: UnsafeCell::new(val), + } + } +} + +impl Mutex { + /// Creates a new `MutexGuard` without checking if the mutex is locked. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds the lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. + #[inline] + pub unsafe fn make_guard_unchecked(&self) -> MutexGuard<'_, R, T> { + MutexGuard { + mutex: self, + marker: PhantomData, + } + } + + /// Acquires a mutex, blocking the current thread until it is able to do so. + /// + /// This function will block the local thread until it is available to acquire + /// the mutex. Upon returning, the thread is the only thread with the mutex + /// held. An RAII guard is returned to allow scoped unlock of the lock. When + /// the guard goes out of scope, the mutex will be unlocked. + /// + /// Attempts to lock a mutex in the thread which already holds the lock will + /// result in a deadlock. + #[inline] + pub fn lock(&self) -> MutexGuard<'_, R, T> { + self.raw.lock(); + // SAFETY: The lock is held, as required. + unsafe { self.make_guard_unchecked() } + } + + /// Attempts to acquire this lock. + /// + /// If the lock could not be acquired at this time, then `None` is returned. + /// Otherwise, an RAII guard is returned. The lock will be unlocked when the + /// guard is dropped. + /// + /// This function does not block. + #[inline] + pub fn try_lock(&self) -> Option> { + if self.raw.try_lock() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_guard_unchecked() }) + } else { + None + } + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `Mutex` mutably, no actual locking needs to + /// take place---the mutable borrow statically guarantees no locks exist. + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { &mut *self.data.get() } + } + + /// Checks whether the mutex is currently locked. + #[inline] + pub fn is_locked(&self) -> bool { + self.raw.is_locked() + } + + /// Forcibly unlocks the mutex. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `MutexGuard` object alive, for example when + /// dealing with FFI. + /// + /// # Safety + /// + /// This method must only be called if the current thread logically owns a + /// `MutexGuard` but that guard has been discarded using `mem::forget`. + /// Behavior is undefined if a mutex is unlocked when not locked. + #[inline] + pub unsafe fn force_unlock(&self) { + self.raw.unlock(); + } + + /// Returns the underlying raw mutex object. + /// + /// Note that you will most likely need to import the `RawMutex` trait from + /// `lock_api` to be able to call functions on the raw mutex. + /// + /// # Safety + /// + /// This method is unsafe because it allows unlocking a mutex while + /// still holding a reference to a `MutexGuard`. + #[inline] + pub unsafe fn raw(&self) -> &R { + &self.raw + } + + /// Returns a raw pointer to the underlying data. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `MutexGuard` object alive, for example when + /// dealing with FFI. + /// + /// # Safety + /// + /// You must ensure that there are no data races when dereferencing the + /// returned pointer, for example if the current thread logically owns + /// a `MutexGuard` but that guard has been discarded using `mem::forget`. + #[inline] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } + + /// Creates a new `ArcMutexGuard` without checking if the mutex is locked. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds the lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn make_arc_guard_unchecked(self: &Arc) -> ArcMutexGuard { + ArcMutexGuard { + mutex: self.clone(), + marker: PhantomData, + } + } + + /// Acquires a lock through an `Arc`. + /// + /// This method is similar to the `lock` method; however, it requires the `Mutex` to be inside of an `Arc` + /// and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn lock_arc(self: &Arc) -> ArcMutexGuard { + self.raw.lock(); + // SAFETY: the locking guarantee is upheld + unsafe { self.make_arc_guard_unchecked() } + } + + /// Attempts to acquire a lock through an `Arc`. + /// + /// This method is similar to the `try_lock` method; however, it requires the `Mutex` to be inside of an + /// `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_arc(self: &Arc) -> Option> { + if self.raw.try_lock() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_guard_unchecked() }) + } else { + None + } + } +} + +impl Mutex { + /// Forcibly unlocks the mutex using a fair unlock procotol. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `MutexGuard` object alive, for example when + /// dealing with FFI. + /// + /// # Safety + /// + /// This method must only be called if the current thread logically owns a + /// `MutexGuard` but that guard has been discarded using `mem::forget`. + /// Behavior is undefined if a mutex is unlocked when not locked. + #[inline] + pub unsafe fn force_unlock_fair(&self) { + self.raw.unlock_fair(); + } +} + +impl Mutex { + /// Attempts to acquire this lock until a timeout is reached. + /// + /// If the lock could not be acquired before the timeout expired, then + /// `None` is returned. Otherwise, an RAII guard is returned. The lock will + /// be unlocked when the guard is dropped. + #[inline] + pub fn try_lock_for(&self, timeout: R::Duration) -> Option> { + if self.raw.try_lock_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this lock until a timeout is reached. + /// + /// If the lock could not be acquired before the timeout expired, then + /// `None` is returned. Otherwise, an RAII guard is returned. The lock will + /// be unlocked when the guard is dropped. + #[inline] + pub fn try_lock_until(&self, timeout: R::Instant) -> Option> { + if self.raw.try_lock_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this lock through an `Arc` until a timeout is reached. + /// + /// This method is similar to the `try_lock_for` method; however, it requires the `Mutex` to be inside of an + /// `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_arc_for(self: &Arc, timeout: R::Duration) -> Option> { + if self.raw.try_lock_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this lock through an `Arc` until a timeout is reached. + /// + /// This method is similar to the `try_lock_until` method; however, it requires the `Mutex` to be inside of + /// an `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_arc_until( + self: &Arc, + timeout: R::Instant, + ) -> Option> { + if self.raw.try_lock_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_guard_unchecked() }) + } else { + None + } + } +} + +impl Default for Mutex { + #[inline] + fn default() -> Mutex { + Mutex::new(Default::default()) + } +} + +impl From for Mutex { + #[inline] + fn from(t: T) -> Mutex { + Mutex::new(t) + } +} + +impl fmt::Debug for Mutex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.try_lock() { + Some(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), + None => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("") + } + } + + f.debug_struct("Mutex") + .field("data", &LockedPlaceholder) + .finish() + } + } + } +} + +// Copied and modified from serde +#[cfg(feature = "serde")] +impl Serialize for Mutex +where + R: RawMutex, + T: Serialize + ?Sized, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.lock().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, R, T> Deserialize<'de> for Mutex +where + R: RawMutex, + T: Deserialize<'de> + ?Sized, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(Mutex::new) + } +} + +/// An RAII implementation of a "scoped lock" of a mutex. When this structure is +/// dropped (falls out of scope), the lock will be unlocked. +/// +/// The data protected by the mutex can be accessed through this guard via its +/// `Deref` and `DerefMut` implementations. +#[clippy::has_significant_drop] +#[must_use = "if unused the Mutex will immediately unlock"] +pub struct MutexGuard<'a, R: RawMutex, T: ?Sized> { + mutex: &'a Mutex, + marker: PhantomData<(&'a mut T, R::GuardMarker)>, +} + +unsafe impl<'a, R: RawMutex + Sync + 'a, T: ?Sized + Sync + 'a> Sync for MutexGuard<'a, R, T> {} + +impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> MutexGuard<'a, R, T> { + /// Returns a reference to the original `Mutex` object. + pub fn mutex(s: &Self) -> &'a Mutex { + s.mutex + } + + /// Makes a new `MappedMutexGuard` for a component of the locked data. + /// + /// This operation cannot fail as the `MutexGuard` passed + /// in already locked the mutex. + /// + /// This is an associated function that needs to be + /// used as `MutexGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn map(s: Self, f: F) -> MappedMutexGuard<'a, R, U> + where + F: FnOnce(&mut T) -> &mut U, + { + let raw = &s.mutex.raw; + let data = f(unsafe { &mut *s.mutex.data.get() }); + mem::forget(s); + MappedMutexGuard { + raw, + data, + marker: PhantomData, + } + } + + /// Attempts to make a new `MappedMutexGuard` for a component of the + /// locked data. The original guard is returned if the closure returns `None`. + /// + /// This operation cannot fail as the `MutexGuard` passed + /// in already locked the mutex. + /// + /// This is an associated function that needs to be + /// used as `MutexGuard::try_map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn try_map(s: Self, f: F) -> Result, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + { + let raw = &s.mutex.raw; + let data = match f(unsafe { &mut *s.mutex.data.get() }) { + Some(data) => data, + None => return Err(s), + }; + mem::forget(s); + Ok(MappedMutexGuard { + raw, + data, + marker: PhantomData, + }) + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the mutex. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.unlock(); + } + defer!(s.mutex.raw.lock()); + f() + } + + /// Leaks the mutex guard and returns a mutable reference to the data + /// protected by the mutex. + /// + /// This will leave the `Mutex` in a locked state. + #[inline] + pub fn leak(s: Self) -> &'a mut T { + let r = unsafe { &mut *s.mutex.data.get() }; + mem::forget(s); + r + } +} + +impl<'a, R: RawMutexFair + 'a, T: ?Sized + 'a> MutexGuard<'a, R, T> { + /// Unlocks the mutex using a fair unlock protocol. + /// + /// By default, mutexes are unfair and allow the current thread to re-lock + /// the mutex before another has the chance to acquire the lock, even if + /// that thread has been blocked on the mutex for a long time. This is the + /// default because it allows much higher throughput as it avoids forcing a + /// context switch on every mutex unlock. This can result in one thread + /// acquiring a mutex many more times than other threads. + /// + /// However in some cases it can be beneficial to ensure fairness by forcing + /// the lock to pass on to a waiting thread if there is one. This is done by + /// using this method instead of dropping the `MutexGuard` normally. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.unlock_fair(); + } + mem::forget(s); + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// The mutex is unlocked using a fair unlock protocol. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the mutex. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.unlock_fair(); + } + defer!(s.mutex.raw.lock()); + f() + } + + /// Temporarily yields the mutex to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_fair` followed + /// by `lock`, however it can be much more efficient in the case where there + /// are no waiting threads. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.bump(); + } + } +} + +impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Deref for MutexGuard<'a, R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.mutex.data.get() } + } +} + +impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> DerefMut for MutexGuard<'a, R, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.mutex.data.get() } + } +} + +impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Drop for MutexGuard<'a, R, T> { + #[inline] + fn drop(&mut self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + self.mutex.raw.unlock(); + } + } +} + +impl<'a, R: RawMutex + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for MutexGuard<'a, R, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R: RawMutex + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display for MutexGuard<'a, R, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[cfg(feature = "owning_ref")] +unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MutexGuard<'a, R, T> {} + +/// An RAII mutex guard returned by the `Arc` locking operations on `Mutex`. +/// +/// This is similar to the `MutexGuard` struct, except instead of using a reference to unlock the `Mutex` it +/// uses an `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] +#[must_use = "if unused the Mutex will immediately unlock"] +pub struct ArcMutexGuard { + mutex: Arc>, + marker: PhantomData<*const ()>, +} + +#[cfg(feature = "arc_lock")] +unsafe impl Send for ArcMutexGuard where + R::GuardMarker: Send +{ +} +#[cfg(feature = "arc_lock")] +unsafe impl Sync for ArcMutexGuard where + R::GuardMarker: Sync +{ +} + +#[cfg(feature = "arc_lock")] +impl ArcMutexGuard { + /// Returns a reference to the `Mutex` this is guarding, contained in its `Arc`. + #[inline] + pub fn mutex(s: &Self) -> &Arc> { + &s.mutex + } + + /// Unlocks the mutex and returns the `Arc` that was held by the [`ArcMutexGuard`]. + #[inline] + pub fn into_arc(s: Self) -> Arc> { + // Safety: Skip our Drop impl and manually unlock the mutex. + let arc = unsafe { ptr::read(&s.mutex) }; + mem::forget(s); + unsafe { + arc.raw.unlock(); + } + arc + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the mutex. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.unlock(); + } + defer!(s.mutex.raw.lock()); + f() + } +} + +#[cfg(feature = "arc_lock")] +impl ArcMutexGuard { + /// Unlocks the mutex using a fair unlock protocol. + /// + /// This is functionally identical to the `unlock_fair` method on [`MutexGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.unlock_fair(); + } + + // SAFETY: make sure the Arc gets it reference decremented + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.mutex) }; + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is functionally identical to the `unlocked_fair` method on [`MutexGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.unlock_fair(); + } + defer!(s.mutex.raw.lock()); + f() + } + + /// Temporarily yields the mutex to a waiting thread if there is one. + /// + /// This is functionally identical to the `bump` method on [`MutexGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.mutex.raw.bump(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl Deref for ArcMutexGuard { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.mutex.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl DerefMut for ArcMutexGuard { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.mutex.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl Drop for ArcMutexGuard { + #[inline] + fn drop(&mut self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + self.mutex.raw.unlock(); + } + } +} + +/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a +/// subfield of the protected data. +/// +/// The main difference between `MappedMutexGuard` and `MutexGuard` is that the +/// former doesn't support temporarily unlocking and re-locking, since that +/// could introduce soundness issues if the locked object is modified by another +/// thread. +#[clippy::has_significant_drop] +#[must_use = "if unused the Mutex will immediately unlock"] +pub struct MappedMutexGuard<'a, R: RawMutex, T: ?Sized> { + raw: &'a R, + data: *mut T, + marker: PhantomData<&'a mut T>, +} + +unsafe impl<'a, R: RawMutex + Sync + 'a, T: ?Sized + Sync + 'a> Sync + for MappedMutexGuard<'a, R, T> +{ +} +unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + Send + 'a> Send for MappedMutexGuard<'a, R, T> where + R::GuardMarker: Send +{ +} + +impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> MappedMutexGuard<'a, R, T> { + /// Makes a new `MappedMutexGuard` for a component of the locked data. + /// + /// This operation cannot fail as the `MappedMutexGuard` passed + /// in already locked the mutex. + /// + /// This is an associated function that needs to be + /// used as `MappedMutexGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn map(s: Self, f: F) -> MappedMutexGuard<'a, R, U> + where + F: FnOnce(&mut T) -> &mut U, + { + let raw = s.raw; + let data = f(unsafe { &mut *s.data }); + mem::forget(s); + MappedMutexGuard { + raw, + data, + marker: PhantomData, + } + } + + /// Attempts to make a new `MappedMutexGuard` for a component of the + /// locked data. The original guard is returned if the closure returns `None`. + /// + /// This operation cannot fail as the `MappedMutexGuard` passed + /// in already locked the mutex. + /// + /// This is an associated function that needs to be + /// used as `MappedMutexGuard::try_map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn try_map(s: Self, f: F) -> Result, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + { + let raw = s.raw; + let data = match f(unsafe { &mut *s.data }) { + Some(data) => data, + None => return Err(s), + }; + mem::forget(s); + Ok(MappedMutexGuard { + raw, + data, + marker: PhantomData, + }) + } +} + +impl<'a, R: RawMutexFair + 'a, T: ?Sized + 'a> MappedMutexGuard<'a, R, T> { + /// Unlocks the mutex using a fair unlock protocol. + /// + /// By default, mutexes are unfair and allow the current thread to re-lock + /// the mutex before another has the chance to acquire the lock, even if + /// that thread has been blocked on the mutex for a long time. This is the + /// default because it allows much higher throughput as it avoids forcing a + /// context switch on every mutex unlock. This can result in one thread + /// acquiring a mutex many more times than other threads. + /// + /// However in some cases it can be beneficial to ensure fairness by forcing + /// the lock to pass on to a waiting thread if there is one. This is done by + /// using this method instead of dropping the `MutexGuard` normally. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A MutexGuard always holds the lock. + unsafe { + s.raw.unlock_fair(); + } + mem::forget(s); + } +} + +impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Deref for MappedMutexGuard<'a, R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.data } + } +} + +impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> DerefMut for MappedMutexGuard<'a, R, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.data } + } +} + +impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Drop for MappedMutexGuard<'a, R, T> { + #[inline] + fn drop(&mut self) { + // Safety: A MappedMutexGuard always holds the lock. + unsafe { + self.raw.unlock(); + } + } +} + +impl<'a, R: RawMutex + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for MappedMutexGuard<'a, R, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R: RawMutex + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display + for MappedMutexGuard<'a, R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[cfg(feature = "owning_ref")] +unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MappedMutexGuard<'a, R, T> {} diff --git a/vendor/lock_api/src/remutex.rs b/vendor/lock_api/src/remutex.rs new file mode 100644 index 0000000..74f2da3 --- /dev/null +++ b/vendor/lock_api/src/remutex.rs @@ -0,0 +1,1051 @@ +// Copyright 2018 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use crate::{ + mutex::{RawMutex, RawMutexFair, RawMutexTimed}, + GuardNoSend, +}; +use core::{ + cell::{Cell, UnsafeCell}, + fmt, + marker::PhantomData, + mem, + num::NonZeroUsize, + ops::Deref, + sync::atomic::{AtomicUsize, Ordering}, +}; + +#[cfg(feature = "arc_lock")] +use alloc::sync::Arc; +#[cfg(feature = "arc_lock")] +use core::mem::ManuallyDrop; +#[cfg(feature = "arc_lock")] +use core::ptr; + +#[cfg(feature = "owning_ref")] +use owning_ref::StableAddress; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// Helper trait which returns a non-zero thread ID. +/// +/// The simplest way to implement this trait is to return the address of a +/// thread-local variable. +/// +/// # Safety +/// +/// Implementations of this trait must ensure that no two active threads share +/// the same thread ID. However the ID of a thread that has exited can be +/// re-used since that thread is no longer active. +pub unsafe trait GetThreadId { + /// Initial value. + // A “non-constant” const item is a legacy way to supply an initialized value to downstream + // static items. Can hopefully be replaced with `const fn new() -> Self` at some point. + #[allow(clippy::declare_interior_mutable_const)] + const INIT: Self; + + /// Returns a non-zero thread ID which identifies the current thread of + /// execution. + fn nonzero_thread_id(&self) -> NonZeroUsize; +} + +/// A raw mutex type that wraps another raw mutex to provide reentrancy. +/// +/// Although this has the same methods as the [`RawMutex`] trait, it does +/// not implement it, and should not be used in the same way, since this +/// mutex can successfully acquire a lock multiple times in the same thread. +/// Only use this when you know you want a raw mutex that can be locked +/// reentrantly; you probably want [`ReentrantMutex`] instead. +/// +/// [`RawMutex`]: trait.RawMutex.html +/// [`ReentrantMutex`]: struct.ReentrantMutex.html +pub struct RawReentrantMutex { + owner: AtomicUsize, + lock_count: Cell, + mutex: R, + get_thread_id: G, +} + +unsafe impl Send for RawReentrantMutex {} +unsafe impl Sync for RawReentrantMutex {} + +impl RawReentrantMutex { + /// Initial value for an unlocked mutex. + #[allow(clippy::declare_interior_mutable_const)] + pub const INIT: Self = RawReentrantMutex { + owner: AtomicUsize::new(0), + lock_count: Cell::new(0), + mutex: R::INIT, + get_thread_id: G::INIT, + }; + + #[inline] + fn lock_internal bool>(&self, try_lock: F) -> bool { + let id = self.get_thread_id.nonzero_thread_id().get(); + if self.owner.load(Ordering::Relaxed) == id { + self.lock_count.set( + self.lock_count + .get() + .checked_add(1) + .expect("ReentrantMutex lock count overflow"), + ); + } else { + if !try_lock() { + return false; + } + self.owner.store(id, Ordering::Relaxed); + debug_assert_eq!(self.lock_count.get(), 0); + self.lock_count.set(1); + } + true + } + + /// Acquires this mutex, blocking if it's held by another thread. + #[inline] + pub fn lock(&self) { + self.lock_internal(|| { + self.mutex.lock(); + true + }); + } + + /// Attempts to acquire this mutex without blocking. Returns `true` + /// if the lock was successfully acquired and `false` otherwise. + #[inline] + pub fn try_lock(&self) -> bool { + self.lock_internal(|| self.mutex.try_lock()) + } + + /// Unlocks this mutex. The inner mutex may not be unlocked if + /// this mutex was acquired previously in the current thread. + /// + /// # Safety + /// + /// This method may only be called if the mutex is held by the current thread. + #[inline] + pub unsafe fn unlock(&self) { + let lock_count = self.lock_count.get() - 1; + self.lock_count.set(lock_count); + if lock_count == 0 { + self.owner.store(0, Ordering::Relaxed); + self.mutex.unlock(); + } + } + + /// Checks whether the mutex is currently locked. + #[inline] + pub fn is_locked(&self) -> bool { + self.mutex.is_locked() + } + + /// Checks whether the mutex is currently held by the current thread. + #[inline] + pub fn is_owned_by_current_thread(&self) -> bool { + let id = self.get_thread_id.nonzero_thread_id().get(); + self.owner.load(Ordering::Relaxed) == id + } +} + +impl RawReentrantMutex { + /// Unlocks this mutex using a fair unlock protocol. The inner mutex + /// may not be unlocked if this mutex was acquired previously in the + /// current thread. + /// + /// # Safety + /// + /// This method may only be called if the mutex is held by the current thread. + #[inline] + pub unsafe fn unlock_fair(&self) { + let lock_count = self.lock_count.get() - 1; + self.lock_count.set(lock_count); + if lock_count == 0 { + self.owner.store(0, Ordering::Relaxed); + self.mutex.unlock_fair(); + } + } + + /// Temporarily yields the mutex to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_fair` followed + /// by `lock`, however it can be much more efficient in the case where there + /// are no waiting threads. + /// + /// # Safety + /// + /// This method may only be called if the mutex is held by the current thread. + #[inline] + pub unsafe fn bump(&self) { + if self.lock_count.get() == 1 { + let id = self.owner.load(Ordering::Relaxed); + self.owner.store(0, Ordering::Relaxed); + self.lock_count.set(0); + self.mutex.bump(); + self.owner.store(id, Ordering::Relaxed); + self.lock_count.set(1); + } + } +} + +impl RawReentrantMutex { + /// Attempts to acquire this lock until a timeout is reached. + #[inline] + pub fn try_lock_until(&self, timeout: R::Instant) -> bool { + self.lock_internal(|| self.mutex.try_lock_until(timeout)) + } + + /// Attempts to acquire this lock until a timeout is reached. + #[inline] + pub fn try_lock_for(&self, timeout: R::Duration) -> bool { + self.lock_internal(|| self.mutex.try_lock_for(timeout)) + } +} + +/// A mutex which can be recursively locked by a single thread. +/// +/// This type is identical to `Mutex` except for the following points: +/// +/// - Locking multiple times from the same thread will work correctly instead of +/// deadlocking. +/// - `ReentrantMutexGuard` does not give mutable references to the locked data. +/// Use a `RefCell` if you need this. +/// +/// See [`Mutex`](struct.Mutex.html) for more details about the underlying mutex +/// primitive. +pub struct ReentrantMutex { + raw: RawReentrantMutex, + data: UnsafeCell, +} + +unsafe impl Send + for ReentrantMutex +{ +} +unsafe impl Sync + for ReentrantMutex +{ +} + +impl ReentrantMutex { + /// Creates a new reentrant mutex in an unlocked state ready for use. + #[cfg(has_const_fn_trait_bound)] + #[inline] + pub const fn new(val: T) -> ReentrantMutex { + ReentrantMutex { + data: UnsafeCell::new(val), + raw: RawReentrantMutex { + owner: AtomicUsize::new(0), + lock_count: Cell::new(0), + mutex: R::INIT, + get_thread_id: G::INIT, + }, + } + } + + /// Creates a new reentrant mutex in an unlocked state ready for use. + #[cfg(not(has_const_fn_trait_bound))] + #[inline] + pub fn new(val: T) -> ReentrantMutex { + ReentrantMutex { + data: UnsafeCell::new(val), + raw: RawReentrantMutex { + owner: AtomicUsize::new(0), + lock_count: Cell::new(0), + mutex: R::INIT, + get_thread_id: G::INIT, + }, + } + } + + /// Consumes this mutex, returning the underlying data. + #[inline] + pub fn into_inner(self) -> T { + self.data.into_inner() + } +} + +impl ReentrantMutex { + /// Creates a new reentrant mutex based on a pre-existing raw mutex and a + /// helper to get the thread ID. + /// + /// This allows creating a reentrant mutex in a constant context on stable + /// Rust. + #[inline] + pub const fn const_new(raw_mutex: R, get_thread_id: G, val: T) -> ReentrantMutex { + ReentrantMutex { + data: UnsafeCell::new(val), + raw: RawReentrantMutex { + owner: AtomicUsize::new(0), + lock_count: Cell::new(0), + mutex: raw_mutex, + get_thread_id, + }, + } + } +} + +impl ReentrantMutex { + /// Creates a new `ReentrantMutexGuard` without checking if the lock is held. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds the lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. + #[inline] + pub unsafe fn make_guard_unchecked(&self) -> ReentrantMutexGuard<'_, R, G, T> { + ReentrantMutexGuard { + remutex: &self, + marker: PhantomData, + } + } + + /// Acquires a reentrant mutex, blocking the current thread until it is able + /// to do so. + /// + /// If the mutex is held by another thread then this function will block the + /// local thread until it is available to acquire the mutex. If the mutex is + /// already held by the current thread then this function will increment the + /// lock reference count and return immediately. Upon returning, + /// the thread is the only thread with the mutex held. An RAII guard is + /// returned to allow scoped unlock of the lock. When the guard goes out of + /// scope, the mutex will be unlocked. + #[inline] + pub fn lock(&self) -> ReentrantMutexGuard<'_, R, G, T> { + self.raw.lock(); + // SAFETY: The lock is held, as required. + unsafe { self.make_guard_unchecked() } + } + + /// Attempts to acquire this lock. + /// + /// If the lock could not be acquired at this time, then `None` is returned. + /// Otherwise, an RAII guard is returned. The lock will be unlocked when the + /// guard is dropped. + /// + /// This function does not block. + #[inline] + pub fn try_lock(&self) -> Option> { + if self.raw.try_lock() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_guard_unchecked() }) + } else { + None + } + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `ReentrantMutex` mutably, no actual locking needs to + /// take place---the mutable borrow statically guarantees no locks exist. + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { &mut *self.data.get() } + } + + /// Checks whether the mutex is currently locked. + #[inline] + pub fn is_locked(&self) -> bool { + self.raw.is_locked() + } + + /// Checks whether the mutex is currently held by the current thread. + #[inline] + pub fn is_owned_by_current_thread(&self) -> bool { + self.raw.is_owned_by_current_thread() + } + + /// Forcibly unlocks the mutex. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `ReentrantMutexGuard` object alive, for example when + /// dealing with FFI. + /// + /// # Safety + /// + /// This method must only be called if the current thread logically owns a + /// `ReentrantMutexGuard` but that guard has be discarded using `mem::forget`. + /// Behavior is undefined if a mutex is unlocked when not locked. + #[inline] + pub unsafe fn force_unlock(&self) { + self.raw.unlock(); + } + + /// Returns the underlying raw mutex object. + /// + /// Note that you will most likely need to import the `RawMutex` trait from + /// `lock_api` to be able to call functions on the raw mutex. + /// + /// # Safety + /// + /// This method is unsafe because it allows unlocking a mutex while + /// still holding a reference to a `ReentrantMutexGuard`. + #[inline] + pub unsafe fn raw(&self) -> &R { + &self.raw.mutex + } + + /// Returns a raw pointer to the underlying data. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `ReentrantMutexGuard` object alive, for example + /// when dealing with FFI. + /// + /// # Safety + /// + /// You must ensure that there are no data races when dereferencing the + /// returned pointer, for example if the current thread logically owns a + /// `ReentrantMutexGuard` but that guard has been discarded using + /// `mem::forget`. + #[inline] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } + + /// Creates a new `ArcReentrantMutexGuard` without checking if the lock is held. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds the lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. + #[cfg(feature = "arc_lock")] + #[inline] + pub unsafe fn make_arc_guard_unchecked(self: &Arc) -> ArcReentrantMutexGuard { + ArcReentrantMutexGuard { + remutex: self.clone(), + marker: PhantomData, + } + } + + /// Acquires a reentrant mutex through an `Arc`. + /// + /// This method is similar to the `lock` method; however, it requires the `ReentrantMutex` to be inside of an + /// `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn lock_arc(self: &Arc) -> ArcReentrantMutexGuard { + self.raw.lock(); + // SAFETY: locking guarantee is upheld + unsafe { self.make_arc_guard_unchecked() } + } + + /// Attempts to acquire a reentrant mutex through an `Arc`. + /// + /// This method is similar to the `try_lock` method; however, it requires the `ReentrantMutex` to be inside + /// of an `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_arc(self: &Arc) -> Option> { + if self.raw.try_lock() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_guard_unchecked() }) + } else { + None + } + } +} + +impl ReentrantMutex { + /// Forcibly unlocks the mutex using a fair unlock protocol. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `ReentrantMutexGuard` object alive, for example when + /// dealing with FFI. + /// + /// # Safety + /// + /// This method must only be called if the current thread logically owns a + /// `ReentrantMutexGuard` but that guard has be discarded using `mem::forget`. + /// Behavior is undefined if a mutex is unlocked when not locked. + #[inline] + pub unsafe fn force_unlock_fair(&self) { + self.raw.unlock_fair(); + } +} + +impl ReentrantMutex { + /// Attempts to acquire this lock until a timeout is reached. + /// + /// If the lock could not be acquired before the timeout expired, then + /// `None` is returned. Otherwise, an RAII guard is returned. The lock will + /// be unlocked when the guard is dropped. + #[inline] + pub fn try_lock_for(&self, timeout: R::Duration) -> Option> { + if self.raw.try_lock_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this lock until a timeout is reached. + /// + /// If the lock could not be acquired before the timeout expired, then + /// `None` is returned. Otherwise, an RAII guard is returned. The lock will + /// be unlocked when the guard is dropped. + #[inline] + pub fn try_lock_until(&self, timeout: R::Instant) -> Option> { + if self.raw.try_lock_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this lock until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_lock_for` method; however, it requires the `ReentrantMutex` to be + /// inside of an `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_arc_for( + self: &Arc, + timeout: R::Duration, + ) -> Option> { + if self.raw.try_lock_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this lock until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_lock_until` method; however, it requires the `ReentrantMutex` to be + /// inside of an `Arc` and the resulting mutex guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_lock_arc_until( + self: &Arc, + timeout: R::Instant, + ) -> Option> { + if self.raw.try_lock_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_guard_unchecked() }) + } else { + None + } + } +} + +impl Default for ReentrantMutex { + #[inline] + fn default() -> ReentrantMutex { + ReentrantMutex::new(Default::default()) + } +} + +impl From for ReentrantMutex { + #[inline] + fn from(t: T) -> ReentrantMutex { + ReentrantMutex::new(t) + } +} + +impl fmt::Debug for ReentrantMutex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.try_lock() { + Some(guard) => f + .debug_struct("ReentrantMutex") + .field("data", &&*guard) + .finish(), + None => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("") + } + } + + f.debug_struct("ReentrantMutex") + .field("data", &LockedPlaceholder) + .finish() + } + } + } +} + +// Copied and modified from serde +#[cfg(feature = "serde")] +impl Serialize for ReentrantMutex +where + R: RawMutex, + G: GetThreadId, + T: Serialize + ?Sized, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.lock().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, R, G, T> Deserialize<'de> for ReentrantMutex +where + R: RawMutex, + G: GetThreadId, + T: Deserialize<'de> + ?Sized, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(ReentrantMutex::new) + } +} + +/// An RAII implementation of a "scoped lock" of a reentrant mutex. When this structure +/// is dropped (falls out of scope), the lock will be unlocked. +/// +/// The data protected by the mutex can be accessed through this guard via its +/// `Deref` implementation. +#[clippy::has_significant_drop] +#[must_use = "if unused the ReentrantMutex will immediately unlock"] +pub struct ReentrantMutexGuard<'a, R: RawMutex, G: GetThreadId, T: ?Sized> { + remutex: &'a ReentrantMutex, + marker: PhantomData<(&'a T, GuardNoSend)>, +} + +unsafe impl<'a, R: RawMutex + Sync + 'a, G: GetThreadId + Sync + 'a, T: ?Sized + Sync + 'a> Sync + for ReentrantMutexGuard<'a, R, G, T> +{ +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> ReentrantMutexGuard<'a, R, G, T> { + /// Returns a reference to the original `ReentrantMutex` object. + pub fn remutex(s: &Self) -> &'a ReentrantMutex { + s.remutex + } + + /// Makes a new `MappedReentrantMutexGuard` for a component of the locked data. + /// + /// This operation cannot fail as the `ReentrantMutexGuard` passed + /// in already locked the mutex. + /// + /// This is an associated function that needs to be + /// used as `ReentrantMutexGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn map(s: Self, f: F) -> MappedReentrantMutexGuard<'a, R, G, U> + where + F: FnOnce(&T) -> &U, + { + let raw = &s.remutex.raw; + let data = f(unsafe { &*s.remutex.data.get() }); + mem::forget(s); + MappedReentrantMutexGuard { + raw, + data, + marker: PhantomData, + } + } + + /// Attempts to make a new `MappedReentrantMutexGuard` for a component of the + /// locked data. The original guard is return if the closure returns `None`. + /// + /// This operation cannot fail as the `ReentrantMutexGuard` passed + /// in already locked the mutex. + /// + /// This is an associated function that needs to be + /// used as `ReentrantMutexGuard::try_map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn try_map( + s: Self, + f: F, + ) -> Result, Self> + where + F: FnOnce(&T) -> Option<&U>, + { + let raw = &s.remutex.raw; + let data = match f(unsafe { &*s.remutex.data.get() }) { + Some(data) => data, + None => return Err(s), + }; + mem::forget(s); + Ok(MappedReentrantMutexGuard { + raw, + data, + marker: PhantomData, + }) + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the mutex. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A ReentrantMutexGuard always holds the lock. + unsafe { + s.remutex.raw.unlock(); + } + defer!(s.remutex.raw.lock()); + f() + } +} + +impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> + ReentrantMutexGuard<'a, R, G, T> +{ + /// Unlocks the mutex using a fair unlock protocol. + /// + /// By default, mutexes are unfair and allow the current thread to re-lock + /// the mutex before another has the chance to acquire the lock, even if + /// that thread has been blocked on the mutex for a long time. This is the + /// default because it allows much higher throughput as it avoids forcing a + /// context switch on every mutex unlock. This can result in one thread + /// acquiring a mutex many more times than other threads. + /// + /// However in some cases it can be beneficial to ensure fairness by forcing + /// the lock to pass on to a waiting thread if there is one. This is done by + /// using this method instead of dropping the `ReentrantMutexGuard` normally. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A ReentrantMutexGuard always holds the lock + unsafe { + s.remutex.raw.unlock_fair(); + } + mem::forget(s); + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// The mutex is unlocked a fair unlock protocol. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the mutex. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A ReentrantMutexGuard always holds the lock + unsafe { + s.remutex.raw.unlock_fair(); + } + defer!(s.remutex.raw.lock()); + f() + } + + /// Temporarily yields the mutex to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_fair` followed + /// by `lock`, however it can be much more efficient in the case where there + /// are no waiting threads. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: A ReentrantMutexGuard always holds the lock + unsafe { + s.remutex.raw.bump(); + } + } +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Deref + for ReentrantMutexGuard<'a, R, G, T> +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.remutex.data.get() } + } +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Drop + for ReentrantMutexGuard<'a, R, G, T> +{ + #[inline] + fn drop(&mut self) { + // Safety: A ReentrantMutexGuard always holds the lock. + unsafe { + self.remutex.raw.unlock(); + } + } +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug + for ReentrantMutexGuard<'a, R, G, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display + for ReentrantMutexGuard<'a, R, G, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[cfg(feature = "owning_ref")] +unsafe impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> StableAddress + for ReentrantMutexGuard<'a, R, G, T> +{ +} + +/// An RAII mutex guard returned by the `Arc` locking operations on `ReentrantMutex`. +/// +/// This is similar to the `ReentrantMutexGuard` struct, except instead of using a reference to unlock the +/// `Mutex` it uses an `Arc`. This has several advantages, most notably that it has an `'static` +/// lifetime. +#[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] +#[must_use = "if unused the ReentrantMutex will immediately unlock"] +pub struct ArcReentrantMutexGuard { + remutex: Arc>, + marker: PhantomData, +} + +#[cfg(feature = "arc_lock")] +impl ArcReentrantMutexGuard { + /// Returns a reference to the `ReentrantMutex` this object is guarding, contained in its `Arc`. + pub fn remutex(s: &Self) -> &Arc> { + &s.remutex + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the mutex. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A ReentrantMutexGuard always holds the lock. + unsafe { + s.remutex.raw.unlock(); + } + defer!(s.remutex.raw.lock()); + f() + } +} + +#[cfg(feature = "arc_lock")] +impl ArcReentrantMutexGuard { + /// Unlocks the mutex using a fair unlock protocol. + /// + /// This is functionally identical to the `unlock_fair` method on [`ReentrantMutexGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A ReentrantMutexGuard always holds the lock + unsafe { + s.remutex.raw.unlock_fair(); + } + + // SAFETY: ensure that the Arc's refcount is decremented + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.remutex) }; + } + + /// Temporarily unlocks the mutex to execute the given function. + /// + /// This is functionally identical to the `unlocked_fair` method on [`ReentrantMutexGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: A ReentrantMutexGuard always holds the lock + unsafe { + s.remutex.raw.unlock_fair(); + } + defer!(s.remutex.raw.lock()); + f() + } + + /// Temporarily yields the mutex to a waiting thread if there is one. + /// + /// This is functionally equivalent to the `bump` method on [`ReentrantMutexGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: A ReentrantMutexGuard always holds the lock + unsafe { + s.remutex.raw.bump(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl Deref for ArcReentrantMutexGuard { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.remutex.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl Drop for ArcReentrantMutexGuard { + #[inline] + fn drop(&mut self) { + // Safety: A ReentrantMutexGuard always holds the lock. + unsafe { + self.remutex.raw.unlock(); + } + } +} + +/// An RAII mutex guard returned by `ReentrantMutexGuard::map`, which can point to a +/// subfield of the protected data. +/// +/// The main difference between `MappedReentrantMutexGuard` and `ReentrantMutexGuard` is that the +/// former doesn't support temporarily unlocking and re-locking, since that +/// could introduce soundness issues if the locked object is modified by another +/// thread. +#[clippy::has_significant_drop] +#[must_use = "if unused the ReentrantMutex will immediately unlock"] +pub struct MappedReentrantMutexGuard<'a, R: RawMutex, G: GetThreadId, T: ?Sized> { + raw: &'a RawReentrantMutex, + data: *const T, + marker: PhantomData<&'a T>, +} + +unsafe impl<'a, R: RawMutex + Sync + 'a, G: GetThreadId + Sync + 'a, T: ?Sized + Sync + 'a> Sync + for MappedReentrantMutexGuard<'a, R, G, T> +{ +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> + MappedReentrantMutexGuard<'a, R, G, T> +{ + /// Makes a new `MappedReentrantMutexGuard` for a component of the locked data. + /// + /// This operation cannot fail as the `MappedReentrantMutexGuard` passed + /// in already locked the mutex. + /// + /// This is an associated function that needs to be + /// used as `MappedReentrantMutexGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn map(s: Self, f: F) -> MappedReentrantMutexGuard<'a, R, G, U> + where + F: FnOnce(&T) -> &U, + { + let raw = s.raw; + let data = f(unsafe { &*s.data }); + mem::forget(s); + MappedReentrantMutexGuard { + raw, + data, + marker: PhantomData, + } + } + + /// Attempts to make a new `MappedReentrantMutexGuard` for a component of the + /// locked data. The original guard is return if the closure returns `None`. + /// + /// This operation cannot fail as the `MappedReentrantMutexGuard` passed + /// in already locked the mutex. + /// + /// This is an associated function that needs to be + /// used as `MappedReentrantMutexGuard::try_map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn try_map( + s: Self, + f: F, + ) -> Result, Self> + where + F: FnOnce(&T) -> Option<&U>, + { + let raw = s.raw; + let data = match f(unsafe { &*s.data }) { + Some(data) => data, + None => return Err(s), + }; + mem::forget(s); + Ok(MappedReentrantMutexGuard { + raw, + data, + marker: PhantomData, + }) + } +} + +impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> + MappedReentrantMutexGuard<'a, R, G, T> +{ + /// Unlocks the mutex using a fair unlock protocol. + /// + /// By default, mutexes are unfair and allow the current thread to re-lock + /// the mutex before another has the chance to acquire the lock, even if + /// that thread has been blocked on the mutex for a long time. This is the + /// default because it allows much higher throughput as it avoids forcing a + /// context switch on every mutex unlock. This can result in one thread + /// acquiring a mutex many more times than other threads. + /// + /// However in some cases it can be beneficial to ensure fairness by forcing + /// the lock to pass on to a waiting thread if there is one. This is done by + /// using this method instead of dropping the `ReentrantMutexGuard` normally. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A MappedReentrantMutexGuard always holds the lock + unsafe { + s.raw.unlock_fair(); + } + mem::forget(s); + } +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Deref + for MappedReentrantMutexGuard<'a, R, G, T> +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.data } + } +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Drop + for MappedReentrantMutexGuard<'a, R, G, T> +{ + #[inline] + fn drop(&mut self) { + // Safety: A MappedReentrantMutexGuard always holds the lock. + unsafe { + self.raw.unlock(); + } + } +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug + for MappedReentrantMutexGuard<'a, R, G, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display + for MappedReentrantMutexGuard<'a, R, G, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[cfg(feature = "owning_ref")] +unsafe impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> StableAddress + for MappedReentrantMutexGuard<'a, R, G, T> +{ +} diff --git a/vendor/lock_api/src/rwlock.rs b/vendor/lock_api/src/rwlock.rs new file mode 100644 index 0000000..cf9e8aa --- /dev/null +++ b/vendor/lock_api/src/rwlock.rs @@ -0,0 +1,2883 @@ +// Copyright 2016 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use core::cell::UnsafeCell; +use core::fmt; +use core::marker::PhantomData; +use core::mem; +use core::ops::{Deref, DerefMut}; + +#[cfg(feature = "arc_lock")] +use alloc::sync::Arc; +#[cfg(feature = "arc_lock")] +use core::mem::ManuallyDrop; +#[cfg(feature = "arc_lock")] +use core::ptr; + +#[cfg(feature = "owning_ref")] +use owning_ref::StableAddress; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// Basic operations for a reader-writer lock. +/// +/// Types implementing this trait can be used by `RwLock` to form a safe and +/// fully-functioning `RwLock` type. +/// +/// # Safety +/// +/// Implementations of this trait must ensure that the `RwLock` is actually +/// exclusive: an exclusive lock can't be acquired while an exclusive or shared +/// lock exists, and a shared lock can't be acquire while an exclusive lock +/// exists. +pub unsafe trait RawRwLock { + /// Initial value for an unlocked `RwLock`. + // A “non-constant” const item is a legacy way to supply an initialized value to downstream + // static items. Can hopefully be replaced with `const fn new() -> Self` at some point. + #[allow(clippy::declare_interior_mutable_const)] + const INIT: Self; + + /// Marker type which determines whether a lock guard should be `Send`. Use + /// one of the `GuardSend` or `GuardNoSend` helper types here. + type GuardMarker; + + /// Acquires a shared lock, blocking the current thread until it is able to do so. + fn lock_shared(&self); + + /// Attempts to acquire a shared lock without blocking. + fn try_lock_shared(&self) -> bool; + + /// Releases a shared lock. + /// + /// # Safety + /// + /// This method may only be called if a shared lock is held in the current context. + unsafe fn unlock_shared(&self); + + /// Acquires an exclusive lock, blocking the current thread until it is able to do so. + fn lock_exclusive(&self); + + /// Attempts to acquire an exclusive lock without blocking. + fn try_lock_exclusive(&self) -> bool; + + /// Releases an exclusive lock. + /// + /// # Safety + /// + /// This method may only be called if an exclusive lock is held in the current context. + unsafe fn unlock_exclusive(&self); + + /// Checks if this `RwLock` is currently locked in any way. + #[inline] + fn is_locked(&self) -> bool { + let acquired_lock = self.try_lock_exclusive(); + if acquired_lock { + // Safety: A lock was successfully acquired above. + unsafe { + self.unlock_exclusive(); + } + } + !acquired_lock + } + + /// Check if this `RwLock` is currently exclusively locked. + fn is_locked_exclusive(&self) -> bool { + let acquired_lock = self.try_lock_shared(); + if acquired_lock { + // Safety: A shared lock was successfully acquired above. + unsafe { + self.unlock_shared(); + } + } + !acquired_lock + } +} + +/// Additional methods for RwLocks which support fair unlocking. +/// +/// Fair unlocking means that a lock is handed directly over to the next waiting +/// thread if there is one, without giving other threads the opportunity to +/// "steal" the lock in the meantime. This is typically slower than unfair +/// unlocking, but may be necessary in certain circumstances. +pub unsafe trait RawRwLockFair: RawRwLock { + /// Releases a shared lock using a fair unlock protocol. + /// + /// # Safety + /// + /// This method may only be called if a shared lock is held in the current context. + unsafe fn unlock_shared_fair(&self); + + /// Releases an exclusive lock using a fair unlock protocol. + /// + /// # Safety + /// + /// This method may only be called if an exclusive lock is held in the current context. + unsafe fn unlock_exclusive_fair(&self); + + /// Temporarily yields a shared lock to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_shared_fair` followed + /// by `lock_shared`, however it can be much more efficient in the case where there + /// are no waiting threads. + /// + /// # Safety + /// + /// This method may only be called if a shared lock is held in the current context. + unsafe fn bump_shared(&self) { + self.unlock_shared_fair(); + self.lock_shared(); + } + + /// Temporarily yields an exclusive lock to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_exclusive_fair` followed + /// by `lock_exclusive`, however it can be much more efficient in the case where there + /// are no waiting threads. + /// + /// # Safety + /// + /// This method may only be called if an exclusive lock is held in the current context. + unsafe fn bump_exclusive(&self) { + self.unlock_exclusive_fair(); + self.lock_exclusive(); + } +} + +/// Additional methods for RwLocks which support atomically downgrading an +/// exclusive lock to a shared lock. +pub unsafe trait RawRwLockDowngrade: RawRwLock { + /// Atomically downgrades an exclusive lock into a shared lock without + /// allowing any thread to take an exclusive lock in the meantime. + /// + /// # Safety + /// + /// This method may only be called if an exclusive lock is held in the current context. + unsafe fn downgrade(&self); +} + +/// Additional methods for RwLocks which support locking with timeouts. +/// +/// The `Duration` and `Instant` types are specified as associated types so that +/// this trait is usable even in `no_std` environments. +pub unsafe trait RawRwLockTimed: RawRwLock { + /// Duration type used for `try_lock_for`. + type Duration; + + /// Instant type used for `try_lock_until`. + type Instant; + + /// Attempts to acquire a shared lock until a timeout is reached. + fn try_lock_shared_for(&self, timeout: Self::Duration) -> bool; + + /// Attempts to acquire a shared lock until a timeout is reached. + fn try_lock_shared_until(&self, timeout: Self::Instant) -> bool; + + /// Attempts to acquire an exclusive lock until a timeout is reached. + fn try_lock_exclusive_for(&self, timeout: Self::Duration) -> bool; + + /// Attempts to acquire an exclusive lock until a timeout is reached. + fn try_lock_exclusive_until(&self, timeout: Self::Instant) -> bool; +} + +/// Additional methods for RwLocks which support recursive read locks. +/// +/// These are guaranteed to succeed without blocking if +/// another read lock is held at the time of the call. This allows a thread +/// to recursively lock a `RwLock`. However using this method can cause +/// writers to starve since readers no longer block if a writer is waiting +/// for the lock. +pub unsafe trait RawRwLockRecursive: RawRwLock { + /// Acquires a shared lock without deadlocking in case of a recursive lock. + fn lock_shared_recursive(&self); + + /// Attempts to acquire a shared lock without deadlocking in case of a recursive lock. + fn try_lock_shared_recursive(&self) -> bool; +} + +/// Additional methods for RwLocks which support recursive read locks and timeouts. +pub unsafe trait RawRwLockRecursiveTimed: RawRwLockRecursive + RawRwLockTimed { + /// Attempts to acquire a shared lock until a timeout is reached, without + /// deadlocking in case of a recursive lock. + fn try_lock_shared_recursive_for(&self, timeout: Self::Duration) -> bool; + + /// Attempts to acquire a shared lock until a timeout is reached, without + /// deadlocking in case of a recursive lock. + fn try_lock_shared_recursive_until(&self, timeout: Self::Instant) -> bool; +} + +/// Additional methods for RwLocks which support atomically upgrading a shared +/// lock to an exclusive lock. +/// +/// This requires acquiring a special "upgradable read lock" instead of a +/// normal shared lock. There may only be one upgradable lock at any time, +/// otherwise deadlocks could occur when upgrading. +pub unsafe trait RawRwLockUpgrade: RawRwLock { + /// Acquires an upgradable lock, blocking the current thread until it is able to do so. + fn lock_upgradable(&self); + + /// Attempts to acquire an upgradable lock without blocking. + fn try_lock_upgradable(&self) -> bool; + + /// Releases an upgradable lock. + /// + /// # Safety + /// + /// This method may only be called if an upgradable lock is held in the current context. + unsafe fn unlock_upgradable(&self); + + /// Upgrades an upgradable lock to an exclusive lock. + /// + /// # Safety + /// + /// This method may only be called if an upgradable lock is held in the current context. + unsafe fn upgrade(&self); + + /// Attempts to upgrade an upgradable lock to an exclusive lock without + /// blocking. + /// + /// # Safety + /// + /// This method may only be called if an upgradable lock is held in the current context. + unsafe fn try_upgrade(&self) -> bool; +} + +/// Additional methods for RwLocks which support upgradable locks and fair +/// unlocking. +pub unsafe trait RawRwLockUpgradeFair: RawRwLockUpgrade + RawRwLockFair { + /// Releases an upgradable lock using a fair unlock protocol. + /// + /// # Safety + /// + /// This method may only be called if an upgradable lock is held in the current context. + unsafe fn unlock_upgradable_fair(&self); + + /// Temporarily yields an upgradable lock to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_upgradable_fair` followed + /// by `lock_upgradable`, however it can be much more efficient in the case where there + /// are no waiting threads. + /// + /// # Safety + /// + /// This method may only be called if an upgradable lock is held in the current context. + unsafe fn bump_upgradable(&self) { + self.unlock_upgradable_fair(); + self.lock_upgradable(); + } +} + +/// Additional methods for RwLocks which support upgradable locks and lock +/// downgrading. +pub unsafe trait RawRwLockUpgradeDowngrade: RawRwLockUpgrade + RawRwLockDowngrade { + /// Downgrades an upgradable lock to a shared lock. + /// + /// # Safety + /// + /// This method may only be called if an upgradable lock is held in the current context. + unsafe fn downgrade_upgradable(&self); + + /// Downgrades an exclusive lock to an upgradable lock. + /// + /// # Safety + /// + /// This method may only be called if an exclusive lock is held in the current context. + unsafe fn downgrade_to_upgradable(&self); +} + +/// Additional methods for RwLocks which support upgradable locks and locking +/// with timeouts. +pub unsafe trait RawRwLockUpgradeTimed: RawRwLockUpgrade + RawRwLockTimed { + /// Attempts to acquire an upgradable lock until a timeout is reached. + fn try_lock_upgradable_for(&self, timeout: Self::Duration) -> bool; + + /// Attempts to acquire an upgradable lock until a timeout is reached. + fn try_lock_upgradable_until(&self, timeout: Self::Instant) -> bool; + + /// Attempts to upgrade an upgradable lock to an exclusive lock until a + /// timeout is reached. + /// + /// # Safety + /// + /// This method may only be called if an upgradable lock is held in the current context. + unsafe fn try_upgrade_for(&self, timeout: Self::Duration) -> bool; + + /// Attempts to upgrade an upgradable lock to an exclusive lock until a + /// timeout is reached. + /// + /// # Safety + /// + /// This method may only be called if an upgradable lock is held in the current context. + unsafe fn try_upgrade_until(&self, timeout: Self::Instant) -> bool; +} + +/// A reader-writer lock +/// +/// This type of lock allows a number of readers or at most one writer at any +/// point in time. The write portion of this lock typically allows modification +/// of the underlying data (exclusive access) and the read portion of this lock +/// typically allows for read-only access (shared access). +/// +/// The type parameter `T` represents the data that this lock protects. It is +/// required that `T` satisfies `Send` to be shared across threads and `Sync` to +/// allow concurrent access through readers. The RAII guards returned from the +/// locking methods implement `Deref` (and `DerefMut` for the `write` methods) +/// to allow access to the contained of the lock. +pub struct RwLock { + raw: R, + data: UnsafeCell, +} + +// Copied and modified from serde +#[cfg(feature = "serde")] +impl Serialize for RwLock +where + R: RawRwLock, + T: Serialize + ?Sized, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.read().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, R, T> Deserialize<'de> for RwLock +where + R: RawRwLock, + T: Deserialize<'de> + ?Sized, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(RwLock::new) + } +} + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +impl RwLock { + /// Creates a new instance of an `RwLock` which is unlocked. + #[cfg(has_const_fn_trait_bound)] + #[inline] + pub const fn new(val: T) -> RwLock { + RwLock { + data: UnsafeCell::new(val), + raw: R::INIT, + } + } + + /// Creates a new instance of an `RwLock` which is unlocked. + #[cfg(not(has_const_fn_trait_bound))] + #[inline] + pub fn new(val: T) -> RwLock { + RwLock { + data: UnsafeCell::new(val), + raw: R::INIT, + } + } + + /// Consumes this `RwLock`, returning the underlying data. + #[inline] + #[allow(unused_unsafe)] + pub fn into_inner(self) -> T { + unsafe { self.data.into_inner() } + } +} + +impl RwLock { + /// Creates a new new instance of an `RwLock` based on a pre-existing + /// `RawRwLock`. + /// + /// This allows creating a `RwLock` in a constant context on stable + /// Rust. + #[inline] + pub const fn const_new(raw_rwlock: R, val: T) -> RwLock { + RwLock { + data: UnsafeCell::new(val), + raw: raw_rwlock, + } + } +} + +impl RwLock { + /// Creates a new `RwLockReadGuard` without checking if the lock is held. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds a read lock. + /// + /// This function does not increment the read count of the lock. Calling this function when a + /// guard has already been produced is undefined behaviour unless the guard was forgotten + /// with `mem::forget`.` + #[inline] + pub unsafe fn make_read_guard_unchecked(&self) -> RwLockReadGuard<'_, R, T> { + RwLockReadGuard { + rwlock: self, + marker: PhantomData, + } + } + + /// Creates a new `RwLockReadGuard` without checking if the lock is held. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds a write lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. + #[inline] + pub unsafe fn make_write_guard_unchecked(&self) -> RwLockWriteGuard<'_, R, T> { + RwLockWriteGuard { + rwlock: self, + marker: PhantomData, + } + } + + /// 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. + /// + /// Note that attempts to recursively acquire a read lock on a `RwLock` when + /// the current thread already holds one may result in a deadlock. + /// + /// Returns an RAII guard which will release this thread's shared access + /// once it is dropped. + #[inline] + pub fn read(&self) -> RwLockReadGuard<'_, R, T> { + self.raw.lock_shared(); + // SAFETY: The lock is held, as required. + unsafe { self.make_read_guard_unchecked() } + } + + /// Attempts to acquire this `RwLock` with shared read access. + /// + /// 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. + /// + /// This function does not block. + #[inline] + pub fn try_read(&self) -> Option> { + if self.raw.try_lock_shared() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_read_guard_unchecked() }) + } else { + None + } + } + + /// Locks this `RwLock` with exclusive write access, blocking the current + /// thread until it can be acquired. + /// + /// This function will not return while other writers or other readers + /// currently have access to the lock. + /// + /// Returns an RAII guard which will drop the write access of this `RwLock` + /// when dropped. + #[inline] + pub fn write(&self) -> RwLockWriteGuard<'_, R, T> { + self.raw.lock_exclusive(); + // SAFETY: The lock is held, as required. + unsafe { self.make_write_guard_unchecked() } + } + + /// Attempts to lock this `RwLock` with exclusive write access. + /// + /// 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 block. + #[inline] + pub fn try_write(&self) -> Option> { + if self.raw.try_lock_exclusive() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_write_guard_unchecked() }) + } else { + None + } + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `RwLock` mutably, no actual locking needs to + /// take place---the mutable borrow statically guarantees no locks exist. + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { &mut *self.data.get() } + } + + /// Checks whether this `RwLock` is currently locked in any way. + #[inline] + pub fn is_locked(&self) -> bool { + self.raw.is_locked() + } + + /// Check if this `RwLock` is currently exclusively locked. + #[inline] + pub fn is_locked_exclusive(&self) -> bool { + self.raw.is_locked_exclusive() + } + + /// Forcibly unlocks a read lock. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `RwLockReadGuard` object alive, for example when + /// dealing with FFI. + /// + /// # Safety + /// + /// This method must only be called if the current thread logically owns a + /// `RwLockReadGuard` but that guard has be discarded using `mem::forget`. + /// Behavior is undefined if a rwlock is read-unlocked when not read-locked. + #[inline] + pub unsafe fn force_unlock_read(&self) { + self.raw.unlock_shared(); + } + + /// Forcibly unlocks a write lock. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `RwLockWriteGuard` object alive, for example when + /// dealing with FFI. + /// + /// # Safety + /// + /// This method must only be called if the current thread logically owns a + /// `RwLockWriteGuard` but that guard has be discarded using `mem::forget`. + /// Behavior is undefined if a rwlock is write-unlocked when not write-locked. + #[inline] + pub unsafe fn force_unlock_write(&self) { + self.raw.unlock_exclusive(); + } + + /// Returns the underlying raw reader-writer lock object. + /// + /// Note that you will most likely need to import the `RawRwLock` trait from + /// `lock_api` to be able to call functions on the raw + /// reader-writer lock. + /// + /// # Safety + /// + /// This method is unsafe because it allows unlocking a mutex while + /// still holding a reference to a lock guard. + pub unsafe fn raw(&self) -> &R { + &self.raw + } + + /// Returns a raw pointer to the underlying data. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `RwLockReadGuard` or `RwLockWriteGuard` object + /// alive, for example when dealing with FFI. + /// + /// # Safety + /// + /// You must ensure that there are no data races when dereferencing the + /// returned pointer, for example if the current thread logically owns a + /// `RwLockReadGuard` or `RwLockWriteGuard` but that guard has been discarded + /// using `mem::forget`. + #[inline] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } + + /// Creates a new `RwLockReadGuard` without checking if the lock is held. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds a read lock. + /// + /// This function does not increment the read count of the lock. Calling this function when a + /// guard has already been produced is undefined behaviour unless the guard was forgotten + /// with `mem::forget`.` + #[cfg(feature = "arc_lock")] + #[inline] + pub unsafe fn make_arc_read_guard_unchecked(self: &Arc) -> ArcRwLockReadGuard { + ArcRwLockReadGuard { + rwlock: self.clone(), + marker: PhantomData, + } + } + + /// Creates a new `RwLockWriteGuard` without checking if the lock is held. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds a write lock. + /// + /// Calling this function when a guard has already been produced is undefined behaviour unless + /// the guard was forgotten with `mem::forget`. + #[cfg(feature = "arc_lock")] + #[inline] + pub unsafe fn make_arc_write_guard_unchecked(self: &Arc) -> ArcRwLockWriteGuard { + ArcRwLockWriteGuard { + rwlock: self.clone(), + marker: PhantomData, + } + } + + /// Locks this `RwLock` with read access, through an `Arc`. + /// + /// This method is similar to the `read` method; however, it requires the `RwLock` to be inside of an `Arc` + /// and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn read_arc(self: &Arc) -> ArcRwLockReadGuard { + self.raw.lock_shared(); + // SAFETY: locking guarantee is upheld + unsafe { self.make_arc_read_guard_unchecked() } + } + + /// Attempts to lock this `RwLock` with read access, through an `Arc`. + /// + /// This method is similar to the `try_read` method; however, it requires the `RwLock` to be inside of an + /// `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_arc(self: &Arc) -> Option> { + if self.raw.try_lock_shared() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_read_guard_unchecked() }) + } else { + None + } + } + + /// Locks this `RwLock` with write access, through an `Arc`. + /// + /// This method is similar to the `write` method; however, it requires the `RwLock` to be inside of an `Arc` + /// and the resulting write guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn write_arc(self: &Arc) -> ArcRwLockWriteGuard { + self.raw.lock_exclusive(); + // SAFETY: locking guarantee is upheld + unsafe { self.make_arc_write_guard_unchecked() } + } + + /// Attempts to lock this `RwLock` with writ access, through an `Arc`. + /// + /// This method is similar to the `try_write` method; however, it requires the `RwLock` to be inside of an + /// `Arc` and the resulting write guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_write_arc(self: &Arc) -> Option> { + if self.raw.try_lock_exclusive() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_write_guard_unchecked() }) + } else { + None + } + } +} + +impl RwLock { + /// Forcibly unlocks a read lock using a fair unlock procotol. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `RwLockReadGuard` object alive, for example when + /// dealing with FFI. + /// + /// # Safety + /// + /// This method must only be called if the current thread logically owns a + /// `RwLockReadGuard` but that guard has be discarded using `mem::forget`. + /// Behavior is undefined if a rwlock is read-unlocked when not read-locked. + #[inline] + pub unsafe fn force_unlock_read_fair(&self) { + self.raw.unlock_shared_fair(); + } + + /// Forcibly unlocks a write lock using a fair unlock procotol. + /// + /// This is useful when combined with `mem::forget` to hold a lock without + /// the need to maintain a `RwLockWriteGuard` object alive, for example when + /// dealing with FFI. + /// + /// # Safety + /// + /// This method must only be called if the current thread logically owns a + /// `RwLockWriteGuard` but that guard has be discarded using `mem::forget`. + /// Behavior is undefined if a rwlock is write-unlocked when not write-locked. + #[inline] + pub unsafe fn force_unlock_write_fair(&self) { + self.raw.unlock_exclusive_fair(); + } +} + +impl RwLock { + /// Attempts to acquire this `RwLock` with shared read access until a timeout + /// is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. Otherwise, an RAII guard is returned which will + /// release the shared access when it is dropped. + #[inline] + pub fn try_read_for(&self, timeout: R::Duration) -> Option> { + if self.raw.try_lock_shared_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_read_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with shared read access until a timeout + /// is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. Otherwise, an RAII guard is returned which will + /// release the shared access when it is dropped. + #[inline] + pub fn try_read_until(&self, timeout: R::Instant) -> Option> { + if self.raw.try_lock_shared_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_read_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with exclusive write access until a + /// timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. Otherwise, an RAII guard is returned which will + /// release the exclusive access when it is dropped. + #[inline] + pub fn try_write_for(&self, timeout: R::Duration) -> Option> { + if self.raw.try_lock_exclusive_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_write_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with exclusive write access until a + /// timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. Otherwise, an RAII guard is returned which will + /// release the exclusive access when it is dropped. + #[inline] + pub fn try_write_until(&self, timeout: R::Instant) -> Option> { + if self.raw.try_lock_exclusive_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_write_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_read_for` method; however, it requires the `RwLock` to be inside of an + /// `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_arc_for( + self: &Arc, + timeout: R::Duration, + ) -> Option> { + if self.raw.try_lock_shared_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_read_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_read_until` method; however, it requires the `RwLock` to be inside of + /// an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_arc_until( + self: &Arc, + timeout: R::Instant, + ) -> Option> { + if self.raw.try_lock_shared_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_read_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with write access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_write_for` method; however, it requires the `RwLock` to be inside of + /// an `Arc` and the resulting write guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_write_arc_for( + self: &Arc, + timeout: R::Duration, + ) -> Option> { + if self.raw.try_lock_exclusive_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_write_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_write_until` method; however, it requires the `RwLock` to be inside of + /// an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_write_arc_until( + self: &Arc, + timeout: R::Instant, + ) -> Option> { + if self.raw.try_lock_exclusive_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_write_guard_unchecked() }) + } else { + None + } + } +} + +impl RwLock { + /// 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. + /// + /// Unlike `read`, this method is guaranteed to succeed without blocking if + /// another read lock is held at the time of the call. This allows a thread + /// to recursively lock a `RwLock`. However using this method can cause + /// writers to starve since readers no longer block if a writer is waiting + /// for the lock. + /// + /// Returns an RAII guard which will release this thread's shared access + /// once it is dropped. + #[inline] + pub fn read_recursive(&self) -> RwLockReadGuard<'_, R, T> { + self.raw.lock_shared_recursive(); + // SAFETY: The lock is held, as required. + unsafe { self.make_read_guard_unchecked() } + } + + /// Attempts to acquire this `RwLock` with shared read access. + /// + /// 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. + /// + /// This method is guaranteed to succeed if another read lock is held at the + /// time of the call. See the documentation for `read_recursive` for details. + /// + /// This function does not block. + #[inline] + pub fn try_read_recursive(&self) -> Option> { + if self.raw.try_lock_shared_recursive() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_read_guard_unchecked() }) + } else { + None + } + } + + /// Locks this `RwLock` with shared read access, through an `Arc`. + /// + /// This method is similar to the `read_recursive` method; however, it requires the `RwLock` to be inside of + /// an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn read_arc_recursive(self: &Arc) -> ArcRwLockReadGuard { + self.raw.lock_shared_recursive(); + // SAFETY: locking guarantee is upheld + unsafe { self.make_arc_read_guard_unchecked() } + } + + /// Attempts to lock this `RwLock` with shared read access, through an `Arc`. + /// + /// This method is similar to the `try_read_recursive` method; however, it requires the `RwLock` to be inside + /// of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_recursive_arc(self: &Arc) -> Option> { + if self.raw.try_lock_shared_recursive() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_read_guard_unchecked() }) + } else { + None + } + } +} + +impl RwLock { + /// Attempts to acquire this `RwLock` with shared read access until a timeout + /// is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. Otherwise, an RAII guard is returned which will + /// release the shared access when it is dropped. + /// + /// This method is guaranteed to succeed without blocking if another read + /// lock is held at the time of the call. See the documentation for + /// `read_recursive` for details. + #[inline] + pub fn try_read_recursive_for( + &self, + timeout: R::Duration, + ) -> Option> { + if self.raw.try_lock_shared_recursive_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_read_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with shared read access until a timeout + /// is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. Otherwise, an RAII guard is returned which will + /// release the shared access when it is dropped. + #[inline] + pub fn try_read_recursive_until( + &self, + timeout: R::Instant, + ) -> Option> { + if self.raw.try_lock_shared_recursive_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_read_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to lock this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_read_recursive_for` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_arc_recursive_for( + self: &Arc, + timeout: R::Duration, + ) -> Option> { + if self.raw.try_lock_shared_recursive_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_read_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to lock this `RwLock` with read access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_read_recursive_until` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_read_arc_recursive_until( + self: &Arc, + timeout: R::Instant, + ) -> Option> { + if self.raw.try_lock_shared_recursive_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_arc_read_guard_unchecked() }) + } else { + None + } + } +} + +impl RwLock { + /// Creates a new `RwLockUpgradableReadGuard` without checking if the lock is held. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds an upgradable read lock. + /// + /// This function does not increment the read count of the lock. Calling this function when a + /// guard has already been produced is undefined behaviour unless the guard was forgotten + /// with `mem::forget`.` + #[inline] + pub unsafe fn make_upgradable_guard_unchecked(&self) -> RwLockUpgradableReadGuard<'_, R, T> { + RwLockUpgradableReadGuard { + rwlock: self, + marker: PhantomData, + } + } + + /// Locks this `RwLock` with upgradable read access, blocking the current thread + /// until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers or other + /// upgradable reads 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. + #[inline] + pub fn upgradable_read(&self) -> RwLockUpgradableReadGuard<'_, R, T> { + self.raw.lock_upgradable(); + // SAFETY: The lock is held, as required. + unsafe { self.make_upgradable_guard_unchecked() } + } + + /// Attempts to acquire this `RwLock` with upgradable read access. + /// + /// 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. + /// + /// This function does not block. + #[inline] + pub fn try_upgradable_read(&self) -> Option> { + if self.raw.try_lock_upgradable() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_upgradable_guard_unchecked() }) + } else { + None + } + } + + /// Creates a new `ArcRwLockUpgradableReadGuard` without checking if the lock is held. + /// + /// # Safety + /// + /// This method must only be called if the thread logically holds an upgradable read lock. + /// + /// This function does not increment the read count of the lock. Calling this function when a + /// guard has already been produced is undefined behaviour unless the guard was forgotten + /// with `mem::forget`.` + #[cfg(feature = "arc_lock")] + #[inline] + pub unsafe fn make_upgradable_arc_guard_unchecked( + self: &Arc, + ) -> ArcRwLockUpgradableReadGuard { + ArcRwLockUpgradableReadGuard { + rwlock: self.clone(), + marker: PhantomData, + } + } + + /// Locks this `RwLock` with upgradable read access, through an `Arc`. + /// + /// This method is similar to the `upgradable_read` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn upgradable_read_arc(self: &Arc) -> ArcRwLockUpgradableReadGuard { + self.raw.lock_upgradable(); + // SAFETY: locking guarantee is upheld + unsafe { self.make_upgradable_arc_guard_unchecked() } + } + + /// Attempts to lock this `RwLock` with upgradable read access, through an `Arc`. + /// + /// This method is similar to the `try_upgradable_read` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_upgradable_read_arc(self: &Arc) -> Option> { + if self.raw.try_lock_upgradable() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_upgradable_arc_guard_unchecked() }) + } else { + None + } + } +} + +impl RwLock { + /// Attempts to acquire this `RwLock` with upgradable read access until a timeout + /// is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. Otherwise, an RAII guard is returned which will + /// release the shared access when it is dropped. + #[inline] + pub fn try_upgradable_read_for( + &self, + timeout: R::Duration, + ) -> Option> { + if self.raw.try_lock_upgradable_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_upgradable_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to acquire this `RwLock` with upgradable read access until a timeout + /// is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. Otherwise, an RAII guard is returned which will + /// release the shared access when it is dropped. + #[inline] + pub fn try_upgradable_read_until( + &self, + timeout: R::Instant, + ) -> Option> { + if self.raw.try_lock_upgradable_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.make_upgradable_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to lock this `RwLock` with upgradable access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_upgradable_read_for` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_upgradable_read_arc_for( + self: &Arc, + timeout: R::Duration, + ) -> Option> { + if self.raw.try_lock_upgradable_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_upgradable_arc_guard_unchecked() }) + } else { + None + } + } + + /// Attempts to lock this `RwLock` with upgradable access until a timeout is reached, through an `Arc`. + /// + /// This method is similar to the `try_upgradable_read_until` method; however, it requires the `RwLock` to be + /// inside of an `Arc` and the resulting read guard has no lifetime requirements. + #[cfg(feature = "arc_lock")] + #[inline] + pub fn try_upgradable_read_arc_until( + self: &Arc, + timeout: R::Instant, + ) -> Option> { + if self.raw.try_lock_upgradable_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.make_upgradable_arc_guard_unchecked() }) + } else { + None + } + } +} + +impl Default for RwLock { + #[inline] + fn default() -> RwLock { + RwLock::new(Default::default()) + } +} + +impl From for RwLock { + #[inline] + fn from(t: T) -> RwLock { + RwLock::new(t) + } +} + +impl fmt::Debug for RwLock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.try_read() { + Some(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(), + None => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("") + } + } + + f.debug_struct("RwLock") + .field("data", &LockedPlaceholder) + .finish() + } + } + } +} + +/// RAII structure used to release the shared read access of a lock when +/// dropped. +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockReadGuard<'a, R: RawRwLock, T: ?Sized> { + rwlock: &'a RwLock, + marker: PhantomData<(&'a T, R::GuardMarker)>, +} + +unsafe impl Sync for RwLockReadGuard<'_, R, T> {} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> RwLockReadGuard<'a, R, T> { + /// Returns a reference to the original reader-writer lock object. + pub fn rwlock(s: &Self) -> &'a RwLock { + s.rwlock + } + + /// Make a new `MappedRwLockReadGuard` for a component of the locked data. + /// + /// This operation cannot fail as the `RwLockReadGuard` passed + /// in already locked the data. + /// + /// This is an associated function that needs to be + /// used as `RwLockReadGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn map(s: Self, f: F) -> MappedRwLockReadGuard<'a, R, U> + where + F: FnOnce(&T) -> &U, + { + let raw = &s.rwlock.raw; + let data = f(unsafe { &*s.rwlock.data.get() }); + mem::forget(s); + MappedRwLockReadGuard { + raw, + data, + marker: PhantomData, + } + } + + /// Attempts to make a new `MappedRwLockReadGuard` for a component of the + /// locked data. Returns the original guard if the closure returns `None`. + /// + /// This operation cannot fail as the `RwLockReadGuard` passed + /// in already locked the data. + /// + /// This is an associated function that needs to be + /// used as `RwLockReadGuard::try_map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn try_map(s: Self, f: F) -> Result, Self> + where + F: FnOnce(&T) -> Option<&U>, + { + let raw = &s.rwlock.raw; + let data = match f(unsafe { &*s.rwlock.data.get() }) { + Some(data) => data, + None => return Err(s), + }; + mem::forget(s); + Ok(MappedRwLockReadGuard { + raw, + data, + marker: PhantomData, + }) + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the `RwLock`. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_shared(); + } + defer!(s.rwlock.raw.lock_shared()); + f() + } +} + +impl<'a, R: RawRwLockFair + 'a, T: ?Sized + 'a> RwLockReadGuard<'a, R, T> { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// By default, `RwLock` is unfair and allow the current thread to re-lock + /// the `RwLock` before another has the chance to acquire the lock, even if + /// that thread has been blocked on the `RwLock` for a long time. This is + /// the default because it allows much higher throughput as it avoids + /// forcing a context switch on every `RwLock` unlock. This can result in one + /// thread acquiring a `RwLock` many more times than other threads. + /// + /// However in some cases it can be beneficial to ensure fairness by forcing + /// the lock to pass on to a waiting thread if there is one. This is done by + /// using this method instead of dropping the `RwLockReadGuard` normally. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_shared_fair(); + } + mem::forget(s); + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// The `RwLock` is unlocked a fair unlock protocol. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the `RwLock`. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_shared_fair(); + } + defer!(s.rwlock.raw.lock_shared()); + f() + } + + /// Temporarily yields the `RwLock` to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_fair` followed + /// by `read`, however it can be much more efficient in the case where there + /// are no waiting threads. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.bump_shared(); + } + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> Deref for RwLockReadGuard<'a, R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> Drop for RwLockReadGuard<'a, R, T> { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + self.rwlock.raw.unlock_shared(); + } + } +} + +impl<'a, R: RawRwLock + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for RwLockReadGuard<'a, R, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R: RawRwLock + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display + for RwLockReadGuard<'a, R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[cfg(feature = "owning_ref")] +unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockReadGuard<'a, R, T> {} + +/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. +/// +/// This is similar to the `RwLockReadGuard` struct, except instead of using a reference to unlock the `RwLock` +/// it uses an `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct ArcRwLockReadGuard { + rwlock: Arc>, + marker: PhantomData, +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockReadGuard { + /// Returns a reference to the rwlock, contained in its `Arc`. + pub fn rwlock(s: &Self) -> &Arc> { + &s.rwlock + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally identical to the `unlocked` method on [`RwLockReadGuard`]. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_shared(); + } + defer!(s.rwlock.raw.lock_shared()); + f() + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockReadGuard { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// This is functionally identical to the `unlock_fair` method on [`RwLockReadGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_shared_fair(); + } + + // SAFETY: ensure the Arc has its refcount decremented + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.rwlock) }; + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally identical to the `unlocked_fair` method on [`RwLockReadGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_shared_fair(); + } + defer!(s.rwlock.raw.lock_shared()); + f() + } + + /// Temporarily yields the `RwLock` to a waiting thread if there is one. + /// + /// This is functionally identical to the `bump` method on [`RwLockReadGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.bump_shared(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl Deref for ArcRwLockReadGuard { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl Drop for ArcRwLockReadGuard { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + self.rwlock.raw.unlock_shared(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Debug for ArcRwLockReadGuard { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Display for ArcRwLockReadGuard { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +/// RAII structure used to release the exclusive write access of a lock when +/// dropped. +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockWriteGuard<'a, R: RawRwLock, T: ?Sized> { + rwlock: &'a RwLock, + marker: PhantomData<(&'a mut T, R::GuardMarker)>, +} + +unsafe impl Sync for RwLockWriteGuard<'_, R, T> {} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> RwLockWriteGuard<'a, R, T> { + /// Returns a reference to the original reader-writer lock object. + pub fn rwlock(s: &Self) -> &'a RwLock { + s.rwlock + } + + /// Make a new `MappedRwLockWriteGuard` for a component of the locked data. + /// + /// This operation cannot fail as the `RwLockWriteGuard` passed + /// in already locked the data. + /// + /// This is an associated function that needs to be + /// used as `RwLockWriteGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn map(s: Self, f: F) -> MappedRwLockWriteGuard<'a, R, U> + where + F: FnOnce(&mut T) -> &mut U, + { + let raw = &s.rwlock.raw; + let data = f(unsafe { &mut *s.rwlock.data.get() }); + mem::forget(s); + MappedRwLockWriteGuard { + raw, + data, + marker: PhantomData, + } + } + + /// Attempts to make a new `MappedRwLockWriteGuard` for a component of the + /// locked data. The original guard is return if the closure returns `None`. + /// + /// This operation cannot fail as the `RwLockWriteGuard` passed + /// in already locked the data. + /// + /// This is an associated function that needs to be + /// used as `RwLockWriteGuard::try_map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn try_map(s: Self, f: F) -> Result, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + { + let raw = &s.rwlock.raw; + let data = match f(unsafe { &mut *s.rwlock.data.get() }) { + Some(data) => data, + None => return Err(s), + }; + mem::forget(s); + Ok(MappedRwLockWriteGuard { + raw, + data, + marker: PhantomData, + }) + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the `RwLock`. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_exclusive(); + } + defer!(s.rwlock.raw.lock_exclusive()); + f() + } +} + +impl<'a, R: RawRwLockDowngrade + 'a, T: ?Sized + 'a> RwLockWriteGuard<'a, R, T> { + /// Atomically downgrades a write lock into a read lock without allowing any + /// writers to take exclusive access of the lock in the meantime. + /// + /// Note that if there are any writers currently waiting to take the lock + /// then other readers may not be able to acquire the lock even if it was + /// downgraded. + pub fn downgrade(s: Self) -> RwLockReadGuard<'a, R, T> { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.downgrade(); + } + let rwlock = s.rwlock; + mem::forget(s); + RwLockReadGuard { + rwlock, + marker: PhantomData, + } + } +} + +impl<'a, R: RawRwLockUpgradeDowngrade + 'a, T: ?Sized + 'a> RwLockWriteGuard<'a, R, T> { + /// Atomically downgrades a write lock into an upgradable read lock without allowing any + /// writers to take exclusive access of the lock in the meantime. + /// + /// Note that if there are any writers currently waiting to take the lock + /// then other readers may not be able to acquire the lock even if it was + /// downgraded. + pub fn downgrade_to_upgradable(s: Self) -> RwLockUpgradableReadGuard<'a, R, T> { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.downgrade_to_upgradable(); + } + let rwlock = s.rwlock; + mem::forget(s); + RwLockUpgradableReadGuard { + rwlock, + marker: PhantomData, + } + } +} + +impl<'a, R: RawRwLockFair + 'a, T: ?Sized + 'a> RwLockWriteGuard<'a, R, T> { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// By default, `RwLock` is unfair and allow the current thread to re-lock + /// the `RwLock` before another has the chance to acquire the lock, even if + /// that thread has been blocked on the `RwLock` for a long time. This is + /// the default because it allows much higher throughput as it avoids + /// forcing a context switch on every `RwLock` unlock. This can result in one + /// thread acquiring a `RwLock` many more times than other threads. + /// + /// However in some cases it can be beneficial to ensure fairness by forcing + /// the lock to pass on to a waiting thread if there is one. This is done by + /// using this method instead of dropping the `RwLockWriteGuard` normally. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.unlock_exclusive_fair(); + } + mem::forget(s); + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// The `RwLock` is unlocked a fair unlock protocol. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the `RwLock`. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.unlock_exclusive_fair(); + } + defer!(s.rwlock.raw.lock_exclusive()); + f() + } + + /// Temporarily yields the `RwLock` to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_fair` followed + /// by `write`, however it can be much more efficient in the case where there + /// are no waiting threads. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.bump_exclusive(); + } + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> Deref for RwLockWriteGuard<'a, R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> DerefMut for RwLockWriteGuard<'a, R, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.rwlock.data.get() } + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> Drop for RwLockWriteGuard<'a, R, T> { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + self.rwlock.raw.unlock_exclusive(); + } + } +} + +impl<'a, R: RawRwLock + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for RwLockWriteGuard<'a, R, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R: RawRwLock + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display + for RwLockWriteGuard<'a, R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[cfg(feature = "owning_ref")] +unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress for RwLockWriteGuard<'a, R, T> {} + +/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. +/// This is similar to the `RwLockWriteGuard` struct, except instead of using a reference to unlock the `RwLock` +/// it uses an `Arc`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct ArcRwLockWriteGuard { + rwlock: Arc>, + marker: PhantomData, +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockWriteGuard { + /// Returns a reference to the rwlock, contained in its `Arc`. + pub fn rwlock(s: &Self) -> &Arc> { + &s.rwlock + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally equivalent to the `unlocked` method on [`RwLockWriteGuard`]. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockWriteGuard always holds a shared lock. + unsafe { + s.rwlock.raw.unlock_exclusive(); + } + defer!(s.rwlock.raw.lock_exclusive()); + f() + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockWriteGuard { + /// Atomically downgrades a write lock into a read lock without allowing any + /// writers to take exclusive access of the lock in the meantime. + /// + /// This is functionally equivalent to the `downgrade` method on [`RwLockWriteGuard`]. + pub fn downgrade(s: Self) -> ArcRwLockReadGuard { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.downgrade(); + } + + // SAFETY: prevent the arc's refcount from changing using ManuallyDrop and ptr::read + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + ArcRwLockReadGuard { + rwlock, + marker: PhantomData, + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockWriteGuard { + /// Atomically downgrades a write lock into an upgradable read lock without allowing any + /// writers to take exclusive access of the lock in the meantime. + /// + /// This is functionally identical to the `downgrade_to_upgradable` method on [`RwLockWriteGuard`]. + pub fn downgrade_to_upgradable(s: Self) -> ArcRwLockUpgradableReadGuard { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.downgrade_to_upgradable(); + } + + // SAFETY: same as above + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + ArcRwLockUpgradableReadGuard { + rwlock, + marker: PhantomData, + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockWriteGuard { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// This is functionally equivalent to the `unlock_fair` method on [`RwLockWriteGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.unlock_exclusive_fair(); + } + + // SAFETY: prevent the Arc from leaking memory + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.rwlock) }; + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally equivalent to the `unlocked_fair` method on [`RwLockWriteGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.unlock_exclusive_fair(); + } + defer!(s.rwlock.raw.lock_exclusive()); + f() + } + + /// Temporarily yields the `RwLock` to a waiting thread if there is one. + /// + /// This method is functionally equivalent to the `bump` method on [`RwLockWriteGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + s.rwlock.raw.bump_exclusive(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl Deref for ArcRwLockWriteGuard { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl DerefMut for ArcRwLockWriteGuard { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl Drop for ArcRwLockWriteGuard { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + self.rwlock.raw.unlock_exclusive(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Debug for ArcRwLockWriteGuard { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Display for ArcRwLockWriteGuard { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +/// RAII structure used to release the upgradable read access of a lock when +/// dropped. +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockUpgradableReadGuard<'a, R: RawRwLockUpgrade, T: ?Sized> { + rwlock: &'a RwLock, + marker: PhantomData<(&'a T, R::GuardMarker)>, +} + +unsafe impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + Sync + 'a> Sync + for RwLockUpgradableReadGuard<'a, R, T> +{ +} + +impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, R, T> { + /// Returns a reference to the original reader-writer lock object. + pub fn rwlock(s: &Self) -> &'a RwLock { + s.rwlock + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the `RwLock`. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.unlock_upgradable(); + } + defer!(s.rwlock.raw.lock_upgradable()); + f() + } + + /// Atomically upgrades an upgradable read lock lock into an exclusive write lock, + /// blocking the current thread until it can be acquired. + pub fn upgrade(s: Self) -> RwLockWriteGuard<'a, R, T> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.upgrade(); + } + let rwlock = s.rwlock; + mem::forget(s); + RwLockWriteGuard { + rwlock, + marker: PhantomData, + } + } + + /// Tries to atomically upgrade an upgradable read lock into an exclusive write lock. + /// + /// If the access could not be granted at this time, then the current guard is returned. + pub fn try_upgrade(s: Self) -> Result, Self> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + if unsafe { s.rwlock.raw.try_upgrade() } { + let rwlock = s.rwlock; + mem::forget(s); + Ok(RwLockWriteGuard { + rwlock, + marker: PhantomData, + }) + } else { + Err(s) + } + } +} + +impl<'a, R: RawRwLockUpgradeFair + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, R, T> { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// By default, `RwLock` is unfair and allow the current thread to re-lock + /// the `RwLock` before another has the chance to acquire the lock, even if + /// that thread has been blocked on the `RwLock` for a long time. This is + /// the default because it allows much higher throughput as it avoids + /// forcing a context switch on every `RwLock` unlock. This can result in one + /// thread acquiring a `RwLock` many more times than other threads. + /// + /// However in some cases it can be beneficial to ensure fairness by forcing + /// the lock to pass on to a waiting thread if there is one. This is done by + /// using this method instead of dropping the `RwLockUpgradableReadGuard` normally. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.unlock_upgradable_fair(); + } + mem::forget(s); + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// The `RwLock` is unlocked a fair unlock protocol. + /// + /// This is safe because `&mut` guarantees that there exist no other + /// references to the data protected by the `RwLock`. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.unlock_upgradable_fair(); + } + defer!(s.rwlock.raw.lock_upgradable()); + f() + } + + /// Temporarily yields the `RwLock` to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `unlock_fair` followed + /// by `upgradable_read`, however it can be much more efficient in the case where there + /// are no waiting threads. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.bump_upgradable(); + } + } +} + +impl<'a, R: RawRwLockUpgradeDowngrade + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, R, T> { + /// Atomically downgrades an upgradable read lock lock into a shared read lock + /// without allowing any writers to take exclusive access of the lock in the + /// meantime. + /// + /// Note that if there are any writers currently waiting to take the lock + /// then other readers may not be able to acquire the lock even if it was + /// downgraded. + pub fn downgrade(s: Self) -> RwLockReadGuard<'a, R, T> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.downgrade_upgradable(); + } + let rwlock = s.rwlock; + mem::forget(s); + RwLockReadGuard { + rwlock, + marker: PhantomData, + } + } + + /// First, atomically upgrades an upgradable read lock lock into an exclusive write lock, + /// blocking the current thread until it can be acquired. + /// + /// Then, calls the provided closure with an exclusive reference to the lock's data. + /// + /// Finally, atomically downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `upgrade` which takes the guard by value. + pub fn with_upgraded Ret>(&mut self, f: F) -> Ret { + unsafe { + self.rwlock.raw.upgrade(); + } + + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_to_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + f(unsafe { &mut *self.rwlock.data.get() }) + } + + /// First, tries to atomically upgrade an upgradable read lock into an exclusive write lock. + /// + /// If the access could not be granted at this time, then `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade` which takes the guard by value. + pub fn try_with_upgraded Ret>(&mut self, f: F) -> Option { + if unsafe { self.rwlock.raw.try_upgrade() } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_to_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } +} + +impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, R, T> { + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// the current guard is returned. + pub fn try_upgrade_for( + s: Self, + timeout: R::Duration, + ) -> Result, Self> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + if unsafe { s.rwlock.raw.try_upgrade_for(timeout) } { + let rwlock = s.rwlock; + mem::forget(s); + Ok(RwLockWriteGuard { + rwlock, + marker: PhantomData, + }) + } else { + Err(s) + } + } + + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// the current guard is returned. + #[inline] + pub fn try_upgrade_until( + s: Self, + timeout: R::Instant, + ) -> Result, Self> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + if unsafe { s.rwlock.raw.try_upgrade_until(timeout) } { + let rwlock = s.rwlock; + mem::forget(s); + Ok(RwLockWriteGuard { + rwlock, + marker: PhantomData, + }) + } else { + Err(s) + } + } +} + +impl<'a, R: RawRwLockUpgradeTimed + RawRwLockUpgradeDowngrade + 'a, T: ?Sized + 'a> + RwLockUpgradableReadGuard<'a, R, T> +{ + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade_for` which takes the guard by value. + pub fn try_with_upgraded_for Ret>( + &mut self, + timeout: R::Duration, + f: F, + ) -> Option { + if unsafe { self.rwlock.raw.try_upgrade_for(timeout) } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } + + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade_until` which takes the guard by value. + pub fn try_with_upgraded_until Ret>( + &mut self, + timeout: R::Instant, + f: F, + ) -> Option { + if unsafe { self.rwlock.raw.try_upgrade_until(timeout) } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } +} + +impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> Deref for RwLockUpgradableReadGuard<'a, R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> Drop for RwLockUpgradableReadGuard<'a, R, T> { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + self.rwlock.raw.unlock_upgradable(); + } + } +} + +impl<'a, R: RawRwLockUpgrade + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug + for RwLockUpgradableReadGuard<'a, R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R: RawRwLockUpgrade + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display + for RwLockUpgradableReadGuard<'a, R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[cfg(feature = "owning_ref")] +unsafe impl<'a, R: RawRwLockUpgrade + 'a, T: ?Sized + 'a> StableAddress + for RwLockUpgradableReadGuard<'a, R, T> +{ +} + +/// An RAII rwlock guard returned by the `Arc` locking operations on `RwLock`. +/// This is similar to the `RwLockUpgradableReadGuard` struct, except instead of using a reference to unlock the +/// `RwLock` it uses an `Arc`. This has several advantages, most notably that it has an `'static` +/// lifetime. +#[cfg(feature = "arc_lock")] +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct ArcRwLockUpgradableReadGuard { + rwlock: Arc>, + marker: PhantomData, +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockUpgradableReadGuard { + /// Returns a reference to the rwlock, contained in its original `Arc`. + pub fn rwlock(s: &Self) -> &Arc> { + &s.rwlock + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally identical to the `unlocked` method on [`RwLockUpgradableReadGuard`]. + #[inline] + pub fn unlocked(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.unlock_upgradable(); + } + defer!(s.rwlock.raw.lock_upgradable()); + f() + } + + /// Atomically upgrades an upgradable read lock lock into an exclusive write lock, + /// blocking the current thread until it can be acquired. + pub fn upgrade(s: Self) -> ArcRwLockWriteGuard { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.upgrade(); + } + + // SAFETY: avoid incrementing or decrementing the refcount using ManuallyDrop and reading the Arc out + // of the struct + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + ArcRwLockWriteGuard { + rwlock, + marker: PhantomData, + } + } + + /// Tries to atomically upgrade an upgradable read lock into an exclusive write lock. + /// + /// If the access could not be granted at this time, then the current guard is returned. + pub fn try_upgrade(s: Self) -> Result, Self> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + if unsafe { s.rwlock.raw.try_upgrade() } { + // SAFETY: same as above + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + Ok(ArcRwLockWriteGuard { + rwlock, + marker: PhantomData, + }) + } else { + Err(s) + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockUpgradableReadGuard { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// This is functionally identical to the `unlock_fair` method on [`RwLockUpgradableReadGuard`]. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.unlock_upgradable_fair(); + } + + // SAFETY: make sure we decrement the refcount properly + let mut s = ManuallyDrop::new(s); + unsafe { ptr::drop_in_place(&mut s.rwlock) }; + } + + /// Temporarily unlocks the `RwLock` to execute the given function. + /// + /// This is functionally equivalent to the `unlocked_fair` method on [`RwLockUpgradableReadGuard`]. + #[inline] + pub fn unlocked_fair(s: &mut Self, f: F) -> U + where + F: FnOnce() -> U, + { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.unlock_upgradable_fair(); + } + defer!(s.rwlock.raw.lock_upgradable()); + f() + } + + /// Temporarily yields the `RwLock` to a waiting thread if there is one. + /// + /// This method is functionally equivalent to calling `bump` on [`RwLockUpgradableReadGuard`]. + #[inline] + pub fn bump(s: &mut Self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.bump_upgradable(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockUpgradableReadGuard { + /// Atomically downgrades an upgradable read lock lock into a shared read lock + /// without allowing any writers to take exclusive access of the lock in the + /// meantime. + /// + /// Note that if there are any writers currently waiting to take the lock + /// then other readers may not be able to acquire the lock even if it was + /// downgraded. + pub fn downgrade(s: Self) -> ArcRwLockReadGuard { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + s.rwlock.raw.downgrade_upgradable(); + } + + // SAFETY: use ManuallyDrop and ptr::read to ensure the refcount is not changed + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + ArcRwLockReadGuard { + rwlock, + marker: PhantomData, + } + } + + /// First, atomically upgrades an upgradable read lock lock into an exclusive write lock, + /// blocking the current thread until it can be acquired. + /// + /// Then, calls the provided closure with an exclusive reference to the lock's data. + /// + /// Finally, atomically downgrades the lock back to an upgradable read lock. + /// The closure's return value is returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `upgrade` which takes the guard by value. + pub fn with_upgraded Ret>(&mut self, f: F) -> Ret { + unsafe { + self.rwlock.raw.upgrade(); + } + + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + f(unsafe { &mut *self.rwlock.data.get() }) + } + + /// First, tries to atomically upgrade an upgradable read lock into an exclusive write lock. + /// + /// If the access could not be granted at this time, then `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade` which takes the guard by value. + pub fn try_with_upgraded Ret>(&mut self, f: F) -> Option { + if unsafe { self.rwlock.raw.try_upgrade() } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } +} + +#[cfg(feature = "arc_lock")] +impl ArcRwLockUpgradableReadGuard { + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// the current guard is returned. + pub fn try_upgrade_for( + s: Self, + timeout: R::Duration, + ) -> Result, Self> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + if unsafe { s.rwlock.raw.try_upgrade_for(timeout) } { + // SAFETY: same as above + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + Ok(ArcRwLockWriteGuard { + rwlock, + marker: PhantomData, + }) + } else { + Err(s) + } + } + + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// the current guard is returned. + #[inline] + pub fn try_upgrade_until( + s: Self, + timeout: R::Instant, + ) -> Result, Self> { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + if unsafe { s.rwlock.raw.try_upgrade_until(timeout) } { + // SAFETY: same as above + let s = ManuallyDrop::new(s); + let rwlock = unsafe { ptr::read(&s.rwlock) }; + + Ok(ArcRwLockWriteGuard { + rwlock, + marker: PhantomData, + }) + } else { + Err(s) + } + } +} + +#[cfg(feature = "arc_lock")] +impl + ArcRwLockUpgradableReadGuard +{ + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade_for` which takes the guard by value. + pub fn try_with_upgraded_for Ret>( + &mut self, + timeout: R::Duration, + f: F, + ) -> Option { + if unsafe { self.rwlock.raw.try_upgrade_for(timeout) } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } + + /// Tries to atomically upgrade an upgradable read lock into an exclusive + /// write lock, until a timeout is reached. + /// + /// If the access could not be granted before the timeout expires, then + /// `None` is returned. + /// + /// Otherwise, calls the provided closure with an exclusive reference to the lock's data, + /// and finally downgrades the lock back to an upgradable read lock. + /// The closure's return value is wrapped in `Some` and returned. + /// + /// This function only requires a mutable reference to the guard, unlike + /// `try_upgrade_until` which takes the guard by value. + pub fn try_with_upgraded_until Ret>( + &mut self, + timeout: R::Instant, + f: F, + ) -> Option { + if unsafe { self.rwlock.raw.try_upgrade_until(timeout) } { + // Safety: We just upgraded the lock, so we have mutable access to the data. + // This will restore the state the lock was in at the start of the function. + defer!(unsafe { self.rwlock.raw.downgrade_upgradable() }); + + // Safety: We upgraded the lock, so we have mutable access to the data. + // When this function returns, whether by drop or panic, + // the drop guard will downgrade it back to an upgradeable lock. + Some(f(unsafe { &mut *self.rwlock.data.get() })) + } else { + None + } + } +} + +#[cfg(feature = "arc_lock")] +impl Deref for ArcRwLockUpgradableReadGuard { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl Drop for ArcRwLockUpgradableReadGuard { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + self.rwlock.raw.unlock_upgradable(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Debug + for ArcRwLockUpgradableReadGuard +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "arc_lock")] +impl fmt::Display + for ArcRwLockUpgradableReadGuard +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +/// An RAII read lock guard returned by `RwLockReadGuard::map`, which can point to a +/// subfield of the protected data. +/// +/// The main difference between `MappedRwLockReadGuard` and `RwLockReadGuard` is that the +/// former doesn't support temporarily unlocking and re-locking, since that +/// could introduce soundness issues if the locked object is modified by another +/// thread. +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct MappedRwLockReadGuard<'a, R: RawRwLock, T: ?Sized> { + raw: &'a R, + data: *const T, + marker: PhantomData<&'a T>, +} + +unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + Sync + 'a> Sync for MappedRwLockReadGuard<'a, R, T> {} +unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + Sync + 'a> Send for MappedRwLockReadGuard<'a, R, T> where + R::GuardMarker: Send +{ +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> MappedRwLockReadGuard<'a, R, T> { + /// Make a new `MappedRwLockReadGuard` for a component of the locked data. + /// + /// This operation cannot fail as the `MappedRwLockReadGuard` passed + /// in already locked the data. + /// + /// This is an associated function that needs to be + /// used as `MappedRwLockReadGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn map(s: Self, f: F) -> MappedRwLockReadGuard<'a, R, U> + where + F: FnOnce(&T) -> &U, + { + let raw = s.raw; + let data = f(unsafe { &*s.data }); + mem::forget(s); + MappedRwLockReadGuard { + raw, + data, + marker: PhantomData, + } + } + + /// Attempts to make a new `MappedRwLockReadGuard` for a component of the + /// locked data. The original guard is return if the closure returns `None`. + /// + /// This operation cannot fail as the `MappedRwLockReadGuard` passed + /// in already locked the data. + /// + /// This is an associated function that needs to be + /// used as `MappedRwLockReadGuard::try_map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn try_map(s: Self, f: F) -> Result, Self> + where + F: FnOnce(&T) -> Option<&U>, + { + let raw = s.raw; + let data = match f(unsafe { &*s.data }) { + Some(data) => data, + None => return Err(s), + }; + mem::forget(s); + Ok(MappedRwLockReadGuard { + raw, + data, + marker: PhantomData, + }) + } +} + +impl<'a, R: RawRwLockFair + 'a, T: ?Sized + 'a> MappedRwLockReadGuard<'a, R, T> { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// By default, `RwLock` is unfair and allow the current thread to re-lock + /// the `RwLock` before another has the chance to acquire the lock, even if + /// that thread has been blocked on the `RwLock` for a long time. This is + /// the default because it allows much higher throughput as it avoids + /// forcing a context switch on every `RwLock` unlock. This can result in one + /// thread acquiring a `RwLock` many more times than other threads. + /// + /// However in some cases it can be beneficial to ensure fairness by forcing + /// the lock to pass on to a waiting thread if there is one. This is done by + /// using this method instead of dropping the `MappedRwLockReadGuard` normally. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A MappedRwLockReadGuard always holds a shared lock. + unsafe { + s.raw.unlock_shared_fair(); + } + mem::forget(s); + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> Deref for MappedRwLockReadGuard<'a, R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.data } + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> Drop for MappedRwLockReadGuard<'a, R, T> { + #[inline] + fn drop(&mut self) { + // Safety: A MappedRwLockReadGuard always holds a shared lock. + unsafe { + self.raw.unlock_shared(); + } + } +} + +impl<'a, R: RawRwLock + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug + for MappedRwLockReadGuard<'a, R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R: RawRwLock + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display + for MappedRwLockReadGuard<'a, R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[cfg(feature = "owning_ref")] +unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress + for MappedRwLockReadGuard<'a, R, T> +{ +} + +/// An RAII write lock guard returned by `RwLockWriteGuard::map`, which can point to a +/// subfield of the protected data. +/// +/// The main difference between `MappedRwLockWriteGuard` and `RwLockWriteGuard` is that the +/// former doesn't support temporarily unlocking and re-locking, since that +/// could introduce soundness issues if the locked object is modified by another +/// thread. +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct MappedRwLockWriteGuard<'a, R: RawRwLock, T: ?Sized> { + raw: &'a R, + data: *mut T, + marker: PhantomData<&'a mut T>, +} + +unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + Sync + 'a> Sync + for MappedRwLockWriteGuard<'a, R, T> +{ +} +unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + Send + 'a> Send for MappedRwLockWriteGuard<'a, R, T> where + R::GuardMarker: Send +{ +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> MappedRwLockWriteGuard<'a, R, T> { + /// Make a new `MappedRwLockWriteGuard` for a component of the locked data. + /// + /// This operation cannot fail as the `MappedRwLockWriteGuard` passed + /// in already locked the data. + /// + /// This is an associated function that needs to be + /// used as `MappedRwLockWriteGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn map(s: Self, f: F) -> MappedRwLockWriteGuard<'a, R, U> + where + F: FnOnce(&mut T) -> &mut U, + { + let raw = s.raw; + let data = f(unsafe { &mut *s.data }); + mem::forget(s); + MappedRwLockWriteGuard { + raw, + data, + marker: PhantomData, + } + } + + /// Attempts to make a new `MappedRwLockWriteGuard` for a component of the + /// locked data. The original guard is return if the closure returns `None`. + /// + /// This operation cannot fail as the `MappedRwLockWriteGuard` passed + /// in already locked the data. + /// + /// This is an associated function that needs to be + /// used as `MappedRwLockWriteGuard::try_map(...)`. A method would interfere with methods of + /// the same name on the contents of the locked data. + #[inline] + pub fn try_map(s: Self, f: F) -> Result, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + { + let raw = s.raw; + let data = match f(unsafe { &mut *s.data }) { + Some(data) => data, + None => return Err(s), + }; + mem::forget(s); + Ok(MappedRwLockWriteGuard { + raw, + data, + marker: PhantomData, + }) + } +} + +impl<'a, R: RawRwLockFair + 'a, T: ?Sized + 'a> MappedRwLockWriteGuard<'a, R, T> { + /// Unlocks the `RwLock` using a fair unlock protocol. + /// + /// By default, `RwLock` is unfair and allow the current thread to re-lock + /// the `RwLock` before another has the chance to acquire the lock, even if + /// that thread has been blocked on the `RwLock` for a long time. This is + /// the default because it allows much higher throughput as it avoids + /// forcing a context switch on every `RwLock` unlock. This can result in one + /// thread acquiring a `RwLock` many more times than other threads. + /// + /// However in some cases it can be beneficial to ensure fairness by forcing + /// the lock to pass on to a waiting thread if there is one. This is done by + /// using this method instead of dropping the `MappedRwLockWriteGuard` normally. + #[inline] + pub fn unlock_fair(s: Self) { + // Safety: A MappedRwLockWriteGuard always holds an exclusive lock. + unsafe { + s.raw.unlock_exclusive_fair(); + } + mem::forget(s); + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> Deref for MappedRwLockWriteGuard<'a, R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.data } + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> DerefMut for MappedRwLockWriteGuard<'a, R, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.data } + } +} + +impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> Drop for MappedRwLockWriteGuard<'a, R, T> { + #[inline] + fn drop(&mut self) { + // Safety: A MappedRwLockWriteGuard always holds an exclusive lock. + unsafe { + self.raw.unlock_exclusive(); + } + } +} + +impl<'a, R: RawRwLock + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug + for MappedRwLockWriteGuard<'a, R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R: RawRwLock + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display + for MappedRwLockWriteGuard<'a, R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[cfg(feature = "owning_ref")] +unsafe impl<'a, R: RawRwLock + 'a, T: ?Sized + 'a> StableAddress + for MappedRwLockWriteGuard<'a, R, T> +{ +} -- cgit v1.2.3