diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/lock_api | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/lock_api')
-rw-r--r-- | third_party/rust/lock_api/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/lock_api/Cargo.toml | 49 | ||||
-rw-r--r-- | third_party/rust/lock_api/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | third_party/rust/lock_api/LICENSE-MIT | 25 | ||||
-rw-r--r-- | third_party/rust/lock_api/build.rs | 7 | ||||
-rw-r--r-- | third_party/rust/lock_api/src/lib.rs | 113 | ||||
-rw-r--r-- | third_party/rust/lock_api/src/mutex.rs | 947 | ||||
-rw-r--r-- | third_party/rust/lock_api/src/remutex.rs | 1036 | ||||
-rw-r--r-- | third_party/rust/lock_api/src/rwlock.rs | 2604 |
9 files changed, 4983 insertions, 0 deletions
diff --git a/third_party/rust/lock_api/.cargo-checksum.json b/third_party/rust/lock_api/.cargo-checksum.json new file mode 100644 index 0000000000..cf8df26fae --- /dev/null +++ b/third_party/rust/lock_api/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"15453a84e25ac6ed84c95e11e71d9bee5b360b6dc787a433b8416b91bf8e216c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","build.rs":"af84139c71d151adead0b4398c394a7dd16087bb2db44b14a0ed970ce868a6c6","src/lib.rs":"7b67c3b69c1b5e97248afe0f6c3bc353c793ed1ce4a5d5177e63f3f05d79c63b","src/mutex.rs":"f5627b1269a9b0d116507af19b8619b9922b95b73a84ab5be3134620c97caadb","src/remutex.rs":"4fa5f0448591a32ac37f2cf9af89813f32e415d2a1ca426670a0cdaccbca66aa","src/rwlock.rs":"9160cbada7e3179bd8ec13769761437e90bfb616316947dc0cc5959f0bcdc5b9"},"package":"435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"}
\ No newline at end of file diff --git a/third_party/rust/lock_api/Cargo.toml b/third_party/rust/lock_api/Cargo.toml new file mode 100644 index 0000000000..b1ff8c4db2 --- /dev/null +++ b/third_party/rust/lock_api/Cargo.toml @@ -0,0 +1,49 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "lock_api" +version = "0.4.9" +authors = ["Amanieu d'Antras <amanieu@gmail.com>"] +description = "Wrappers to create fully-featured Mutex and RwLock types. Compatible with no_std." +keywords = [ + "mutex", + "rwlock", + "lock", + "no_std", +] +categories = [ + "concurrency", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/Amanieu/parking_lot" + +[dependencies.owning_ref] +version = "0.4.1" +optional = true + +[dependencies.scopeguard] +version = "1.1.0" +default-features = false + +[dependencies.serde] +version = "1.0.126" +optional = true +default-features = false + +[build-dependencies.autocfg] +version = "1.1.0" + +[features] +arc_lock = [] +nightly = [] diff --git a/third_party/rust/lock_api/LICENSE-APACHE b/third_party/rust/lock_api/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/lock_api/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/lock_api/LICENSE-MIT b/third_party/rust/lock_api/LICENSE-MIT new file mode 100644 index 0000000000..40b8817a47 --- /dev/null +++ b/third_party/rust/lock_api/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/lock_api/build.rs b/third_party/rust/lock_api/build.rs new file mode 100644 index 0000000000..886a3454c3 --- /dev/null +++ b/third_party/rust/lock_api/build.rs @@ -0,0 +1,7 @@ +fn main() { + let cfg = autocfg::new(); + + if cfg.probe_rustc_version(1, 61) { + println!("cargo:rustc-cfg=has_const_fn_trait_bound"); + } +} diff --git a/third_party/rust/lock_api/src/lib.rs b/third_party/rust/lock_api/src/lib.rs new file mode 100644 index 0000000000..cfa53bce45 --- /dev/null +++ b/third_party/rust/lock_api/src/lib.rs @@ -0,0 +1,113 @@ +// Copyright 2018 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, 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<T> = lock_api::Mutex<RawSpinlock, T>; +//! 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] +#![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::*; + +mod remutex; +pub use crate::remutex::*; + +mod rwlock; +pub use crate::rwlock::*; diff --git a/third_party/rust/lock_api/src/mutex.rs b/third_party/rust/lock_api/src/mutex.rs new file mode 100644 index 0000000000..c97e5430b6 --- /dev/null +++ b/third_party/rust/lock_api/src/mutex.rs @@ -0,0 +1,947 @@ +// Copyright 2018 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, 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<R, T: ?Sized> { + raw: R, + data: UnsafeCell<T>, +} + +unsafe impl<R: RawMutex + Send, T: ?Sized + Send> Send for Mutex<R, T> {} +unsafe impl<R: RawMutex + Sync, T: ?Sized + Send> Sync for Mutex<R, T> {} + +impl<R: RawMutex, T> Mutex<R, T> { + /// 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<R, T> { + 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<R, T> { + 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<R, T> Mutex<R, T> { + /// 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<R, T> { + Mutex { + raw: raw_mutex, + data: UnsafeCell::new(val), + } + } +} + +impl<R: RawMutex, T: ?Sized> Mutex<R, T> { + /// # Safety + /// + /// The lock must be held when calling this method. + #[inline] + unsafe fn guard(&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.guard() } + } + + /// 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<MutexGuard<'_, R, T>> { + if self.raw.try_lock() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.guard() }) + } 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 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 `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() + } + + /// # Safety + /// + /// The lock needs to be held for the behavior of this function to be defined. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn guard_arc(self: &Arc<Self>) -> ArcMutexGuard<R, T> { + 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<Self>) -> ArcMutexGuard<R, T> { + self.raw.lock(); + // SAFETY: the locking guarantee is upheld + unsafe { self.guard_arc() } + } + + /// 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<Self>) -> Option<ArcMutexGuard<R, T>> { + if self.raw.try_lock() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.guard_arc() }) + } else { + None + } + } +} + +impl<R: RawMutexFair, T: ?Sized> Mutex<R, T> { + /// 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 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<R: RawMutexTimed, T: ?Sized> Mutex<R, T> { + /// 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<MutexGuard<'_, R, T>> { + if self.raw.try_lock_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.guard() }) + } 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<MutexGuard<'_, R, T>> { + if self.raw.try_lock_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.guard() }) + } 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<Self>, timeout: R::Duration) -> Option<ArcMutexGuard<R, T>> { + if self.raw.try_lock_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.guard_arc() }) + } 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<Self>, + timeout: R::Instant, + ) -> Option<ArcMutexGuard<R, T>> { + if self.raw.try_lock_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.guard_arc() }) + } else { + None + } + } +} + +impl<R: RawMutex, T: ?Sized + Default> Default for Mutex<R, T> { + #[inline] + fn default() -> Mutex<R, T> { + Mutex::new(Default::default()) + } +} + +impl<R: RawMutex, T> From<T> for Mutex<R, T> { + #[inline] + fn from(t: T) -> Mutex<R, T> { + Mutex::new(t) + } +} + +impl<R: RawMutex, T: ?Sized + fmt::Debug> fmt::Debug for Mutex<R, T> { + 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("<locked>") + } + } + + f.debug_struct("Mutex") + .field("data", &LockedPlaceholder) + .finish() + } + } + } +} + +// Copied and modified from serde +#[cfg(feature = "serde")] +impl<R, T> Serialize for Mutex<R, T> +where + R: RawMutex, + T: Serialize + ?Sized, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.lock().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, R, T> Deserialize<'de> for Mutex<R, T> +where + R: RawMutex, + T: Deserialize<'de> + ?Sized, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + 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. +#[must_use = "if unused the Mutex will immediately unlock"] +pub struct MutexGuard<'a, R: RawMutex, T: ?Sized> { + mutex: &'a Mutex<R, T>, + 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<R, T> { + 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<U: ?Sized, F>(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<U: ?Sized, F>(s: Self, f: F) -> Result<MappedMutexGuard<'a, R, U>, 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<F, U>(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<F, U>(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<Mutex>`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the Mutex will immediately unlock"] +pub struct ArcMutexGuard<R: RawMutex, T: ?Sized> { + mutex: Arc<Mutex<R, T>>, + marker: PhantomData<*const ()>, +} + +#[cfg(feature = "arc_lock")] +unsafe impl<R: RawMutex + Send + Sync, T: Send + ?Sized> Send for ArcMutexGuard<R, T> where + R::GuardMarker: Send +{ +} +#[cfg(feature = "arc_lock")] +unsafe impl<R: RawMutex + Sync, T: Sync + ?Sized> Sync for ArcMutexGuard<R, T> where + R::GuardMarker: Sync +{ +} + +#[cfg(feature = "arc_lock")] +impl<R: RawMutex, T: ?Sized> ArcMutexGuard<R, T> { + /// Returns a reference to the `Mutex` this is guarding, contained in its `Arc`. + #[inline] + pub fn mutex(s: &Self) -> &Arc<Mutex<R, T>> { + &s.mutex + } + + /// Unlocks the mutex and returns the `Arc` that was held by the [`ArcMutexGuard`]. + #[inline] + pub fn into_arc(s: Self) -> Arc<Mutex<R, T>> { + // 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<F, U>(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<R: RawMutexFair, T: ?Sized> ArcMutexGuard<R, T> { + /// 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<F, U>(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<R: RawMutex, T: ?Sized> Deref for ArcMutexGuard<R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.mutex.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawMutex, T: ?Sized> DerefMut for ArcMutexGuard<R, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.mutex.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawMutex, T: ?Sized> Drop for ArcMutexGuard<R, T> { + #[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. +#[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<U: ?Sized, F>(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<U: ?Sized, F>(s: Self, f: F) -> Result<MappedMutexGuard<'a, R, U>, 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/third_party/rust/lock_api/src/remutex.rs b/third_party/rust/lock_api/src/remutex.rs new file mode 100644 index 0000000000..3e2010f2b4 --- /dev/null +++ b/third_party/rust/lock_api/src/remutex.rs @@ -0,0 +1,1036 @@ +// Copyright 2018 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, 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<R, G> { + owner: AtomicUsize, + lock_count: Cell<usize>, + mutex: R, + get_thread_id: G, +} + +unsafe impl<R: RawMutex + Send, G: GetThreadId + Send> Send for RawReentrantMutex<R, G> {} +unsafe impl<R: RawMutex + Sync, G: GetThreadId + Sync> Sync for RawReentrantMutex<R, G> {} + +impl<R: RawMutex, G: GetThreadId> RawReentrantMutex<R, G> { + /// 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<F: FnOnce() -> 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<R: RawMutexFair, G: GetThreadId> RawReentrantMutex<R, G> { + /// 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.mutex.bump(); + self.owner.store(id, Ordering::Relaxed); + } + } +} + +impl<R: RawMutexTimed, G: GetThreadId> RawReentrantMutex<R, G> { + /// 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<R, G, T: ?Sized> { + raw: RawReentrantMutex<R, G>, + data: UnsafeCell<T>, +} + +unsafe impl<R: RawMutex + Send, G: GetThreadId + Send, T: ?Sized + Send> Send + for ReentrantMutex<R, G, T> +{ +} +unsafe impl<R: RawMutex + Sync, G: GetThreadId + Sync, T: ?Sized + Send> Sync + for ReentrantMutex<R, G, T> +{ +} + +impl<R: RawMutex, G: GetThreadId, T> ReentrantMutex<R, G, T> { + /// 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<R, G, T> { + 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<R, G, T> { + 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<R, G, T> ReentrantMutex<R, G, T> { + /// 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<R, G, T> { + ReentrantMutex { + data: UnsafeCell::new(val), + raw: RawReentrantMutex { + owner: AtomicUsize::new(0), + lock_count: Cell::new(0), + mutex: raw_mutex, + get_thread_id, + }, + } + } +} + +impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> { + /// # Safety + /// + /// The lock must be held when calling this method. + #[inline] + unsafe fn guard(&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.guard() } + } + + /// 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<ReentrantMutexGuard<'_, R, G, T>> { + if self.raw.try_lock() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.guard() }) + } 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() + } + + /// # Safety + /// + /// The lock must be held before calling this method. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn guard_arc(self: &Arc<Self>) -> ArcReentrantMutexGuard<R, G, T> { + 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<Self>) -> ArcReentrantMutexGuard<R, G, T> { + self.raw.lock(); + // SAFETY: locking guarantee is upheld + unsafe { self.guard_arc() } + } + + /// 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<Self>) -> Option<ArcReentrantMutexGuard<R, G, T>> { + if self.raw.try_lock() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.guard_arc() }) + } else { + None + } + } +} + +impl<R: RawMutexFair, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> { + /// 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<R: RawMutexTimed, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> { + /// 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<ReentrantMutexGuard<'_, R, G, T>> { + if self.raw.try_lock_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.guard() }) + } 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<ReentrantMutexGuard<'_, R, G, T>> { + if self.raw.try_lock_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.guard() }) + } 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<Self>, + timeout: R::Duration, + ) -> Option<ArcReentrantMutexGuard<R, G, T>> { + if self.raw.try_lock_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.guard_arc() }) + } 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<Self>, + timeout: R::Instant, + ) -> Option<ArcReentrantMutexGuard<R, G, T>> { + if self.raw.try_lock_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.guard_arc() }) + } else { + None + } + } +} + +impl<R: RawMutex, G: GetThreadId, T: ?Sized + Default> Default for ReentrantMutex<R, G, T> { + #[inline] + fn default() -> ReentrantMutex<R, G, T> { + ReentrantMutex::new(Default::default()) + } +} + +impl<R: RawMutex, G: GetThreadId, T> From<T> for ReentrantMutex<R, G, T> { + #[inline] + fn from(t: T) -> ReentrantMutex<R, G, T> { + ReentrantMutex::new(t) + } +} + +impl<R: RawMutex, G: GetThreadId, T: ?Sized + fmt::Debug> fmt::Debug for ReentrantMutex<R, G, T> { + 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("<locked>") + } + } + + f.debug_struct("ReentrantMutex") + .field("data", &LockedPlaceholder) + .finish() + } + } + } +} + +// Copied and modified from serde +#[cfg(feature = "serde")] +impl<R, G, T> Serialize for ReentrantMutex<R, G, T> +where + R: RawMutex, + G: GetThreadId, + T: Serialize + ?Sized, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.lock().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, R, G, T> Deserialize<'de> for ReentrantMutex<R, G, T> +where + R: RawMutex, + G: GetThreadId, + T: Deserialize<'de> + ?Sized, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + 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. +#[must_use = "if unused the ReentrantMutex will immediately unlock"] +pub struct ReentrantMutexGuard<'a, R: RawMutex, G: GetThreadId, T: ?Sized> { + remutex: &'a ReentrantMutex<R, G, T>, + 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<R, G, T> { + 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<U: ?Sized, F>(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<U: ?Sized, F>( + s: Self, + f: F, + ) -> Result<MappedReentrantMutexGuard<'a, R, G, U>, 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<F, U>(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<F, U>(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<ReentrantMutex>`. This has several advantages, most notably that it has an `'static` +/// lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the ReentrantMutex will immediately unlock"] +pub struct ArcReentrantMutexGuard<R: RawMutex, G: GetThreadId, T: ?Sized> { + remutex: Arc<ReentrantMutex<R, G, T>>, + marker: PhantomData<GuardNoSend>, +} + +#[cfg(feature = "arc_lock")] +impl<R: RawMutex, G: GetThreadId, T: ?Sized> ArcReentrantMutexGuard<R, G, T> { + /// Returns a reference to the `ReentrantMutex` this object is guarding, contained in its `Arc`. + pub fn remutex(s: &Self) -> &Arc<ReentrantMutex<R, G, T>> { + &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<F, U>(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<R: RawMutexFair, G: GetThreadId, T: ?Sized> ArcReentrantMutexGuard<R, G, T> { + /// 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<F, U>(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<R: RawMutex, G: GetThreadId, T: ?Sized> Deref for ArcReentrantMutexGuard<R, G, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.remutex.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawMutex, G: GetThreadId, T: ?Sized> Drop for ArcReentrantMutexGuard<R, G, T> { + #[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. +#[must_use = "if unused the ReentrantMutex will immediately unlock"] +pub struct MappedReentrantMutexGuard<'a, R: RawMutex, G: GetThreadId, T: ?Sized> { + raw: &'a RawReentrantMutex<R, G>, + 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<U: ?Sized, F>(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<U: ?Sized, F>( + s: Self, + f: F, + ) -> Result<MappedReentrantMutexGuard<'a, R, G, U>, 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/third_party/rust/lock_api/src/rwlock.rs b/third_party/rust/lock_api/src/rwlock.rs new file mode 100644 index 0000000000..c972fb6c67 --- /dev/null +++ b/third_party/rust/lock_api/src/rwlock.rs @@ -0,0 +1,2604 @@ +// Copyright 2016 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, 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<R, T: ?Sized> { + raw: R, + data: UnsafeCell<T>, +} + +// Copied and modified from serde +#[cfg(feature = "serde")] +impl<R, T> Serialize for RwLock<R, T> +where + R: RawRwLock, + T: Serialize + ?Sized, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.read().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, R, T> Deserialize<'de> for RwLock<R, T> +where + R: RawRwLock, + T: Deserialize<'de> + ?Sized, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(RwLock::new) + } +} + +unsafe impl<R: RawRwLock + Send, T: ?Sized + Send> Send for RwLock<R, T> {} +unsafe impl<R: RawRwLock + Sync, T: ?Sized + Send + Sync> Sync for RwLock<R, T> {} + +impl<R: RawRwLock, T> RwLock<R, T> { + /// Creates a new instance of an `RwLock<T>` which is unlocked. + #[cfg(has_const_fn_trait_bound)] + #[inline] + pub const fn new(val: T) -> RwLock<R, T> { + RwLock { + data: UnsafeCell::new(val), + raw: R::INIT, + } + } + + /// Creates a new instance of an `RwLock<T>` which is unlocked. + #[cfg(not(has_const_fn_trait_bound))] + #[inline] + pub fn new(val: T) -> RwLock<R, T> { + 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<R, T> RwLock<R, T> { + /// Creates a new new instance of an `RwLock<T>` based on a pre-existing + /// `RawRwLock<T>`. + /// + /// This allows creating a `RwLock<T>` in a constant context on stable + /// Rust. + #[inline] + pub const fn const_new(raw_rwlock: R, val: T) -> RwLock<R, T> { + RwLock { + data: UnsafeCell::new(val), + raw: raw_rwlock, + } + } +} + +impl<R: RawRwLock, T: ?Sized> RwLock<R, T> { + /// # Safety + /// + /// The lock must be held when calling this method. + #[inline] + unsafe fn read_guard(&self) -> RwLockReadGuard<'_, R, T> { + RwLockReadGuard { + rwlock: self, + marker: PhantomData, + } + } + + /// # Safety + /// + /// The lock must be held when calling this method. + #[inline] + unsafe fn write_guard(&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.read_guard() } + } + + /// 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<RwLockReadGuard<'_, R, T>> { + if self.raw.try_lock_shared() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.read_guard() }) + } 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.write_guard() } + } + + /// 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<RwLockWriteGuard<'_, R, T>> { + if self.raw.try_lock_exclusive() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.write_guard() }) + } 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() + } + + /// # Safety + /// + /// The lock must be held when calling this method. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn read_guard_arc(self: &Arc<Self>) -> ArcRwLockReadGuard<R, T> { + ArcRwLockReadGuard { + rwlock: self.clone(), + marker: PhantomData, + } + } + + /// # Safety + /// + /// The lock must be held when calling this method. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn write_guard_arc(self: &Arc<Self>) -> ArcRwLockWriteGuard<R, T> { + 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<Self>) -> ArcRwLockReadGuard<R, T> { + self.raw.lock_shared(); + // SAFETY: locking guarantee is upheld + unsafe { self.read_guard_arc() } + } + + /// 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<Self>) -> Option<ArcRwLockReadGuard<R, T>> { + if self.raw.try_lock_shared() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.read_guard_arc() }) + } 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<Self>) -> ArcRwLockWriteGuard<R, T> { + self.raw.lock_exclusive(); + // SAFETY: locking guarantee is upheld + unsafe { self.write_guard_arc() } + } + + /// 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<Self>) -> Option<ArcRwLockWriteGuard<R, T>> { + if self.raw.try_lock_exclusive() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.write_guard_arc() }) + } else { + None + } + } +} + +impl<R: RawRwLockFair, T: ?Sized> RwLock<R, T> { + /// 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<R: RawRwLockTimed, T: ?Sized> RwLock<R, T> { + /// 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<RwLockReadGuard<'_, R, T>> { + if self.raw.try_lock_shared_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.read_guard() }) + } 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<RwLockReadGuard<'_, R, T>> { + if self.raw.try_lock_shared_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.read_guard() }) + } 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<RwLockWriteGuard<'_, R, T>> { + if self.raw.try_lock_exclusive_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.write_guard() }) + } 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<RwLockWriteGuard<'_, R, T>> { + if self.raw.try_lock_exclusive_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.write_guard() }) + } 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<Self>, + timeout: R::Duration, + ) -> Option<ArcRwLockReadGuard<R, T>> { + if self.raw.try_lock_shared_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.read_guard_arc() }) + } 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<Self>, + timeout: R::Instant, + ) -> Option<ArcRwLockReadGuard<R, T>> { + if self.raw.try_lock_shared_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.read_guard_arc() }) + } 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<Self>, + timeout: R::Duration, + ) -> Option<ArcRwLockWriteGuard<R, T>> { + if self.raw.try_lock_exclusive_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.write_guard_arc() }) + } 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<Self>, + timeout: R::Instant, + ) -> Option<ArcRwLockWriteGuard<R, T>> { + if self.raw.try_lock_exclusive_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.write_guard_arc() }) + } else { + None + } + } +} + +impl<R: RawRwLockRecursive, T: ?Sized> RwLock<R, T> { + /// 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.read_guard() } + } + + /// 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<RwLockReadGuard<'_, R, T>> { + if self.raw.try_lock_shared_recursive() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.read_guard() }) + } 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<Self>) -> ArcRwLockReadGuard<R, T> { + self.raw.lock_shared_recursive(); + // SAFETY: locking guarantee is upheld + unsafe { self.read_guard_arc() } + } + + /// 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<Self>) -> Option<ArcRwLockReadGuard<R, T>> { + if self.raw.try_lock_shared_recursive() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.read_guard_arc() }) + } else { + None + } + } +} + +impl<R: RawRwLockRecursiveTimed, T: ?Sized> RwLock<R, T> { + /// 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<RwLockReadGuard<'_, R, T>> { + if self.raw.try_lock_shared_recursive_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.read_guard() }) + } 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<RwLockReadGuard<'_, R, T>> { + if self.raw.try_lock_shared_recursive_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.read_guard() }) + } 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<Self>, + timeout: R::Duration, + ) -> Option<ArcRwLockReadGuard<R, T>> { + if self.raw.try_lock_shared_recursive_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.read_guard_arc() }) + } 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<Self>, + timeout: R::Instant, + ) -> Option<ArcRwLockReadGuard<R, T>> { + if self.raw.try_lock_shared_recursive_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.read_guard_arc() }) + } else { + None + } + } +} + +impl<R: RawRwLockUpgrade, T: ?Sized> RwLock<R, T> { + /// # Safety + /// + /// The lock must be held when calling this method. + #[inline] + unsafe fn upgradable_guard(&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.upgradable_guard() } + } + + /// 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<RwLockUpgradableReadGuard<'_, R, T>> { + if self.raw.try_lock_upgradable() { + // SAFETY: The lock is held, as required. + Some(unsafe { self.upgradable_guard() }) + } else { + None + } + } + + /// # Safety + /// + /// The lock must be held when calling this method. + #[cfg(feature = "arc_lock")] + #[inline] + unsafe fn upgradable_guard_arc(self: &Arc<Self>) -> ArcRwLockUpgradableReadGuard<R, T> { + 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<Self>) -> ArcRwLockUpgradableReadGuard<R, T> { + self.raw.lock_upgradable(); + // SAFETY: locking guarantee is upheld + unsafe { self.upgradable_guard_arc() } + } + + /// 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<Self>) -> Option<ArcRwLockUpgradableReadGuard<R, T>> { + if self.raw.try_lock_upgradable() { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.upgradable_guard_arc() }) + } else { + None + } + } +} + +impl<R: RawRwLockUpgradeTimed, T: ?Sized> RwLock<R, T> { + /// 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<RwLockUpgradableReadGuard<'_, R, T>> { + if self.raw.try_lock_upgradable_for(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.upgradable_guard() }) + } 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<RwLockUpgradableReadGuard<'_, R, T>> { + if self.raw.try_lock_upgradable_until(timeout) { + // SAFETY: The lock is held, as required. + Some(unsafe { self.upgradable_guard() }) + } 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<Self>, + timeout: R::Duration, + ) -> Option<ArcRwLockUpgradableReadGuard<R, T>> { + if self.raw.try_lock_upgradable_for(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.upgradable_guard_arc() }) + } 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<Self>, + timeout: R::Instant, + ) -> Option<ArcRwLockUpgradableReadGuard<R, T>> { + if self.raw.try_lock_upgradable_until(timeout) { + // SAFETY: locking guarantee is upheld + Some(unsafe { self.upgradable_guard_arc() }) + } else { + None + } + } +} + +impl<R: RawRwLock, T: ?Sized + Default> Default for RwLock<R, T> { + #[inline] + fn default() -> RwLock<R, T> { + RwLock::new(Default::default()) + } +} + +impl<R: RawRwLock, T> From<T> for RwLock<R, T> { + #[inline] + fn from(t: T) -> RwLock<R, T> { + RwLock::new(t) + } +} + +impl<R: RawRwLock, T: ?Sized + fmt::Debug> fmt::Debug for RwLock<R, T> { + 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("<locked>") + } + } + + f.debug_struct("RwLock") + .field("data", &LockedPlaceholder) + .finish() + } + } + } +} + +/// RAII structure used to release the shared read access of a lock when +/// dropped. +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockReadGuard<'a, R: RawRwLock, T: ?Sized> { + rwlock: &'a RwLock<R, T>, + marker: PhantomData<(&'a T, R::GuardMarker)>, +} + +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<R, T> { + 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<U: ?Sized, F>(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<U: ?Sized, F>(s: Self, f: F) -> Result<MappedRwLockReadGuard<'a, R, U>, 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. + /// + /// 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<F, U>(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<F, U>(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<RwLock>`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct ArcRwLockReadGuard<R: RawRwLock, T: ?Sized> { + rwlock: Arc<RwLock<R, T>>, + marker: PhantomData<R::GuardMarker>, +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLock, T: ?Sized> ArcRwLockReadGuard<R, T> { + /// Returns a reference to the rwlock, contained in its `Arc`. + pub fn rwlock(s: &Self) -> &Arc<RwLock<R, T>> { + &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<F, U>(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<R: RawRwLockFair, T: ?Sized> ArcRwLockReadGuard<R, T> { + /// 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<F, U>(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<R: RawRwLock, T: ?Sized> Deref for ArcRwLockReadGuard<R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLock, T: ?Sized> Drop for ArcRwLockReadGuard<R, T> { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockReadGuard always holds a shared lock. + unsafe { + self.rwlock.raw.unlock_shared(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLock, T: fmt::Debug + ?Sized> fmt::Debug for ArcRwLockReadGuard<R, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLock, T: fmt::Display + ?Sized> fmt::Display for ArcRwLockReadGuard<R, T> { + 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. +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockWriteGuard<'a, R: RawRwLock, T: ?Sized> { + rwlock: &'a RwLock<R, T>, + marker: PhantomData<(&'a mut T, R::GuardMarker)>, +} + +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<R, T> { + 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<U: ?Sized, F>(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<U: ?Sized, F>(s: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, R, U>, 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<F, U>(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<F, U>(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<RwLock>`. This has several advantages, most notably that it has an `'static` lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct ArcRwLockWriteGuard<R: RawRwLock, T: ?Sized> { + rwlock: Arc<RwLock<R, T>>, + marker: PhantomData<R::GuardMarker>, +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLock, T: ?Sized> ArcRwLockWriteGuard<R, T> { + /// Returns a reference to the rwlock, contained in its `Arc`. + pub fn rwlock(s: &Self) -> &Arc<RwLock<R, T>> { + &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<F, U>(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<R: RawRwLockDowngrade, T: ?Sized> ArcRwLockWriteGuard<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. + /// + /// This is functionally equivalent to the `downgrade` method on [`RwLockWriteGuard`]. + pub fn downgrade(s: Self) -> ArcRwLockReadGuard<R, T> { + // 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<R: RawRwLockUpgradeDowngrade, T: ?Sized> ArcRwLockWriteGuard<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. + /// + /// This is functionally identical to the `downgrade_to_upgradable` method on [`RwLockWriteGuard`]. + pub fn downgrade_to_upgradable(s: Self) -> ArcRwLockUpgradableReadGuard<R, T> { + // 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<R: RawRwLockFair, T: ?Sized> ArcRwLockWriteGuard<R, T> { + /// 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<F, U>(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<R: RawRwLock, T: ?Sized> Deref for ArcRwLockWriteGuard<R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLock, T: ?Sized> DerefMut for ArcRwLockWriteGuard<R, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLock, T: ?Sized> Drop for ArcRwLockWriteGuard<R, T> { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockWriteGuard always holds an exclusive lock. + unsafe { + self.rwlock.raw.unlock_exclusive(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLock, T: fmt::Debug + ?Sized> fmt::Debug for ArcRwLockWriteGuard<R, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLock, T: fmt::Display + ?Sized> fmt::Display for ArcRwLockWriteGuard<R, T> { + 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. +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockUpgradableReadGuard<'a, R: RawRwLockUpgrade, T: ?Sized> { + rwlock: &'a RwLock<R, T>, + 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<R, T> { + 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<F, U>(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 a 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 a 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<RwLockWriteGuard<'a, R, T>, 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<F, U>(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, + } + } +} + +impl<'a, R: RawRwLockUpgradeTimed + 'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, R, T> { + /// Tries to atomically upgrade an upgradable read lock into a 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<RwLockWriteGuard<'a, R, T>, 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 a 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<RwLockWriteGuard<'a, R, T>, 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: 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<RwLock>`. This has several advantages, most notably that it has an `'static` +/// lifetime. +#[cfg(feature = "arc_lock")] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct ArcRwLockUpgradableReadGuard<R: RawRwLockUpgrade, T: ?Sized> { + rwlock: Arc<RwLock<R, T>>, + marker: PhantomData<R::GuardMarker>, +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLockUpgrade, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> { + /// Returns a reference to the rwlock, contained in its original `Arc`. + pub fn rwlock(s: &Self) -> &Arc<RwLock<R, T>> { + &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<F, U>(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 a exclusive write lock, + /// blocking the current thread until it can be acquired. + pub fn upgrade(s: Self) -> ArcRwLockWriteGuard<R, T> { + // 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 a 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<ArcRwLockWriteGuard<R, T>, 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<R: RawRwLockUpgradeFair, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> { + /// 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<F, U>(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<R: RawRwLockUpgradeDowngrade, T: ?Sized> ArcRwLockUpgradableReadGuard<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) -> ArcRwLockReadGuard<R, T> { + // 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, + } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLockUpgradeTimed, T: ?Sized> ArcRwLockUpgradableReadGuard<R, T> { + /// Tries to atomically upgrade an upgradable read lock into a 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<ArcRwLockWriteGuard<R, T>, 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 a 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<ArcRwLockWriteGuard<R, T>, 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<R: RawRwLockUpgrade, T: ?Sized> Deref for ArcRwLockUpgradableReadGuard<R, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.rwlock.data.get() } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLockUpgrade, T: ?Sized> Drop for ArcRwLockUpgradableReadGuard<R, T> { + #[inline] + fn drop(&mut self) { + // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock. + unsafe { + self.rwlock.raw.unlock_upgradable(); + } + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLockUpgrade, T: fmt::Debug + ?Sized> fmt::Debug + for ArcRwLockUpgradableReadGuard<R, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "arc_lock")] +impl<R: RawRwLockUpgrade, T: fmt::Display + ?Sized> fmt::Display + for ArcRwLockUpgradableReadGuard<R, T> +{ + 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. +#[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<U: ?Sized, F>(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<U: ?Sized, F>(s: Self, f: F) -> Result<MappedRwLockReadGuard<'a, R, U>, 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. +#[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<U: ?Sized, F>(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<U: ?Sized, F>(s: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, R, U>, 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> +{ +} |