Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
1
vendor/lock_api/.cargo-checksum.json
vendored
Normal file
1
vendor/lock_api/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"33d5077741ae3052ec99816d7390a65220b898b87fb100589d5783352d4052f5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","build.rs":"af84139c71d151adead0b4398c394a7dd16087bb2db44b14a0ed970ce868a6c6","src/lib.rs":"4d2f97a740d3bda0cf2ba0ccbaa44a294952a701fc5a8219a755b4187bab29d4","src/mutex.rs":"d24c765e7b371542992465027dba520e66a09e67a78324ab8396449aadad0d77","src/remutex.rs":"036fb60892d4b727257dbdf68a921738f048a94ed5ca0a1bb78ee0f68381cf9e","src/rwlock.rs":"4b85d7b42474ebe0ba91f6fd953232510164989ce5ef1511790de486d8960301"},"package":"3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"}
|
60
vendor/lock_api/Cargo.toml
vendored
Normal file
60
vendor/lock_api/Cargo.toml
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
# 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"
|
||||
rust-version = "1.49.0"
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
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"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
"--generate-link-to-definition",
|
||||
]
|
||||
|
||||
[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 = []
|
||||
atomic_usize = []
|
||||
default = ["atomic_usize"]
|
||||
nightly = []
|
201
vendor/lock_api/LICENSE-APACHE
vendored
Normal file
201
vendor/lock_api/LICENSE-APACHE
vendored
Normal file
@ -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.
|
25
vendor/lock_api/LICENSE-MIT
vendored
Normal file
25
vendor/lock_api/LICENSE-MIT
vendored
Normal file
@ -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.
|
7
vendor/lock_api/build.rs
vendored
Normal file
7
vendor/lock_api/build.rs
vendored
Normal file
@ -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");
|
||||
}
|
||||
}
|
116
vendor/lock_api/src/lib.rs
vendored
Normal file
116
vendor/lock_api/src/lib.rs
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
// 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]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate scopeguard;
|
||||
|
||||
#[cfg(feature = "arc_lock")]
|
||||
extern crate alloc;
|
||||
|
||||
/// Marker type which indicates that the Guard type for a lock is `Send`.
|
||||
pub struct GuardSend(());
|
||||
|
||||
/// Marker type which indicates that the Guard type for a lock is not `Send`.
|
||||
pub struct GuardNoSend(*mut ());
|
||||
|
||||
unsafe impl Sync for GuardNoSend {}
|
||||
|
||||
mod mutex;
|
||||
pub use crate::mutex::*;
|
||||
|
||||
#[cfg(feature = "atomic_usize")]
|
||||
mod remutex;
|
||||
#[cfg(feature = "atomic_usize")]
|
||||
pub use crate::remutex::*;
|
||||
|
||||
mod rwlock;
|
||||
pub use crate::rwlock::*;
|
960
vendor/lock_api/src/mutex.rs
vendored
Normal file
960
vendor/lock_api/src/mutex.rs
vendored
Normal file
@ -0,0 +1,960 @@
|
||||
// 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> {
|
||||
/// Creates a new `MutexGuard` without checking if the mutex is locked.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This method must only be called if the thread logically holds the lock.
|
||||
///
|
||||
/// Calling this function when a guard has already been produced is undefined behaviour unless
|
||||
/// the guard was forgotten with `mem::forget`.
|
||||
#[inline]
|
||||
pub unsafe fn make_guard_unchecked(&self) -> MutexGuard<'_, R, T> {
|
||||
MutexGuard {
|
||||
mutex: self,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires a mutex, blocking the current thread until it is able to do so.
|
||||
///
|
||||
/// This function will block the local thread until it is available to acquire
|
||||
/// the mutex. Upon returning, the thread is the only thread with the mutex
|
||||
/// held. An RAII guard is returned to allow scoped unlock of the lock. When
|
||||
/// the guard goes out of scope, the mutex will be unlocked.
|
||||
///
|
||||
/// Attempts to lock a mutex in the thread which already holds the lock will
|
||||
/// result in a deadlock.
|
||||
#[inline]
|
||||
pub fn lock(&self) -> MutexGuard<'_, R, T> {
|
||||
self.raw.lock();
|
||||
// SAFETY: The lock is held, as required.
|
||||
unsafe { self.make_guard_unchecked() }
|
||||
}
|
||||
|
||||
/// Attempts to acquire this lock.
|
||||
///
|
||||
/// If the lock could not be acquired at this time, then `None` is returned.
|
||||
/// Otherwise, an RAII guard is returned. The lock will be unlocked when the
|
||||
/// guard is dropped.
|
||||
///
|
||||
/// This function does not block.
|
||||
#[inline]
|
||||
pub fn try_lock(&self) -> Option<MutexGuard<'_, R, T>> {
|
||||
if self.raw.try_lock() {
|
||||
// SAFETY: The lock is held, as required.
|
||||
Some(unsafe { self.make_guard_unchecked() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying data.
|
||||
///
|
||||
/// Since this call borrows the `Mutex` mutably, no actual locking needs to
|
||||
/// take place---the mutable borrow statically guarantees no locks exist.
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.data.get() }
|
||||
}
|
||||
|
||||
/// Checks whether the mutex is currently locked.
|
||||
#[inline]
|
||||
pub fn is_locked(&self) -> bool {
|
||||
self.raw.is_locked()
|
||||
}
|
||||
|
||||
/// Forcibly unlocks the mutex.
|
||||
///
|
||||
/// This is useful when combined with `mem::forget` to hold a lock without
|
||||
/// the need to maintain a `MutexGuard` object alive, for example when
|
||||
/// dealing with FFI.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This method must only be called if the current thread logically owns a
|
||||
/// `MutexGuard` but that guard has been discarded using `mem::forget`.
|
||||
/// Behavior is undefined if a mutex is unlocked when not locked.
|
||||
#[inline]
|
||||
pub unsafe fn force_unlock(&self) {
|
||||
self.raw.unlock();
|
||||
}
|
||||
|
||||
/// Returns the underlying raw mutex object.
|
||||
///
|
||||
/// Note that you will most likely need to import the `RawMutex` trait from
|
||||
/// `lock_api` to be able to call functions on the raw mutex.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This method is unsafe because it allows unlocking a mutex while
|
||||
/// still holding a reference to a `MutexGuard`.
|
||||
#[inline]
|
||||
pub unsafe fn raw(&self) -> &R {
|
||||
&self.raw
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the underlying data.
|
||||
///
|
||||
/// This is useful when combined with `mem::forget` to hold a lock without
|
||||
/// the need to maintain a `MutexGuard` object alive, for example when
|
||||
/// dealing with FFI.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// You must ensure that there are no data races when dereferencing the
|
||||
/// returned pointer, for example if the current thread logically owns
|
||||
/// a `MutexGuard` but that guard has been discarded using `mem::forget`.
|
||||
#[inline]
|
||||
pub fn data_ptr(&self) -> *mut T {
|
||||
self.data.get()
|
||||
}
|
||||
|
||||
/// Creates a new `ArcMutexGuard` without checking if the mutex is locked.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This method must only be called if the thread logically holds the lock.
|
||||
///
|
||||
/// Calling this function when a guard has already been produced is undefined behaviour unless
|
||||
/// the guard was forgotten with `mem::forget`.
|
||||
#[cfg(feature = "arc_lock")]
|
||||
#[inline]
|
||||
unsafe fn make_arc_guard_unchecked(self: &Arc<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.make_arc_guard_unchecked() }
|
||||
}
|
||||
|
||||
/// Attempts to acquire a lock through an `Arc`.
|
||||
///
|
||||
/// This method is similar to the `try_lock` method; however, it requires the `Mutex` to be inside of an
|
||||
/// `Arc` and the resulting mutex guard has no lifetime requirements.
|
||||
#[cfg(feature = "arc_lock")]
|
||||
#[inline]
|
||||
pub fn try_lock_arc(self: &Arc<Self>) -> Option<ArcMutexGuard<R, T>> {
|
||||
if self.raw.try_lock() {
|
||||
// SAFETY: locking guarantee is upheld
|
||||
Some(unsafe { self.make_arc_guard_unchecked() })
|
||||
} 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 been discarded using `mem::forget`.
|
||||
/// Behavior is undefined if a mutex is unlocked when not locked.
|
||||
#[inline]
|
||||
pub unsafe fn force_unlock_fair(&self) {
|
||||
self.raw.unlock_fair();
|
||||
}
|
||||
}
|
||||
|
||||
impl<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.make_guard_unchecked() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to acquire this lock until a timeout is reached.
|
||||
///
|
||||
/// If the lock could not be acquired before the timeout expired, then
|
||||
/// `None` is returned. Otherwise, an RAII guard is returned. The lock will
|
||||
/// be unlocked when the guard is dropped.
|
||||
#[inline]
|
||||
pub fn try_lock_until(&self, timeout: R::Instant) -> Option<MutexGuard<'_, R, T>> {
|
||||
if self.raw.try_lock_until(timeout) {
|
||||
// SAFETY: The lock is held, as required.
|
||||
Some(unsafe { self.make_guard_unchecked() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to acquire this lock through an `Arc` until a timeout is reached.
|
||||
///
|
||||
/// This method is similar to the `try_lock_for` method; however, it requires the `Mutex` to be inside of an
|
||||
/// `Arc` and the resulting mutex guard has no lifetime requirements.
|
||||
#[cfg(feature = "arc_lock")]
|
||||
#[inline]
|
||||
pub fn try_lock_arc_for(self: &Arc<Self>, timeout: R::Duration) -> Option<ArcMutexGuard<R, T>> {
|
||||
if self.raw.try_lock_for(timeout) {
|
||||
// SAFETY: locking guarantee is upheld
|
||||
Some(unsafe { self.make_arc_guard_unchecked() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to acquire this lock through an `Arc` until a timeout is reached.
|
||||
///
|
||||
/// This method is similar to the `try_lock_until` method; however, it requires the `Mutex` to be inside of
|
||||
/// an `Arc` and the resulting mutex guard has no lifetime requirements.
|
||||
#[cfg(feature = "arc_lock")]
|
||||
#[inline]
|
||||
pub fn try_lock_arc_until(
|
||||
self: &Arc<Self>,
|
||||
timeout: R::Instant,
|
||||
) -> Option<ArcMutexGuard<R, T>> {
|
||||
if self.raw.try_lock_until(timeout) {
|
||||
// SAFETY: locking guarantee is upheld
|
||||
Some(unsafe { self.make_arc_guard_unchecked() })
|
||||
} 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.
|
||||
#[clippy::has_significant_drop]
|
||||
#[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")]
|
||||
#[clippy::has_significant_drop]
|
||||
#[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.
|
||||
#[clippy::has_significant_drop]
|
||||
#[must_use = "if unused the Mutex will immediately unlock"]
|
||||
pub struct MappedMutexGuard<'a, R: RawMutex, T: ?Sized> {
|
||||
raw: &'a R,
|
||||
data: *mut T,
|
||||
marker: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
unsafe impl<'a, R: RawMutex + Sync + 'a, T: ?Sized + Sync + 'a> Sync
|
||||
for MappedMutexGuard<'a, R, T>
|
||||
{
|
||||
}
|
||||
unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + Send + 'a> Send for MappedMutexGuard<'a, R, T> where
|
||||
R::GuardMarker: Send
|
||||
{
|
||||
}
|
||||
|
||||
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> MappedMutexGuard<'a, R, T> {
|
||||
/// Makes a new `MappedMutexGuard` for a component of the locked data.
|
||||
///
|
||||
/// This operation cannot fail as the `MappedMutexGuard` passed
|
||||
/// in already locked the mutex.
|
||||
///
|
||||
/// This is an associated function that needs to be
|
||||
/// used as `MappedMutexGuard::map(...)`. A method would interfere with methods of
|
||||
/// the same name on the contents of the locked data.
|
||||
#[inline]
|
||||
pub fn map<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> {}
|
1051
vendor/lock_api/src/remutex.rs
vendored
Normal file
1051
vendor/lock_api/src/remutex.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2883
vendor/lock_api/src/rwlock.rs
vendored
Normal file
2883
vendor/lock_api/src/rwlock.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user