Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"5d3b8f434d1481093d6d7879ee3104552383d222f01c62cd891a5cff711a4c3d","Cargo.lock":"a77d003ad0c0b22962172cdedc53836fe31283f59dccedfdd860ebe986871905","Cargo.toml":"895418d9df500f38a1a4169cff817f9d6d69316322d085f3e308b18b6916e930","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"65991d3d7edeb47460d23d795212387bdf8b95e3d9bf4ba3d742fa113fe3c1a2","bors.toml":"938b40da0516dd1e18f6ab893d43a3c6a011836124696157568380f3ce784958","release-plz.toml":"65816ad24e70fb84a5dba903c6f751346fecef6a07630023dda70fbfaf11cd52","src/condvar.rs":"182e5a2f6c06cf665bb7723c2780580647a73d9de5ff319f26c0fbbf5e7280ea","src/deadlock.rs":"7d3ebb5b4f63658435df277bb983e352e4bc651a92c4fd48ae68bf103e452d0d","src/elision.rs":"7fb2d3580ffbb0422180019af2cea33af669024946c67793a1a977ae250a7a87","src/fair_mutex.rs":"2d0c5c2b779492653cad99825180628af95ce5f4bdbcfed57e7a5f2138a55fc0","src/lib.rs":"263f907c78e226368687a8e36458ebd0129db9cba9368809c35920830e7798ec","src/mutex.rs":"77af07dd477ada09a63f31decf1fabe469db8af74b2a4317df5df418faf66266","src/once.rs":"58c78dba952e217c17bd8d5cf3dce32bb78e3e1c38a86860c8edc8c308caeca7","src/raw_fair_mutex.rs":"316f954d9673ac5b8d6bf4c19f2444800f63daf801c224d986e2d6dac810643c","src/raw_mutex.rs":"4a79255673f47e167ce28d331c3b51f245017c7023e36c1c9b09baf00cc121c6","src/raw_rwlock.rs":"e874afdc82b6fea501c5c086fc0fdbfd808c3e25cb284da60474b18cdf7ee982","src/remutex.rs":"f0c0711ed46be67f7736a8500689e37a301ccf0dacb7706e1087513d3e87a432","src/rwlock.rs":"7edd9dd320858a628388c1ebca1ed89cc2984abc30157c4b0c03194ebba7eade","src/util.rs":"37a2c8b5c9254df83e8f3a5cd831558c1045061a76c2571bdc4d78eb86e467f2","tests/issue_203.rs":"5fbdf6ec63f391d86457df949678c203a1e81e8aa32d4e10037fa76e768702c0","tests/issue_392.rs":"163a423eeea14025ad84958ae12ded4a6fbde3330f689bc3e08ed18e0c58eb8b"},"package":"70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"}

277
vendor/parking_lot/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,277 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## `parking_lot` - [0.12.4](https://github.com/Amanieu/parking_lot/compare/parking_lot-v0.12.3...parking_lot-v0.12.4) - 2025-05-29
- Fix parked upgraders potentially not being woken up after a write lock
- Fix clearing `PARKED_WRITER_BIT` after a timeout
## `parking_lot_core` - [0.9.11](https://github.com/Amanieu/parking_lot/compare/parking_lot_core-v0.9.10...parking_lot_core-v0.9.11) - 2025-05-29
- Use Release/Acquire ordering in thread_parker::windows::Backend::create
- Remove warnings due to new lint on unknown cfgs
## `lock_api` - [0.4.13](https://github.com/Amanieu/parking_lot/compare/lock_api-v0.4.12...lock_api-v0.4.13) - 2025-05-29
- Remove warnings due to new lint on unknown cfgs
## parking_lot 0.12.3 (2024-05-24)
- Export types provided by arc_lock feature (#442)
## parking_lot 0.12.2, parking_lot_core 0.9.10, lock_api 0.4.12 (2024-04-15)
- Fixed panic when calling `with_upgraded` twice on a `ArcRwLockUpgradableReadGuard` (#431)
- Fixed `RwLockUpgradeableReadGuard::with_upgraded`
- Added lock_api::{Mutex, ReentrantMutex, RwLock}::from_raw methods (#429)
- Added Apple visionOS support (#433)
## parking_lot_core 0.9.9, lock_api 0.4.11 (2023-10-18)
- Fixed `RwLockUpgradeableReadGuard::with_upgraded`. (#393)
- Fixed `ReentrantMutex::bump` lock count. (#390)
- Added methods to unsafely create a lock guard out of thin air. (#403)
- Added support for Apple tvOS. (#405)
## parking_lot_core 0.9.8, lock_api 0.4.10 (2023-06-05)
- Mark guards with `#[clippy::has_significant_drop]` (#369, #371)
- Removed windows-sys dependency (#374, #378)
- Add `atomic_usize` default feature to support platforms without atomics. (#380)
- Add with_upgraded API to upgradable read locks (#386)
- Make RwLock guards Sync again (#370)
## parking_lot_core 0.9.7 (2023-02-01)
- Update windows-sys dependency to 0.45. (#368)
## parking_lot_core 0.9.6 (2023-01-11)
- Add support for watchOS. (#367)
## parking_lot_core 0.9.5 (2022-11-29)
- Update use of `libc::timespec` to prepare for future libc version (#363)
## parking_lot_core 0.9.4 (2022-10-18)
- Bump windows-sys dependency to 0.42. (#356)
## lock_api 0.4.9 (2022-09-20)
- Fixed `ReentrantMutexGuard::try_map` signature (#355)
## lock_api 0.4.8 (2022-08-28)
- Fixed unsound `Sync`/`Send` impls for `ArcMutexGuard`. (#349)
- Added `ArcMutexGuard::into_arc`. (#350)
## parking_lot 0.12.1 (2022-05-31)
- Fixed incorrect memory ordering in `RwLock`. (#344)
- Added `Condvar::wait_while` convenience methods (#343)
## parking_lot_core 0.9.3 (2022-04-30)
- Bump windows-sys dependency to 0.36. (#339)
## parking_lot_core 0.9.2, lock_api 0.4.7 (2022-03-25)
- Enable const new() on lock types on stable. (#325)
- Added `MutexGuard::leak` function. (#333)
- Bump windows-sys dependency to 0.34. (#331)
- Bump petgraph dependency to 0.6. (#326)
- Don't use pthread attributes on the espidf platform. (#319)
## parking_lot_core 0.9.1 (2022-02-06)
- Bump windows-sys dependency to 0.32. (#316)
## parking_lot 0.12.0, parking_lot_core 0.9.0, lock_api 0.4.6 (2022-01-28)
- The MSRV is bumped to 1.49.0.
- Disabled eventual fairness on wasm32-unknown-unknown. (#302)
- Added a rwlock method to report if lock is held exclusively. (#303)
- Use new `asm!` macro. (#304)
- Use windows-rs instead of winapi for faster builds. (#311)
- Moved hardware lock elision support to a separate Cargo feature. (#313)
- Removed used of deprecated `spin_loop_hint`. (#314)
## parking_lot 0.11.2, parking_lot_core 0.8.4, lock_api 0.4.5 (2021-08-28)
- Fixed incorrect memory orderings on `RwLock` and `WordLock`. (#294, #292)
- Added `Arc`-based lock guards. (#291)
- Added workaround for TSan's lack of support for `fence`. (#292)
## lock_api 0.4.4 (2021-05-01)
- Update for latest nightly. (#281)
## lock_api 0.4.3 (2021-04-03)
- Added `[Raw]ReentrantMutex::is_owned`. (#280)
## parking_lot_core 0.8.3 (2021-02-12)
- Updated smallvec to 1.6. (#276)
## parking_lot_core 0.8.2 (2020-12-21)
- Fixed assertion failure on OpenBSD. (#270)
## parking_lot_core 0.8.1 (2020-12-04)
- Removed deprecated CloudABI support. (#263)
- Fixed build on wasm32-unknown-unknown. (#265)
- Relaxed dependency on `smallvec`. (#266)
## parking_lot 0.11.1, lock_api 0.4.2 (2020-11-18)
- Fix bounds on Send and Sync impls for lock guards. (#262)
- Fix incorrect memory ordering in `RwLock`. (#260)
## lock_api 0.4.1 (2020-07-06)
- Add `data_ptr` method to lock types to allow unsafely accessing the inner data
without a guard. (#247)
## parking_lot 0.11.0, parking_lot_core 0.8.0, lock_api 0.4.0 (2020-06-23)
- Add `is_locked` method to mutex types. (#235)
- Make `RawReentrantMutex` public. (#233)
- Allow lock guard to be sent to another thread with the `send_guard` feature. (#240)
- Use `Instant` type from the `instant` crate on wasm32-unknown-unknown. (#231)
- Remove deprecated and unsound `MappedRwLockWriteGuard::downgrade`. (#244)
- Most methods on the `Raw*` traits have been made unsafe since they assume
the current thread holds the lock. (#243)
## parking_lot_core 0.7.2 (2020-04-21)
- Add support for `wasm32-unknown-unknown` under the "nightly" feature. (#226)
## parking_lot 0.10.2 (2020-04-10)
- Update minimum version of `lock_api`.
## parking_lot 0.10.1, parking_lot_core 0.7.1, lock_api 0.3.4 (2020-04-10)
- Add methods to construct `Mutex`, `RwLock`, etc in a `const` context. (#217)
- Add `FairMutex` which always uses fair unlocking. (#204)
- Fixed panic with deadlock detection on macOS. (#203)
- Fixed incorrect synchronization in `create_hashtable`. (#210)
- Use `llvm_asm!` instead of the deprecated `asm!`. (#223)
## lock_api 0.3.3 (2020-01-04)
- Deprecate unsound `MappedRwLockWriteGuard::downgrade` (#198)
## parking_lot 0.10.0, parking_lot_core 0.7.0, lock_api 0.3.2 (2019-11-25)
- Upgrade smallvec dependency to 1.0 in parking_lot_core.
- Replace all usage of `mem::uninitialized` with `mem::MaybeUninit`.
- The minimum required Rust version is bumped to 1.36. Because of the above two changes.
- Make methods on `WaitTimeoutResult` and `OnceState` take `self` by value instead of reference.
## parking_lot_core 0.6.2 (2019-07-22)
- Fixed compile error on Windows with old cfg_if version. (#164)
## parking_lot_core 0.6.1 (2019-07-17)
- Fixed Android build. (#163)
## parking_lot 0.9.0, parking_lot_core 0.6.0, lock_api 0.3.1 (2019-07-14)
- Re-export lock_api (0.3.1) from parking_lot (#150)
- Removed (non-dev) dependency on rand crate for fairness mechanism, by
including a simple xorshift PRNG in core (#144)
- Android now uses the futex-based ThreadParker. (#140)
- Fixed CloudABI ThreadParker. (#140)
- Fix race condition in lock_api::ReentrantMutex (da16c2c7)
## lock_api 0.3.0 (2019-07-03, _yanked_)
- Use NonZeroUsize in GetThreadId::nonzero_thread_id (#148)
- Debug assert lock_count in ReentrantMutex (#148)
- Tag as `unsafe` and document some internal methods (#148)
- This release was _yanked_ due to a regression in ReentrantMutex (da16c2c7)
## parking_lot 0.8.1 (2019-07-03, _yanked_)
- Re-export lock_api (0.3.0) from parking_lot (#150)
- This release was _yanked_ from crates.io due to unexpected breakage (#156)
## parking_lot 0.8.0, parking_lot_core 0.5.0, lock_api 0.2.0 (2019-05-04)
- Fix race conditions in deadlock detection.
- Support for more platforms by adding ThreadParker implementations for
Wasm, Redox, SGX and CloudABI.
- Drop support for older Rust. parking_lot now requires 1.31 and is a
Rust 2018 edition crate (#122).
- Disable the owning_ref feature by default.
- Fix was_last_thread value in the timeout callback of park() (#129).
- Support single byte Mutex/Once on stable Rust when compiler is at least
version 1.34.
- Make Condvar::new and Once::new const fns on stable Rust and remove
ONCE_INIT (#134).
- Add optional Serde support (#135).
## parking_lot 0.7.1 (2019-01-01)
- Fixed potential deadlock when upgrading a RwLock.
- Fixed overflow panic on very long timeouts (#111).
## parking_lot 0.7.0, parking_lot_core 0.4.0 (2018-11-26)
- Return if or how many threads were notified from `Condvar::notify_*`
## parking_lot 0.6.3 (2018-07-18)
- Export `RawMutex`, `RawRwLock` and `RawThreadId`.
## parking_lot 0.6.2 (2018-06-18)
- Enable `lock_api/nightly` feature from `parking_lot/nightly` (#79)
## parking_lot 0.6.1 (2018-06-08)
Added missing typedefs for mapped lock guards:
- `MappedMutexGuard`
- `MappedReentrantMutexGuard`
- `MappedRwLockReadGuard`
- `MappedRwLockWriteGuard`
## parking_lot 0.6.0 (2018-06-08)
This release moves most of the code for type-safe `Mutex` and `RwLock` types
into a separate crate called `lock_api`. This new crate is compatible with
`no_std` and provides `Mutex` and `RwLock` type-safe wrapper types from a raw
mutex type which implements the `RawMutex` or `RawRwLock` trait. The API
provided by the wrapper types can be extended by implementing more traits on
the raw mutex type which provide more functionality (e.g. `RawMutexTimed`). See
the crate documentation for more details.
There are also several major changes:
- The minimum required Rust version is bumped to 1.26.
- All methods on `MutexGuard` (and other guard types) are no longer inherent
methods and must be called as `MutexGuard::method(self)`. This avoids
conflicts with methods from the inner type.
- `MutexGuard` (and other guard types) add the `unlocked` method which
temporarily unlocks a mutex, runs the given closure, and then re-locks the
mutex.
- `MutexGuard` (and other guard types) add the `bump` method which gives a
chance for other threads to acquire the mutex by temporarily unlocking it and
re-locking it. However this is optimized for the common case where there are
no threads waiting on the lock, in which case no unlocking is performed.
- `MutexGuard` (and other guard types) add the `map` method which returns a
`MappedMutexGuard` which holds only a subset of the original locked type. The
`MappedMutexGuard` type is identical to `MutexGuard` except that it does not
support the `unlocked` and `bump` methods, and can't be used with `CondVar`.

441
vendor/parking_lot/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,441 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "backtrace"
version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets",
]
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "hashbrown"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
[[package]]
name = "indexmap"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "libc"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "lock_api"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [
"autocfg",
"owning_ref",
"scopeguard",
"serde",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miniz_oxide"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
]
[[package]]
name = "object"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [
"memchr",
]
[[package]]
name = "owning_ref"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
dependencies = [
"stable_deref_trait",
]
[[package]]
name = "parking_lot"
version = "0.12.4"
dependencies = [
"bincode",
"lock_api",
"parking_lot_core",
"rand",
]
[[package]]
name = "parking_lot_core"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"backtrace",
"cfg-if",
"libc",
"petgraph",
"redox_syscall",
"smallvec",
"thread-id",
"windows-targets",
]
[[package]]
name = "petgraph"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
dependencies = [
"bitflags",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "smallvec"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thread-id"
version = "4.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe8f25bbdd100db7e1d34acf7fd2dc59c4bf8f7483f505eaa7d4f12f76cc0ea"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "zerocopy"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

87
vendor/parking_lot/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,87 @@
# 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 = "2021"
rust-version = "1.64"
name = "parking_lot"
version = "0.12.4"
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "More compact and efficient implementations of the standard synchronization primitives."
readme = "README.md"
keywords = [
"mutex",
"condvar",
"rwlock",
"once",
"thread",
]
categories = ["concurrency"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/Amanieu/parking_lot"
[package.metadata.docs.rs]
features = [
"arc_lock",
"serde",
"deadlock_detection",
]
rustdoc-args = ["--generate-link-to-definition"]
[package.metadata.playground]
features = [
"arc_lock",
"serde",
"deadlock_detection",
]
[features]
arc_lock = ["lock_api/arc_lock"]
deadlock_detection = ["parking_lot_core/deadlock_detection"]
default = []
hardware-lock-elision = []
nightly = [
"parking_lot_core/nightly",
"lock_api/nightly",
]
owning_ref = ["lock_api/owning_ref"]
send_guard = []
serde = ["lock_api/serde"]
[lib]
name = "parking_lot"
path = "src/lib.rs"
[[test]]
name = "issue_203"
path = "tests/issue_203.rs"
[[test]]
name = "issue_392"
path = "tests/issue_392.rs"
[dependencies.lock_api]
version = "0.4.13"
[dependencies.parking_lot_core]
version = "0.9.11"
[dev-dependencies.bincode]
version = "1.3.3"
[dev-dependencies.rand]
version = "0.8.3"

201
vendor/parking_lot/LICENSE-APACHE vendored Normal file
View 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/parking_lot/LICENSE-MIT vendored Normal file
View 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.

151
vendor/parking_lot/README.md vendored Normal file
View File

@@ -0,0 +1,151 @@
parking_lot
============
[![Rust](https://github.com/Amanieu/parking_lot/workflows/Rust/badge.svg)](https://github.com/Amanieu/parking_lot/actions)
[![Crates.io](https://img.shields.io/crates/v/parking_lot.svg)](https://crates.io/crates/parking_lot)
[Documentation (synchronization primitives)](https://docs.rs/parking_lot/)
[Documentation (core parking lot API)](https://docs.rs/parking_lot_core/)
[Documentation (type-safe lock API)](https://docs.rs/lock_api/)
This library provides implementations of `Mutex`, `RwLock`, `Condvar` and
`Once` that are smaller, faster and more flexible than those in the Rust
standard library, as well as a `ReentrantMutex` type which supports recursive
locking. It also exposes a low-level API for creating your own efficient
synchronization primitives.
When tested on x86_64 Linux, `parking_lot::Mutex` was found to be 1.5x
faster than `std::sync::Mutex` when uncontended, and up to 5x faster when
contended from multiple threads. The numbers for `RwLock` vary depending on
the number of reader and writer threads, but are almost always faster than
the standard library `RwLock`, and even up to 50x faster in some cases.
## Features
The primitives provided by this library have several advantages over those
in the Rust standard library:
1. `Mutex` and `Once` only require 1 byte of storage space, while `Condvar`
and `RwLock` only require 1 word of storage space. On the other hand on
some platforms (macOS and a few others) the standard library primitives
require a dynamically allocated `Box` to hold OS-specific synchronization
primitives. The small size of `Mutex` in particular encourages the use
of fine-grained locks to increase parallelism.
2. Uncontended lock acquisition and release is done through fast inline
paths which only require a single atomic operation.
3. Microcontention (a contended lock with a short critical section) is
efficiently handled by spinning a few times while trying to acquire a
lock.
4. The locks are adaptive and will suspend a thread after a few failed spin
attempts. This makes the locks suitable for both long and short critical
sections.
5. `Condvar`, `RwLock` and `Once` work on Windows XP, unlike the standard
library versions of those types.
6. `RwLock` takes advantage of hardware lock elision on processors that
support it, which can lead to huge performance wins with many readers.
This must be enabled with the `hardware-lock-elision` feature.
7. `RwLock` uses a task-fair locking policy, which avoids reader and writer
starvation, whereas the standard library version makes no guarantees.
8. `Condvar` is guaranteed not to produce spurious wakeups. A thread will
only be woken up if it timed out or it was woken up by a notification.
9. `Condvar::notify_all` will only wake up a single thread and requeue the
rest to wait on the associated `Mutex`. This avoids a thundering herd
problem where all threads try to acquire the lock at the same time.
10. `RwLock` supports atomically downgrading a write lock into a read lock.
11. `Mutex` and `RwLock` allow raw unlocking without a RAII guard object.
12. `Mutex<()>` and `RwLock<()>` allow raw locking without a RAII guard
object.
13. `Mutex` and `RwLock` support [eventual fairness](https://trac.webkit.org/changeset/203350)
which allows them to be fair on average without sacrificing performance.
14. A `ReentrantMutex` type which supports recursive locking.
15. An *experimental* deadlock detector that works for `Mutex`,
`RwLock` and `ReentrantMutex`. This feature is disabled by default and
can be enabled via the `deadlock_detection` feature.
16. `RwLock` supports atomically upgrading an "upgradable" read lock into a
write lock.
17. Optional support for [serde](https://docs.serde.rs/serde/). Enable via the
feature `serde`. **NOTE!** this support is for `Mutex`, `ReentrantMutex`,
and `RwLock` only; `Condvar` and `Once` are not currently supported.
18. Lock guards can be sent to other threads when the `send_guard` feature is
enabled.
## The parking lot
To keep these primitives small, all thread queuing and suspending
functionality is offloaded to the *parking lot*. The idea behind this is
based on the Webkit [`WTF::ParkingLot`](https://webkit.org/blog/6161/locking-in-webkit/)
class, which essentially consists of a hash table mapping of lock addresses
to queues of parked (sleeping) threads. The Webkit parking lot was itself
inspired by Linux [futexes](https://man7.org/linux/man-pages/man2/futex.2.html),
but it is more powerful since it allows invoking callbacks while holding a queue
lock.
## Nightly vs stable
There are a few restrictions when using this library on stable Rust:
- The `wasm32-unknown-unknown` target is only fully supported on nightly with
`-C target-feature=+atomics` in `RUSTFLAGS` and `-Zbuild-std=panic_abort,std`
passed to cargo. parking_lot will work mostly fine on stable, the only
difference is it will panic instead of block forever if you hit a deadlock.
Just make sure not to enable `-C target-feature=+atomics` on stable as that
will allow wasm to run with multiple threads which will completely break
parking_lot's concurrency guarantees.
To enable nightly-only functionality, you need to enable the `nightly` feature
in Cargo (see below).
## Usage
Add this to your `Cargo.toml`:
```toml
[dependencies]
parking_lot = "0.12"
```
To enable nightly-only features, add this to your `Cargo.toml` instead:
```toml
[dependencies]
parking_lot = { version = "0.12", features = ["nightly"] }
```
The experimental deadlock detector can be enabled with the
`deadlock_detection` Cargo feature.
To allow sending `MutexGuard`s and `RwLock*Guard`s to other threads, enable the
`send_guard` option.
Note that the `deadlock_detection` and `send_guard` features are incompatible
and cannot be used together.
Hardware lock elision support for x86 can be enabled with the
`hardware-lock-elision` feature. This requires Rust 1.59 due to the use of
inline assembly.
The core parking lot API is provided by the `parking_lot_core` crate. It is
separate from the synchronization primitives in the `parking_lot` crate so that
changes to the core API do not cause breaking changes for users of `parking_lot`.
## Minimum Rust version
The current minimum required Rust version is 1.64. Any change to this is
considered a breaking change and will require a major version bump.
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

4
vendor/parking_lot/bors.toml vendored Normal file
View File

@@ -0,0 +1,4 @@
status = [
"build_tier_one",
"build_other_platforms",
]

19
vendor/parking_lot/release-plz.toml vendored Normal file
View File

@@ -0,0 +1,19 @@
[workspace]
# set the path of all the crates to the changelog to the root of the repository
changelog_path = "./CHANGELOG.md"
[changelog]
body = """
## `{{ package }}` - [{{ version }}]{%- if release_link -%}({{ release_link }}){% endif %} - {{ timestamp | date(format="%Y-%m-%d") }}
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
{%- if commit.scope -%}
- *({{commit.scope}})* {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message }}{%- if commit.links %} ({% for link in commit.links %}[{{link.text}}]({{link.href}}) {% endfor -%}){% endif %}
{% else -%}
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message }}
{% endif -%}
{% endfor -%}
{% endfor -%}
"""

1270
vendor/parking_lot/src/condvar.rs vendored Normal file

File diff suppressed because it is too large Load Diff

232
vendor/parking_lot/src/deadlock.rs vendored Normal file
View File

@@ -0,0 +1,232 @@
//! \[Experimental\] Deadlock detection
//!
//! This feature is optional and can be enabled via the `deadlock_detection` feature flag.
//!
//! # Example
//!
//! ```
//! #[cfg(feature = "deadlock_detection")]
//! { // only for #[cfg]
//! use std::thread;
//! use std::time::Duration;
//! use parking_lot::deadlock;
//!
//! // Create a background thread which checks for deadlocks every 10s
//! thread::spawn(move || {
//! loop {
//! thread::sleep(Duration::from_secs(10));
//! let deadlocks = deadlock::check_deadlock();
//! if deadlocks.is_empty() {
//! continue;
//! }
//!
//! println!("{} deadlocks detected", deadlocks.len());
//! for (i, threads) in deadlocks.iter().enumerate() {
//! println!("Deadlock #{}", i);
//! for t in threads {
//! println!("Thread Id {:#?}", t.thread_id());
//! println!("{:#?}", t.backtrace());
//! }
//! }
//! }
//! });
//! } // only for #[cfg]
//! ```
#[cfg(feature = "deadlock_detection")]
pub use parking_lot_core::deadlock::check_deadlock;
pub(crate) use parking_lot_core::deadlock::{acquire_resource, release_resource};
#[cfg(test)]
#[cfg(feature = "deadlock_detection")]
mod tests {
use crate::{Mutex, ReentrantMutex, RwLock};
use std::sync::{Arc, Barrier};
use std::thread::{self, sleep};
use std::time::Duration;
// We need to serialize these tests since deadlock detection uses global state
static DEADLOCK_DETECTION_LOCK: Mutex<()> = crate::const_mutex(());
fn check_deadlock() -> bool {
use parking_lot_core::deadlock::check_deadlock;
!check_deadlock().is_empty()
}
#[test]
fn test_mutex_deadlock() {
let _guard = DEADLOCK_DETECTION_LOCK.lock();
let m1: Arc<Mutex<()>> = Default::default();
let m2: Arc<Mutex<()>> = Default::default();
let m3: Arc<Mutex<()>> = Default::default();
let b = Arc::new(Barrier::new(4));
let m1_ = m1.clone();
let m2_ = m2.clone();
let m3_ = m3.clone();
let b1 = b.clone();
let b2 = b.clone();
let b3 = b.clone();
assert!(!check_deadlock());
let _t1 = thread::spawn(move || {
let _g = m1.lock();
b1.wait();
let _ = m2_.lock();
});
let _t2 = thread::spawn(move || {
let _g = m2.lock();
b2.wait();
let _ = m3_.lock();
});
let _t3 = thread::spawn(move || {
let _g = m3.lock();
b3.wait();
let _ = m1_.lock();
});
assert!(!check_deadlock());
b.wait();
sleep(Duration::from_millis(50));
assert!(check_deadlock());
assert!(!check_deadlock());
}
#[test]
fn test_mutex_deadlock_reentrant() {
let _guard = DEADLOCK_DETECTION_LOCK.lock();
let m1: Arc<Mutex<()>> = Default::default();
assert!(!check_deadlock());
let _t1 = thread::spawn(move || {
let _g = m1.lock();
let _ = m1.lock();
});
sleep(Duration::from_millis(50));
assert!(check_deadlock());
assert!(!check_deadlock());
}
#[test]
fn test_remutex_deadlock() {
let _guard = DEADLOCK_DETECTION_LOCK.lock();
let m1: Arc<ReentrantMutex<()>> = Default::default();
let m2: Arc<ReentrantMutex<()>> = Default::default();
let m3: Arc<ReentrantMutex<()>> = Default::default();
let b = Arc::new(Barrier::new(4));
let m1_ = m1.clone();
let m2_ = m2.clone();
let m3_ = m3.clone();
let b1 = b.clone();
let b2 = b.clone();
let b3 = b.clone();
assert!(!check_deadlock());
let _t1 = thread::spawn(move || {
let _g = m1.lock();
let _g = m1.lock();
b1.wait();
let _ = m2_.lock();
});
let _t2 = thread::spawn(move || {
let _g = m2.lock();
let _g = m2.lock();
b2.wait();
let _ = m3_.lock();
});
let _t3 = thread::spawn(move || {
let _g = m3.lock();
let _g = m3.lock();
b3.wait();
let _ = m1_.lock();
});
assert!(!check_deadlock());
b.wait();
sleep(Duration::from_millis(50));
assert!(check_deadlock());
assert!(!check_deadlock());
}
#[test]
fn test_rwlock_deadlock() {
let _guard = DEADLOCK_DETECTION_LOCK.lock();
let m1: Arc<RwLock<()>> = Default::default();
let m2: Arc<RwLock<()>> = Default::default();
let m3: Arc<RwLock<()>> = Default::default();
let b = Arc::new(Barrier::new(4));
let m1_ = m1.clone();
let m2_ = m2.clone();
let m3_ = m3.clone();
let b1 = b.clone();
let b2 = b.clone();
let b3 = b.clone();
assert!(!check_deadlock());
let _t1 = thread::spawn(move || {
let _g = m1.read();
b1.wait();
let _g = m2_.write();
});
let _t2 = thread::spawn(move || {
let _g = m2.read();
b2.wait();
let _g = m3_.write();
});
let _t3 = thread::spawn(move || {
let _g = m3.read();
b3.wait();
let _ = m1_.write();
});
assert!(!check_deadlock());
b.wait();
sleep(Duration::from_millis(50));
assert!(check_deadlock());
assert!(!check_deadlock());
}
#[cfg(rwlock_deadlock_detection_not_supported)]
#[test]
fn test_rwlock_deadlock_reentrant() {
let _guard = DEADLOCK_DETECTION_LOCK.lock();
let m1: Arc<RwLock<()>> = Default::default();
assert!(!check_deadlock());
let _t1 = thread::spawn(move || {
let _g = m1.read();
let _ = m1.write();
});
sleep(Duration::from_millis(50));
assert!(check_deadlock());
assert!(!check_deadlock());
}
}

116
vendor/parking_lot/src/elision.rs vendored Normal file
View File

@@ -0,0 +1,116 @@
// 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 std::sync::atomic::AtomicUsize;
// Extension trait to add lock elision primitives to atomic types
pub trait AtomicElisionExt {
type IntType;
// Perform a compare_exchange and start a transaction
fn elision_compare_exchange_acquire(
&self,
current: Self::IntType,
new: Self::IntType,
) -> Result<Self::IntType, Self::IntType>;
// Perform a fetch_sub and end a transaction
fn elision_fetch_sub_release(&self, val: Self::IntType) -> Self::IntType;
}
// Indicates whether the target architecture supports lock elision
#[inline]
pub fn have_elision() -> bool {
cfg!(all(
feature = "hardware-lock-elision",
any(target_arch = "x86", target_arch = "x86_64"),
))
}
// This implementation is never actually called because it is guarded by
// have_elision().
#[cfg(not(all(
feature = "hardware-lock-elision",
any(target_arch = "x86", target_arch = "x86_64")
)))]
impl AtomicElisionExt for AtomicUsize {
type IntType = usize;
#[inline]
fn elision_compare_exchange_acquire(&self, _: usize, _: usize) -> Result<usize, usize> {
unreachable!();
}
#[inline]
fn elision_fetch_sub_release(&self, _: usize) -> usize {
unreachable!();
}
}
#[cfg(all(
feature = "hardware-lock-elision",
any(target_arch = "x86", target_arch = "x86_64")
))]
impl AtomicElisionExt for AtomicUsize {
type IntType = usize;
#[inline]
fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result<usize, usize> {
unsafe {
use core::arch::asm;
let prev: usize;
#[cfg(target_pointer_width = "32")]
asm!(
"xacquire",
"lock",
"cmpxchg [{:e}], {:e}",
in(reg) self,
in(reg) new,
inout("eax") current => prev,
);
#[cfg(target_pointer_width = "64")]
asm!(
"xacquire",
"lock",
"cmpxchg [{}], {}",
in(reg) self,
in(reg) new,
inout("rax") current => prev,
);
if prev == current {
Ok(prev)
} else {
Err(prev)
}
}
}
#[inline]
fn elision_fetch_sub_release(&self, val: usize) -> usize {
unsafe {
use core::arch::asm;
let prev: usize;
#[cfg(target_pointer_width = "32")]
asm!(
"xrelease",
"lock",
"xadd [{:e}], {:e}",
in(reg) self,
inout(reg) val.wrapping_neg() => prev,
);
#[cfg(target_pointer_width = "64")]
asm!(
"xrelease",
"lock",
"xadd [{}], {}",
in(reg) self,
inout(reg) val.wrapping_neg() => prev,
);
prev
}
}
}

274
vendor/parking_lot/src/fair_mutex.rs vendored Normal file
View File

@@ -0,0 +1,274 @@
// 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 crate::raw_fair_mutex::RawFairMutex;
/// A mutual exclusive primitive that is always fair, useful for protecting shared data
///
/// This mutex will block threads waiting for the lock to become available. The
/// mutex can be statically initialized or created by the `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.
///
/// The regular mutex provided by `parking_lot` uses eventual fairness
/// (after some time it will default to the fair algorithm), but eventual
/// fairness does not provide the same guarantees an always fair method would.
/// Fair mutexes are generally slower, but sometimes needed.
///
/// In a fair mutex the waiters form a queue, and the lock is always granted to
/// the next requester in the queue, in first-in first-out order. This ensures
/// that one thread cannot starve others by quickly re-acquiring the lock after
/// releasing it.
///
/// A fair mutex may not be interesting if threads have different priorities (this is known as
/// priority inversion).
///
/// # Differences from the standard library `Mutex`
///
/// - No poisoning, the lock is released normally on panic.
/// - Only requires 1 byte of space, whereas the standard library boxes the
/// `FairMutex` due to platform limitations.
/// - Can be statically constructed.
/// - Does not require any drop glue when dropped.
/// - Inline fast path for the uncontended case.
/// - Efficient handling of micro-contention using adaptive spinning.
/// - Allows raw locking & unlocking without a guard.
///
/// # Examples
///
/// ```
/// use parking_lot::FairMutex;
/// use std::sync::{Arc, mpsc::channel};
/// use std::thread;
///
/// const N: usize = 10;
///
/// // Spawn a few threads to increment a shared variable (non-atomically), and
/// // let the main thread know once all increments are done.
/// //
/// // Here we're using an Arc to share memory among threads, and the data inside
/// // the Arc is protected with a mutex.
/// let data = Arc::new(FairMutex::new(0));
///
/// let (tx, rx) = channel();
/// for _ in 0..10 {
/// let (data, tx) = (Arc::clone(&data), tx.clone());
/// thread::spawn(move || {
/// // The shared state can only be accessed once the lock is held.
/// // Our non-atomic increment is safe because we're the only thread
/// // which can access the shared state when the lock is held.
/// let mut data = data.lock();
/// *data += 1;
/// if *data == N {
/// tx.send(()).unwrap();
/// }
/// // the lock is unlocked here when `data` goes out of scope.
/// });
/// }
///
/// rx.recv().unwrap();
/// ```
pub type FairMutex<T> = lock_api::Mutex<RawFairMutex, T>;
/// Creates a new fair mutex in an unlocked state ready for use.
///
/// This allows creating a fair mutex in a constant context on stable Rust.
pub const fn const_fair_mutex<T>(val: T) -> FairMutex<T> {
FairMutex::const_new(<RawFairMutex as lock_api::RawMutex>::INIT, val)
}
/// 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.
pub type FairMutexGuard<'a, T> = lock_api::MutexGuard<'a, RawFairMutex, T>;
/// An RAII mutex guard returned by `FairMutexGuard::map`, which can point to a
/// subfield of the protected data.
///
/// The main difference between `MappedFairMutexGuard` and `FairMutexGuard` 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.
pub type MappedFairMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawFairMutex, T>;
#[cfg(test)]
mod tests {
use crate::FairMutex;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::thread;
#[cfg(feature = "serde")]
use bincode::{deserialize, serialize};
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
#[test]
fn smoke() {
let m = FairMutex::new(());
drop(m.lock());
drop(m.lock());
}
#[test]
fn lots_and_lots() {
const J: u32 = 1000;
const K: u32 = 3;
let m = Arc::new(FairMutex::new(0));
fn inc(m: &FairMutex<u32>) {
for _ in 0..J {
*m.lock() += 1;
}
}
let (tx, rx) = channel();
for _ in 0..K {
let tx2 = tx.clone();
let m2 = m.clone();
thread::spawn(move || {
inc(&m2);
tx2.send(()).unwrap();
});
let tx2 = tx.clone();
let m2 = m.clone();
thread::spawn(move || {
inc(&m2);
tx2.send(()).unwrap();
});
}
drop(tx);
for _ in 0..2 * K {
rx.recv().unwrap();
}
assert_eq!(*m.lock(), J * K * 2);
}
#[test]
fn try_lock() {
let m = FairMutex::new(());
*m.try_lock().unwrap() = ();
}
#[test]
fn test_into_inner() {
let m = FairMutex::new(NonCopy(10));
assert_eq!(m.into_inner(), NonCopy(10));
}
#[test]
fn test_into_inner_drop() {
struct Foo(Arc<AtomicUsize>);
impl Drop for Foo {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
let num_drops = Arc::new(AtomicUsize::new(0));
let m = FairMutex::new(Foo(num_drops.clone()));
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
{
let _inner = m.into_inner();
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
}
assert_eq!(num_drops.load(Ordering::SeqCst), 1);
}
#[test]
fn test_get_mut() {
let mut m = FairMutex::new(NonCopy(10));
*m.get_mut() = NonCopy(20);
assert_eq!(m.into_inner(), NonCopy(20));
}
#[test]
fn test_mutex_arc_nested() {
// Tests nested mutexes and access
// to underlying data.
let arc = Arc::new(FairMutex::new(1));
let arc2 = Arc::new(FairMutex::new(arc));
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let lock = arc2.lock();
let lock2 = lock.lock();
assert_eq!(*lock2, 1);
tx.send(()).unwrap();
});
rx.recv().unwrap();
}
#[test]
fn test_mutex_arc_access_in_unwind() {
let arc = Arc::new(FairMutex::new(1));
let arc2 = arc.clone();
let _ = thread::spawn(move || {
struct Unwinder {
i: Arc<FairMutex<i32>>,
}
impl Drop for Unwinder {
fn drop(&mut self) {
*self.i.lock() += 1;
}
}
let _u = Unwinder { i: arc2 };
panic!();
})
.join();
let lock = arc.lock();
assert_eq!(*lock, 2);
}
#[test]
fn test_mutex_unsized() {
let mutex: &FairMutex<[i32]> = &FairMutex::new([1, 2, 3]);
{
let b = &mut *mutex.lock();
b[0] = 4;
b[2] = 5;
}
let comp: &[i32] = &[4, 2, 5];
assert_eq!(&*mutex.lock(), comp);
}
#[test]
fn test_mutexguard_sync() {
fn sync<T: Sync>(_: T) {}
let mutex = FairMutex::new(());
sync(mutex.lock());
}
#[test]
fn test_mutex_debug() {
let mutex = FairMutex::new(vec![0u8, 10]);
assert_eq!(format!("{:?}", mutex), "Mutex { data: [0, 10] }");
let _lock = mutex.lock();
assert_eq!(format!("{:?}", mutex), "Mutex { data: <locked> }");
}
#[cfg(feature = "serde")]
#[test]
fn test_serde() {
let contents: Vec<u8> = vec![0, 1, 2];
let mutex = FairMutex::new(contents.clone());
let serialized = serialize(&mutex).unwrap();
let deserialized: FairMutex<Vec<u8>> = deserialize(&serialized).unwrap();
assert_eq!(*(mutex.lock()), *(deserialized.lock()));
assert_eq!(contents, *(deserialized.lock()));
}
}

59
vendor/parking_lot/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,59 @@
// 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.
//! This library provides implementations of `Mutex`, `RwLock`, `Condvar` and
//! `Once` that are smaller, faster and more flexible than those in the Rust
//! standard library. It also provides a `ReentrantMutex` type.
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
mod condvar;
mod elision;
mod fair_mutex;
mod mutex;
mod once;
mod raw_fair_mutex;
mod raw_mutex;
mod raw_rwlock;
mod remutex;
mod rwlock;
mod util;
#[cfg(feature = "deadlock_detection")]
pub mod deadlock;
#[cfg(not(feature = "deadlock_detection"))]
mod deadlock;
// If deadlock detection is enabled, we cannot allow lock guards to be sent to
// other threads.
#[cfg(all(feature = "send_guard", feature = "deadlock_detection"))]
compile_error!("the `send_guard` and `deadlock_detection` features cannot be used together");
#[cfg(feature = "send_guard")]
type GuardMarker = lock_api::GuardSend;
#[cfg(not(feature = "send_guard"))]
type GuardMarker = lock_api::GuardNoSend;
pub use self::condvar::{Condvar, WaitTimeoutResult};
pub use self::fair_mutex::{const_fair_mutex, FairMutex, FairMutexGuard, MappedFairMutexGuard};
pub use self::mutex::{const_mutex, MappedMutexGuard, Mutex, MutexGuard};
pub use self::once::{Once, OnceState};
pub use self::raw_fair_mutex::RawFairMutex;
pub use self::raw_mutex::RawMutex;
pub use self::raw_rwlock::RawRwLock;
pub use self::remutex::{
const_reentrant_mutex, MappedReentrantMutexGuard, RawThreadId, ReentrantMutex,
ReentrantMutexGuard,
};
pub use self::rwlock::{
const_rwlock, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard,
RwLockUpgradableReadGuard, RwLockWriteGuard,
};
pub use ::lock_api;
#[cfg(feature = "arc_lock")]
pub use self::lock_api::{ArcMutexGuard, ArcReentrantMutexGuard, ArcRwLockReadGuard, ArcRwLockUpgradableReadGuard, ArcRwLockWriteGuard};

311
vendor/parking_lot/src/mutex.rs vendored Normal file
View File

@@ -0,0 +1,311 @@
// 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 crate::raw_mutex::RawMutex;
/// A mutual exclusion primitive useful for protecting shared data
///
/// This mutex will block threads waiting for the lock to become available. The
/// mutex can be statically initialized or created by the `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.
///
/// # Fairness
///
/// A typical unfair lock can often end up in a situation where a single thread
/// quickly acquires and releases the same mutex in succession, which can starve
/// other threads waiting to acquire the mutex. While this improves throughput
/// because it doesn't force a context switch when a thread tries to re-acquire
/// a mutex it has just released, this can starve other threads.
///
/// This mutex uses [eventual fairness](https://trac.webkit.org/changeset/203350)
/// to ensure that the lock will be fair on average without sacrificing
/// throughput. This is done by forcing a fair unlock on average every 0.5ms,
/// which will force the lock to go to the next thread waiting for the mutex.
///
/// Additionally, any critical section longer than 1ms will always use a fair
/// unlock, which has a negligible impact on throughput considering the length
/// of the critical section.
///
/// You can also force a fair unlock by calling `MutexGuard::unlock_fair` when
/// unlocking a mutex instead of simply dropping the `MutexGuard`.
///
/// # Differences from the standard library `Mutex`
///
/// - No poisoning, the lock is released normally on panic.
/// - Only requires 1 byte of space, whereas the standard library boxes the
/// `Mutex` due to platform limitations.
/// - Can be statically constructed.
/// - Does not require any drop glue when dropped.
/// - Inline fast path for the uncontended case.
/// - Efficient handling of micro-contention using adaptive spinning.
/// - Allows raw locking & unlocking without a guard.
/// - Supports eventual fairness so that the mutex is fair on average.
/// - Optionally allows making the mutex fair by calling `MutexGuard::unlock_fair`.
///
/// # Examples
///
/// ```
/// use parking_lot::Mutex;
/// use std::sync::{Arc, mpsc::channel};
/// use std::thread;
///
/// const N: usize = 10;
///
/// // Spawn a few threads to increment a shared variable (non-atomically), and
/// // let the main thread know once all increments are done.
/// //
/// // Here we're using an Arc to share memory among threads, and the data inside
/// // the Arc is protected with a mutex.
/// let data = Arc::new(Mutex::new(0));
///
/// let (tx, rx) = channel();
/// for _ in 0..10 {
/// let (data, tx) = (Arc::clone(&data), tx.clone());
/// thread::spawn(move || {
/// // The shared state can only be accessed once the lock is held.
/// // Our non-atomic increment is safe because we're the only thread
/// // which can access the shared state when the lock is held.
/// let mut data = data.lock();
/// *data += 1;
/// if *data == N {
/// tx.send(()).unwrap();
/// }
/// // the lock is unlocked here when `data` goes out of scope.
/// });
/// }
///
/// rx.recv().unwrap();
/// ```
pub type Mutex<T> = lock_api::Mutex<RawMutex, T>;
/// Creates a new mutex in an unlocked state ready for use.
///
/// This allows creating a mutex in a constant context on stable Rust.
pub const fn const_mutex<T>(val: T) -> Mutex<T> {
Mutex::const_new(<RawMutex as lock_api::RawMutex>::INIT, val)
}
/// 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.
pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>;
/// 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.
pub type MappedMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawMutex, T>;
#[cfg(test)]
mod tests {
use crate::{Condvar, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::thread;
#[cfg(feature = "serde")]
use bincode::{deserialize, serialize};
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
unsafe impl<T: Send> Send for Packet<T> {}
unsafe impl<T> Sync for Packet<T> {}
#[test]
fn smoke() {
let m = Mutex::new(());
drop(m.lock());
drop(m.lock());
}
#[test]
fn lots_and_lots() {
const J: u32 = 1000;
const K: u32 = 3;
let m = Arc::new(Mutex::new(0));
fn inc(m: &Mutex<u32>) {
for _ in 0..J {
*m.lock() += 1;
}
}
let (tx, rx) = channel();
for _ in 0..K {
let tx2 = tx.clone();
let m2 = m.clone();
thread::spawn(move || {
inc(&m2);
tx2.send(()).unwrap();
});
let tx2 = tx.clone();
let m2 = m.clone();
thread::spawn(move || {
inc(&m2);
tx2.send(()).unwrap();
});
}
drop(tx);
for _ in 0..2 * K {
rx.recv().unwrap();
}
assert_eq!(*m.lock(), J * K * 2);
}
#[test]
fn try_lock() {
let m = Mutex::new(());
*m.try_lock().unwrap() = ();
}
#[test]
fn test_into_inner() {
let m = Mutex::new(NonCopy(10));
assert_eq!(m.into_inner(), NonCopy(10));
}
#[test]
fn test_into_inner_drop() {
struct Foo(Arc<AtomicUsize>);
impl Drop for Foo {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
let num_drops = Arc::new(AtomicUsize::new(0));
let m = Mutex::new(Foo(num_drops.clone()));
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
{
let _inner = m.into_inner();
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
}
assert_eq!(num_drops.load(Ordering::SeqCst), 1);
}
#[test]
fn test_get_mut() {
let mut m = Mutex::new(NonCopy(10));
*m.get_mut() = NonCopy(20);
assert_eq!(m.into_inner(), NonCopy(20));
}
#[test]
fn test_mutex_arc_condvar() {
let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
let packet2 = Packet(packet.0.clone());
let (tx, rx) = channel();
let _t = thread::spawn(move || {
// wait until parent gets in
rx.recv().unwrap();
let (lock, cvar) = &*packet2.0;
let mut lock = lock.lock();
*lock = true;
cvar.notify_one();
});
let (lock, cvar) = &*packet.0;
let mut lock = lock.lock();
tx.send(()).unwrap();
assert!(!*lock);
while !*lock {
cvar.wait(&mut lock);
}
}
#[test]
fn test_mutex_arc_nested() {
// Tests nested mutexes and access
// to underlying data.
let arc = Arc::new(Mutex::new(1));
let arc2 = Arc::new(Mutex::new(arc));
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let lock = arc2.lock();
let lock2 = lock.lock();
assert_eq!(*lock2, 1);
tx.send(()).unwrap();
});
rx.recv().unwrap();
}
#[test]
fn test_mutex_arc_access_in_unwind() {
let arc = Arc::new(Mutex::new(1));
let arc2 = arc.clone();
let _ = thread::spawn(move || {
struct Unwinder {
i: Arc<Mutex<i32>>,
}
impl Drop for Unwinder {
fn drop(&mut self) {
*self.i.lock() += 1;
}
}
let _u = Unwinder { i: arc2 };
panic!();
})
.join();
let lock = arc.lock();
assert_eq!(*lock, 2);
}
#[test]
fn test_mutex_unsized() {
let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
{
let b = &mut *mutex.lock();
b[0] = 4;
b[2] = 5;
}
let comp: &[i32] = &[4, 2, 5];
assert_eq!(&*mutex.lock(), comp);
}
#[test]
fn test_mutexguard_sync() {
fn sync<T: Sync>(_: T) {}
let mutex = Mutex::new(());
sync(mutex.lock());
}
#[test]
fn test_mutex_debug() {
let mutex = Mutex::new(vec![0u8, 10]);
assert_eq!(format!("{:?}", mutex), "Mutex { data: [0, 10] }");
let _lock = mutex.lock();
assert_eq!(format!("{:?}", mutex), "Mutex { data: <locked> }");
}
#[cfg(feature = "serde")]
#[test]
fn test_serde() {
let contents: Vec<u8> = vec![0, 1, 2];
let mutex = Mutex::new(contents.clone());
let serialized = serialize(&mutex).unwrap();
let deserialized: Mutex<Vec<u8>> = deserialize(&serialized).unwrap();
assert_eq!(*(mutex.lock()), *(deserialized.lock()));
assert_eq!(contents, *(deserialized.lock()));
}
}

452
vendor/parking_lot/src/once.rs vendored Normal file
View File

@@ -0,0 +1,452 @@
// 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 crate::util::UncheckedOptionExt;
use core::{
fmt, mem,
sync::atomic::{fence, AtomicU8, Ordering},
};
use parking_lot_core::{self, SpinWait, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN};
const DONE_BIT: u8 = 1;
const POISON_BIT: u8 = 2;
const LOCKED_BIT: u8 = 4;
const PARKED_BIT: u8 = 8;
/// Current state of a `Once`.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum OnceState {
/// A closure has not been executed yet
New,
/// A closure was executed but panicked.
Poisoned,
/// A thread is currently executing a closure.
InProgress,
/// A closure has completed successfully.
Done,
}
impl OnceState {
/// Returns whether the associated `Once` has been poisoned.
///
/// Once an initialization routine for a `Once` has panicked it will forever
/// indicate to future forced initialization routines that it is poisoned.
#[inline]
pub fn poisoned(self) -> bool {
matches!(self, OnceState::Poisoned)
}
/// Returns whether the associated `Once` has successfully executed a
/// closure.
#[inline]
pub fn done(self) -> bool {
matches!(self, OnceState::Done)
}
}
/// A synchronization primitive which can be used to run a one-time
/// initialization. Useful for one-time initialization for globals, FFI or
/// related functionality.
///
/// # Differences from the standard library `Once`
///
/// - Only requires 1 byte of space, instead of 1 word.
/// - Not required to be `'static`.
/// - Relaxed memory barriers in the fast path, which can significantly improve
/// performance on some architectures.
/// - Efficient handling of micro-contention using adaptive spinning.
///
/// # Examples
///
/// ```
/// use parking_lot::Once;
///
/// static START: Once = Once::new();
///
/// START.call_once(|| {
/// // run initialization here
/// });
/// ```
pub struct Once(AtomicU8);
impl Once {
/// Creates a new `Once` value.
#[inline]
pub const fn new() -> Once {
Once(AtomicU8::new(0))
}
/// Returns the current state of this `Once`.
#[inline]
pub fn state(&self) -> OnceState {
let state = self.0.load(Ordering::Acquire);
if state & DONE_BIT != 0 {
OnceState::Done
} else if state & LOCKED_BIT != 0 {
OnceState::InProgress
} else if state & POISON_BIT != 0 {
OnceState::Poisoned
} else {
OnceState::New
}
}
/// Performs an initialization routine once and only once. The given closure
/// will be executed if this is the first time `call_once` has been called,
/// and otherwise the routine will *not* be invoked.
///
/// This method will block the calling thread if another initialization
/// routine is currently running.
///
/// When this function returns, it is guaranteed that some initialization
/// has run and completed (it may not be the closure specified). It is also
/// guaranteed that any memory writes performed by the executed closure can
/// be reliably observed by other threads at this point (there is a
/// happens-before relation between the closure and code executing after the
/// return).
///
/// # Examples
///
/// ```
/// use parking_lot::Once;
///
/// static mut VAL: usize = 0;
/// static INIT: Once = Once::new();
///
/// // Accessing a `static mut` is unsafe much of the time, but if we do so
/// // in a synchronized fashion (e.g. write once or read all) then we're
/// // good to go!
/// //
/// // This function will only call `expensive_computation` once, and will
/// // otherwise always return the value returned from the first invocation.
/// fn get_cached_val() -> usize {
/// unsafe {
/// INIT.call_once(|| {
/// VAL = expensive_computation();
/// });
/// VAL
/// }
/// }
///
/// fn expensive_computation() -> usize {
/// // ...
/// # 2
/// }
/// ```
///
/// # Panics
///
/// The closure `f` will only be executed once if this is called
/// concurrently amongst many threads. If that closure panics, however, then
/// it will *poison* this `Once` instance, causing all future invocations of
/// `call_once` to also panic.
#[inline]
pub fn call_once<F>(&self, f: F)
where
F: FnOnce(),
{
if self.0.load(Ordering::Acquire) == DONE_BIT {
return;
}
let mut f = Some(f);
self.call_once_slow(false, &mut |_| unsafe { f.take().unchecked_unwrap()() });
}
/// Performs the same function as `call_once` except ignores poisoning.
///
/// If this `Once` has been poisoned (some initialization panicked) then
/// this function will continue to attempt to call initialization functions
/// until one of them doesn't panic.
///
/// The closure `f` is yielded a structure which can be used to query the
/// state of this `Once` (whether initialization has previously panicked or
/// not).
#[inline]
pub fn call_once_force<F>(&self, f: F)
where
F: FnOnce(OnceState),
{
if self.0.load(Ordering::Acquire) == DONE_BIT {
return;
}
let mut f = Some(f);
self.call_once_slow(true, &mut |state| unsafe {
f.take().unchecked_unwrap()(state)
});
}
// This is a non-generic function to reduce the monomorphization cost of
// using `call_once` (this isn't exactly a trivial or small implementation).
//
// Additionally, this is tagged with `#[cold]` as it should indeed be cold
// and it helps let LLVM know that calls to this function should be off the
// fast path. Essentially, this should help generate more straight line code
// in LLVM.
//
// Finally, this takes an `FnMut` instead of a `FnOnce` because there's
// currently no way to take an `FnOnce` and call it via virtual dispatch
// without some allocation overhead.
#[cold]
fn call_once_slow(&self, ignore_poison: bool, f: &mut dyn FnMut(OnceState)) {
let mut spinwait = SpinWait::new();
let mut state = self.0.load(Ordering::Relaxed);
loop {
// If another thread called the closure, we're done
if state & DONE_BIT != 0 {
// An acquire fence is needed here since we didn't load the
// state with Ordering::Acquire.
fence(Ordering::Acquire);
return;
}
// If the state has been poisoned and we aren't forcing, then panic
if state & POISON_BIT != 0 && !ignore_poison {
// Need the fence here as well for the same reason
fence(Ordering::Acquire);
panic!("Once instance has previously been poisoned");
}
// Grab the lock if it isn't locked, even if there is a queue on it.
// We also clear the poison bit since we are going to try running
// the closure again.
if state & LOCKED_BIT == 0 {
match self.0.compare_exchange_weak(
state,
(state | LOCKED_BIT) & !POISON_BIT,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => break,
Err(x) => state = x,
}
continue;
}
// If there is no queue, try spinning a few times
if state & PARKED_BIT == 0 && spinwait.spin() {
state = self.0.load(Ordering::Relaxed);
continue;
}
// Set the parked bit
if state & PARKED_BIT == 0 {
if let Err(x) = self.0.compare_exchange_weak(
state,
state | PARKED_BIT,
Ordering::Relaxed,
Ordering::Relaxed,
) {
state = x;
continue;
}
}
// Park our thread until we are woken up by the thread that owns the
// lock.
let addr = self as *const _ as usize;
let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
let before_sleep = || {};
let timed_out = |_, _| unreachable!();
unsafe {
parking_lot_core::park(
addr,
validate,
before_sleep,
timed_out,
DEFAULT_PARK_TOKEN,
None,
);
}
// Loop back and check if the done bit was set
spinwait.reset();
state = self.0.load(Ordering::Relaxed);
}
struct PanicGuard<'a>(&'a Once);
impl<'a> Drop for PanicGuard<'a> {
fn drop(&mut self) {
// Mark the state as poisoned, unlock it and unpark all threads.
let once = self.0;
let state = once.0.swap(POISON_BIT, Ordering::Release);
if state & PARKED_BIT != 0 {
let addr = once as *const _ as usize;
unsafe {
parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
}
}
}
}
// At this point we have the lock, so run the closure. Make sure we
// properly clean up if the closure panicks.
let guard = PanicGuard(self);
let once_state = if state & POISON_BIT != 0 {
OnceState::Poisoned
} else {
OnceState::New
};
f(once_state);
mem::forget(guard);
// Now unlock the state, set the done bit and unpark all threads
let state = self.0.swap(DONE_BIT, Ordering::Release);
if state & PARKED_BIT != 0 {
let addr = self as *const _ as usize;
unsafe {
parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
}
}
}
}
impl Default for Once {
#[inline]
fn default() -> Once {
Once::new()
}
}
impl fmt::Debug for Once {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Once")
.field("state", &self.state())
.finish()
}
}
#[cfg(test)]
mod tests {
use crate::Once;
use std::panic;
use std::sync::mpsc::channel;
use std::thread;
#[test]
fn smoke_once() {
static O: Once = Once::new();
let mut a = 0;
O.call_once(|| a += 1);
assert_eq!(a, 1);
O.call_once(|| a += 1);
assert_eq!(a, 1);
}
#[test]
fn stampede_once() {
static O: Once = Once::new();
static mut RUN: bool = false;
let (tx, rx) = channel();
for _ in 0..10 {
let tx = tx.clone();
thread::spawn(move || {
for _ in 0..4 {
thread::yield_now()
}
unsafe {
O.call_once(|| {
assert!(!RUN);
RUN = true;
});
assert!(RUN);
}
tx.send(()).unwrap();
});
}
unsafe {
O.call_once(|| {
assert!(!RUN);
RUN = true;
});
assert!(RUN);
}
for _ in 0..10 {
rx.recv().unwrap();
}
}
#[test]
fn poison_bad() {
static O: Once = Once::new();
// poison the once
let t = panic::catch_unwind(|| {
O.call_once(|| panic!());
});
assert!(t.is_err());
// poisoning propagates
let t = panic::catch_unwind(|| {
O.call_once(|| {});
});
assert!(t.is_err());
// we can subvert poisoning, however
let mut called = false;
O.call_once_force(|p| {
called = true;
assert!(p.poisoned())
});
assert!(called);
// once any success happens, we stop propagating the poison
O.call_once(|| {});
}
#[test]
fn wait_for_force_to_finish() {
static O: Once = Once::new();
// poison the once
let t = panic::catch_unwind(|| {
O.call_once(|| panic!());
});
assert!(t.is_err());
// make sure someone's waiting inside the once via a force
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
let t1 = thread::spawn(move || {
O.call_once_force(|p| {
assert!(p.poisoned());
tx1.send(()).unwrap();
rx2.recv().unwrap();
});
});
rx1.recv().unwrap();
// put another waiter on the once
let t2 = thread::spawn(|| {
let mut called = false;
O.call_once(|| {
called = true;
});
assert!(!called);
});
tx2.send(()).unwrap();
assert!(t1.join().is_ok());
assert!(t2.join().is_ok());
}
#[test]
fn test_once_debug() {
static O: Once = Once::new();
assert_eq!(format!("{:?}", O), "Once { state: New }");
}
}

View File

@@ -0,0 +1,65 @@
// 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 crate::raw_mutex::RawMutex;
use lock_api::RawMutexFair;
/// Raw fair mutex type backed by the parking lot.
pub struct RawFairMutex(RawMutex);
unsafe impl lock_api::RawMutex for RawFairMutex {
const INIT: Self = RawFairMutex(<RawMutex as lock_api::RawMutex>::INIT);
type GuardMarker = <RawMutex as lock_api::RawMutex>::GuardMarker;
#[inline]
fn lock(&self) {
self.0.lock()
}
#[inline]
fn try_lock(&self) -> bool {
self.0.try_lock()
}
#[inline]
unsafe fn unlock(&self) {
self.unlock_fair()
}
#[inline]
fn is_locked(&self) -> bool {
self.0.is_locked()
}
}
unsafe impl lock_api::RawMutexFair for RawFairMutex {
#[inline]
unsafe fn unlock_fair(&self) {
self.0.unlock_fair()
}
#[inline]
unsafe fn bump(&self) {
self.0.bump()
}
}
unsafe impl lock_api::RawMutexTimed for RawFairMutex {
type Duration = <RawMutex as lock_api::RawMutexTimed>::Duration;
type Instant = <RawMutex as lock_api::RawMutexTimed>::Instant;
#[inline]
fn try_lock_until(&self, timeout: Self::Instant) -> bool {
self.0.try_lock_until(timeout)
}
#[inline]
fn try_lock_for(&self, timeout: Self::Duration) -> bool {
self.0.try_lock_for(timeout)
}
}

331
vendor/parking_lot/src/raw_mutex.rs vendored Normal file
View File

@@ -0,0 +1,331 @@
// 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 crate::{deadlock, util};
use core::{
sync::atomic::{AtomicU8, Ordering},
time::Duration,
};
use lock_api::RawMutex as RawMutex_;
use parking_lot_core::{self, ParkResult, SpinWait, UnparkResult, UnparkToken, DEFAULT_PARK_TOKEN};
use std::time::Instant;
// UnparkToken used to indicate that that the target thread should attempt to
// lock the mutex again as soon as it is unparked.
pub(crate) const TOKEN_NORMAL: UnparkToken = UnparkToken(0);
// UnparkToken used to indicate that the mutex is being handed off to the target
// thread directly without unlocking it.
pub(crate) const TOKEN_HANDOFF: UnparkToken = UnparkToken(1);
/// This bit is set in the `state` of a `RawMutex` when that mutex is locked by some thread.
const LOCKED_BIT: u8 = 0b01;
/// This bit is set in the `state` of a `RawMutex` just before parking a thread. A thread is being
/// parked if it wants to lock the mutex, but it is currently being held by some other thread.
const PARKED_BIT: u8 = 0b10;
/// Raw mutex type backed by the parking lot.
pub struct RawMutex {
/// This atomic integer holds the current state of the mutex instance. Only the two lowest bits
/// are used. See `LOCKED_BIT` and `PARKED_BIT` for the bitmask for these bits.
///
/// # State table:
///
/// PARKED_BIT | LOCKED_BIT | Description
/// 0 | 0 | The mutex is not locked, nor is anyone waiting for it.
/// -----------+------------+------------------------------------------------------------------
/// 0 | 1 | The mutex is locked by exactly one thread. No other thread is
/// | | waiting for it.
/// -----------+------------+------------------------------------------------------------------
/// 1 | 0 | The mutex is not locked. One or more thread is parked or about to
/// | | park. At least one of the parked threads are just about to be
/// | | unparked, or a thread heading for parking might abort the park.
/// -----------+------------+------------------------------------------------------------------
/// 1 | 1 | The mutex is locked by exactly one thread. One or more thread is
/// | | parked or about to park, waiting for the lock to become available.
/// | | In this state, PARKED_BIT is only ever cleared when a bucket lock
/// | | is held (i.e. in a parking_lot_core callback). This ensures that
/// | | we never end up in a situation where there are parked threads but
/// | | PARKED_BIT is not set (which would result in those threads
/// | | potentially never getting woken up).
state: AtomicU8,
}
unsafe impl lock_api::RawMutex for RawMutex {
const INIT: RawMutex = RawMutex {
state: AtomicU8::new(0),
};
type GuardMarker = crate::GuardMarker;
#[inline]
fn lock(&self) {
if self
.state
.compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
self.lock_slow(None);
}
unsafe { deadlock::acquire_resource(self as *const _ as usize) };
}
#[inline]
fn try_lock(&self) -> bool {
let mut state = self.state.load(Ordering::Relaxed);
loop {
if state & LOCKED_BIT != 0 {
return false;
}
match self.state.compare_exchange_weak(
state,
state | LOCKED_BIT,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => {
unsafe { deadlock::acquire_resource(self as *const _ as usize) };
return true;
}
Err(x) => state = x,
}
}
}
#[inline]
unsafe fn unlock(&self) {
deadlock::release_resource(self as *const _ as usize);
if self
.state
.compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
.is_ok()
{
return;
}
self.unlock_slow(false);
}
#[inline]
fn is_locked(&self) -> bool {
let state = self.state.load(Ordering::Relaxed);
state & LOCKED_BIT != 0
}
}
unsafe impl lock_api::RawMutexFair for RawMutex {
#[inline]
unsafe fn unlock_fair(&self) {
deadlock::release_resource(self as *const _ as usize);
if self
.state
.compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
.is_ok()
{
return;
}
self.unlock_slow(true);
}
#[inline]
unsafe fn bump(&self) {
if self.state.load(Ordering::Relaxed) & PARKED_BIT != 0 {
self.bump_slow();
}
}
}
unsafe impl lock_api::RawMutexTimed for RawMutex {
type Duration = Duration;
type Instant = Instant;
#[inline]
fn try_lock_until(&self, timeout: Instant) -> bool {
let result = if self
.state
.compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
true
} else {
self.lock_slow(Some(timeout))
};
if result {
unsafe { deadlock::acquire_resource(self as *const _ as usize) };
}
result
}
#[inline]
fn try_lock_for(&self, timeout: Duration) -> bool {
let result = if self
.state
.compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
true
} else {
self.lock_slow(util::to_deadline(timeout))
};
if result {
unsafe { deadlock::acquire_resource(self as *const _ as usize) };
}
result
}
}
impl RawMutex {
// Used by Condvar when requeuing threads to us, must be called while
// holding the queue lock.
#[inline]
pub(crate) fn mark_parked_if_locked(&self) -> bool {
let mut state = self.state.load(Ordering::Relaxed);
loop {
if state & LOCKED_BIT == 0 {
return false;
}
match self.state.compare_exchange_weak(
state,
state | PARKED_BIT,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => return true,
Err(x) => state = x,
}
}
}
// Used by Condvar when requeuing threads to us, must be called while
// holding the queue lock.
#[inline]
pub(crate) fn mark_parked(&self) {
self.state.fetch_or(PARKED_BIT, Ordering::Relaxed);
}
#[cold]
fn lock_slow(&self, timeout: Option<Instant>) -> bool {
let mut spinwait = SpinWait::new();
let mut state = self.state.load(Ordering::Relaxed);
loop {
// Grab the lock if it isn't locked, even if there is a queue on it
if state & LOCKED_BIT == 0 {
match self.state.compare_exchange_weak(
state,
state | LOCKED_BIT,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => return true,
Err(x) => state = x,
}
continue;
}
// If there is no queue, try spinning a few times
if state & PARKED_BIT == 0 && spinwait.spin() {
state = self.state.load(Ordering::Relaxed);
continue;
}
// Set the parked bit
if state & PARKED_BIT == 0 {
if let Err(x) = self.state.compare_exchange_weak(
state,
state | PARKED_BIT,
Ordering::Relaxed,
Ordering::Relaxed,
) {
state = x;
continue;
}
}
// Park our thread until we are woken up by an unlock
let addr = self as *const _ as usize;
let validate = || self.state.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
let before_sleep = || {};
let timed_out = |_, was_last_thread| {
// Clear the parked bit if we were the last parked thread
if was_last_thread {
self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed);
}
};
// SAFETY:
// * `addr` is an address we control.
// * `validate`/`timed_out` does not panic or call into any function of `parking_lot`.
// * `before_sleep` does not call `park`, nor does it panic.
match unsafe {
parking_lot_core::park(
addr,
validate,
before_sleep,
timed_out,
DEFAULT_PARK_TOKEN,
timeout,
)
} {
// The thread that unparked us passed the lock on to us
// directly without unlocking it.
ParkResult::Unparked(TOKEN_HANDOFF) => return true,
// We were unparked normally, try acquiring the lock again
ParkResult::Unparked(_) => (),
// The validation function failed, try locking again
ParkResult::Invalid => (),
// Timeout expired
ParkResult::TimedOut => return false,
}
// Loop back and try locking again
spinwait.reset();
state = self.state.load(Ordering::Relaxed);
}
}
#[cold]
fn unlock_slow(&self, force_fair: bool) {
// Unpark one thread and leave the parked bit set if there might
// still be parked threads on this address.
let addr = self as *const _ as usize;
let callback = |result: UnparkResult| {
// If we are using a fair unlock then we should keep the
// mutex locked and hand it off to the unparked thread.
if result.unparked_threads != 0 && (force_fair || result.be_fair) {
// Clear the parked bit if there are no more parked
// threads.
if !result.have_more_threads {
self.state.store(LOCKED_BIT, Ordering::Relaxed);
}
return TOKEN_HANDOFF;
}
// Clear the locked bit, and the parked bit as well if there
// are no more parked threads.
if result.have_more_threads {
self.state.store(PARKED_BIT, Ordering::Release);
} else {
self.state.store(0, Ordering::Release);
}
TOKEN_NORMAL
};
// SAFETY:
// * `addr` is an address we control.
// * `callback` does not panic or call into any function of `parking_lot`.
unsafe {
parking_lot_core::unpark_one(addr, callback);
}
}
#[cold]
fn bump_slow(&self) {
unsafe { deadlock::release_resource(self as *const _ as usize) };
self.unlock_slow(true);
self.lock();
}
}

1157
vendor/parking_lot/src/raw_rwlock.rs vendored Normal file

File diff suppressed because it is too large Load Diff

171
vendor/parking_lot/src/remutex.rs vendored Normal file
View File

@@ -0,0 +1,171 @@
// 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 crate::raw_mutex::RawMutex;
use core::num::NonZeroUsize;
use lock_api::{self, GetThreadId};
/// Implementation of the `GetThreadId` trait for `lock_api::ReentrantMutex`.
pub struct RawThreadId;
unsafe impl GetThreadId for RawThreadId {
const INIT: RawThreadId = RawThreadId;
fn nonzero_thread_id(&self) -> NonZeroUsize {
// The address of a thread-local variable is guaranteed to be unique to the
// current thread, and is also guaranteed to be non-zero. The variable has to have a
// non-zero size to guarantee it has a unique address for each thread.
thread_local!(static KEY: u8 = 0);
KEY.with(|x| {
NonZeroUsize::new(x as *const _ as usize)
.expect("thread-local variable address is null")
})
}
}
/// 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`](crate::Mutex) for more details about the underlying mutex
/// primitive.
pub type ReentrantMutex<T> = lock_api::ReentrantMutex<RawMutex, RawThreadId, T>;
/// Creates a new reentrant mutex in an unlocked state ready for use.
///
/// This allows creating a reentrant mutex in a constant context on stable Rust.
pub const fn const_reentrant_mutex<T>(val: T) -> ReentrantMutex<T> {
ReentrantMutex::const_new(
<RawMutex as lock_api::RawMutex>::INIT,
<RawThreadId as lock_api::GetThreadId>::INIT,
val,
)
}
/// 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.
pub type ReentrantMutexGuard<'a, T> = lock_api::ReentrantMutexGuard<'a, RawMutex, RawThreadId, T>;
/// 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.
pub type MappedReentrantMutexGuard<'a, T> =
lock_api::MappedReentrantMutexGuard<'a, RawMutex, RawThreadId, T>;
#[cfg(test)]
mod tests {
use crate::ReentrantMutex;
use crate::ReentrantMutexGuard;
use std::cell::RefCell;
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::thread;
#[cfg(feature = "serde")]
use bincode::{deserialize, serialize};
#[test]
fn smoke() {
let m = ReentrantMutex::new(2);
{
let a = m.lock();
{
let b = m.lock();
{
let c = m.lock();
assert_eq!(*c, 2);
}
assert_eq!(*b, 2);
}
assert_eq!(*a, 2);
}
}
#[test]
fn is_mutex() {
let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
let m2 = m.clone();
let lock = m.lock();
let child = thread::spawn(move || {
let lock = m2.lock();
assert_eq!(*lock.borrow(), 4950);
});
for i in 0..100 {
let lock = m.lock();
*lock.borrow_mut() += i;
}
drop(lock);
child.join().unwrap();
}
#[test]
fn trylock_works() {
let m = Arc::new(ReentrantMutex::new(()));
let m2 = m.clone();
let _lock = m.try_lock();
let _lock2 = m.try_lock();
thread::spawn(move || {
let lock = m2.try_lock();
assert!(lock.is_none());
})
.join()
.unwrap();
let _lock3 = m.try_lock();
}
#[test]
fn test_reentrant_mutex_debug() {
let mutex = ReentrantMutex::new(vec![0u8, 10]);
assert_eq!(format!("{:?}", mutex), "ReentrantMutex { data: [0, 10] }");
}
#[test]
fn test_reentrant_mutex_bump() {
let mutex = Arc::new(ReentrantMutex::new(()));
let mutex2 = mutex.clone();
let mut guard = mutex.lock();
let (tx, rx) = channel();
thread::spawn(move || {
let _guard = mutex2.lock();
tx.send(()).unwrap();
});
// `bump()` repeatedly until the thread starts up and requests the lock
while rx.try_recv().is_err() {
ReentrantMutexGuard::bump(&mut guard);
}
}
#[cfg(feature = "serde")]
#[test]
fn test_serde() {
let contents: Vec<u8> = vec![0, 1, 2];
let mutex = ReentrantMutex::new(contents.clone());
let serialized = serialize(&mutex).unwrap();
let deserialized: ReentrantMutex<Vec<u8>> = deserialize(&serialized).unwrap();
assert_eq!(*(mutex.lock()), *(deserialized.lock()));
assert_eq!(contents, *(deserialized.lock()));
}
}

659
vendor/parking_lot/src/rwlock.rs vendored Normal file
View File

@@ -0,0 +1,659 @@
// 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 crate::raw_rwlock::RawRwLock;
/// 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).
///
/// This lock uses a task-fair locking policy which avoids both reader and
/// writer starvation. This means that readers trying to acquire the lock will
/// block even if the lock is unlocked when there are writers waiting to acquire
/// the lock. Because of this, attempts to recursively acquire a read lock
/// within a single thread may result in a deadlock.
///
/// 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.
///
/// # Fairness
///
/// A typical unfair lock can often end up in a situation where a single thread
/// quickly acquires and releases the same lock in succession, which can starve
/// other threads waiting to acquire the rwlock. While this improves throughput
/// because it doesn't force a context switch when a thread tries to re-acquire
/// a rwlock it has just released, this can starve other threads.
///
/// This rwlock uses [eventual fairness](https://trac.webkit.org/changeset/203350)
/// to ensure that the lock will be fair on average without sacrificing
/// throughput. This is done by forcing a fair unlock on average every 0.5ms,
/// which will force the lock to go to the next thread waiting for the rwlock.
///
/// Additionally, any critical section longer than 1ms will always use a fair
/// unlock, which has a negligible impact on throughput considering the length
/// of the critical section.
///
/// You can also force a fair unlock by calling `RwLockReadGuard::unlock_fair`
/// or `RwLockWriteGuard::unlock_fair` when unlocking a mutex instead of simply
/// dropping the guard.
///
/// # Differences from the standard library `RwLock`
///
/// - Supports atomically downgrading a write lock into a read lock.
/// - Task-fair locking policy instead of an unspecified platform default.
/// - No poisoning, the lock is released normally on panic.
/// - Only requires 1 word of space, whereas the standard library boxes the
/// `RwLock` due to platform limitations.
/// - Can be statically constructed.
/// - Does not require any drop glue when dropped.
/// - Inline fast path for the uncontended case.
/// - Efficient handling of micro-contention using adaptive spinning.
/// - Allows raw locking & unlocking without a guard.
/// - Supports eventual fairness so that the rwlock is fair on average.
/// - Optionally allows making the rwlock fair by calling
/// `RwLockReadGuard::unlock_fair` and `RwLockWriteGuard::unlock_fair`.
///
/// # Examples
///
/// ```
/// use parking_lot::RwLock;
///
/// let lock = RwLock::new(5);
///
/// // many reader locks can be held at once
/// {
/// let r1 = lock.read();
/// let r2 = lock.read();
/// assert_eq!(*r1, 5);
/// assert_eq!(*r2, 5);
/// } // read locks are dropped at this point
///
/// // only one write lock may be held, however
/// {
/// let mut w = lock.write();
/// *w += 1;
/// assert_eq!(*w, 6);
/// } // write lock is dropped here
/// ```
pub type RwLock<T> = lock_api::RwLock<RawRwLock, T>;
/// Creates a new instance of an `RwLock<T>` which is unlocked.
///
/// This allows creating a `RwLock<T>` in a constant context on stable Rust.
pub const fn const_rwlock<T>(val: T) -> RwLock<T> {
RwLock::const_new(<RawRwLock as lock_api::RawRwLock>::INIT, val)
}
/// RAII structure used to release the shared read access of a lock when
/// dropped.
pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>;
/// RAII structure used to release the exclusive write access of a lock when
/// dropped.
pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>;
/// 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.
pub type MappedRwLockReadGuard<'a, T> = lock_api::MappedRwLockReadGuard<'a, RawRwLock, 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.
pub type MappedRwLockWriteGuard<'a, T> = lock_api::MappedRwLockWriteGuard<'a, RawRwLock, T>;
/// RAII structure used to release the upgradable read access of a lock when
/// dropped.
pub type RwLockUpgradableReadGuard<'a, T> = lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>;
#[cfg(test)]
mod tests {
use crate::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard};
use rand::Rng;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
#[cfg(feature = "serde")]
use bincode::{deserialize, serialize};
#[derive(Eq, PartialEq, Debug)]
struct NonCopy(i32);
#[test]
fn smoke() {
let l = RwLock::new(());
drop(l.read());
drop(l.write());
drop(l.upgradable_read());
drop((l.read(), l.read()));
drop((l.read(), l.upgradable_read()));
drop(l.write());
}
#[test]
fn frob() {
const N: u32 = 10;
const M: u32 = 1000;
let r = Arc::new(RwLock::new(()));
let (tx, rx) = channel::<()>();
for _ in 0..N {
let tx = tx.clone();
let r = r.clone();
thread::spawn(move || {
let mut rng = rand::thread_rng();
for _ in 0..M {
if rng.gen_bool(1.0 / N as f64) {
drop(r.write());
} else {
drop(r.read());
}
}
drop(tx);
});
}
drop(tx);
let _ = rx.recv();
}
#[test]
fn test_rw_arc_no_poison_wr() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.write();
panic!();
})
.join();
let lock = arc.read();
assert_eq!(*lock, 1);
}
#[test]
fn test_rw_arc_no_poison_ww() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.write();
panic!();
})
.join();
let lock = arc.write();
assert_eq!(*lock, 1);
}
#[test]
fn test_rw_arc_no_poison_rr() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.read();
panic!();
})
.join();
let lock = arc.read();
assert_eq!(*lock, 1);
}
#[test]
fn test_rw_arc_no_poison_rw() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _: Result<(), _> = thread::spawn(move || {
let _lock = arc2.read();
panic!()
})
.join();
let lock = arc.write();
assert_eq!(*lock, 1);
}
#[test]
fn test_ruw_arc() {
let arc = Arc::new(RwLock::new(0));
let arc2 = arc.clone();
let (tx, rx) = channel();
thread::spawn(move || {
for _ in 0..10 {
let mut lock = arc2.write();
let tmp = *lock;
*lock = -1;
thread::yield_now();
*lock = tmp + 1;
}
tx.send(()).unwrap();
});
let mut children = Vec::new();
// Upgradable readers try to catch the writer in the act and also
// try to touch the value
for _ in 0..5 {
let arc3 = arc.clone();
children.push(thread::spawn(move || {
let lock = arc3.upgradable_read();
let tmp = *lock;
assert!(tmp >= 0);
thread::yield_now();
let mut lock = RwLockUpgradableReadGuard::upgrade(lock);
assert_eq!(tmp, *lock);
*lock = -1;
thread::yield_now();
*lock = tmp + 1;
}));
}
// Readers try to catch the writers in the act
for _ in 0..5 {
let arc4 = arc.clone();
children.push(thread::spawn(move || {
let lock = arc4.read();
assert!(*lock >= 0);
}));
}
// Wait for children to pass their asserts
for r in children {
assert!(r.join().is_ok());
}
// Wait for writer to finish
rx.recv().unwrap();
let lock = arc.read();
assert_eq!(*lock, 15);
}
#[test]
fn test_rw_arc() {
let arc = Arc::new(RwLock::new(0));
let arc2 = arc.clone();
let (tx, rx) = channel();
thread::spawn(move || {
let mut lock = arc2.write();
for _ in 0..10 {
let tmp = *lock;
*lock = -1;
thread::yield_now();
*lock = tmp + 1;
}
tx.send(()).unwrap();
});
// Readers try to catch the writer in the act
let mut children = Vec::new();
for _ in 0..5 {
let arc3 = arc.clone();
children.push(thread::spawn(move || {
let lock = arc3.read();
assert!(*lock >= 0);
}));
}
// Wait for children to pass their asserts
for r in children {
assert!(r.join().is_ok());
}
// Wait for writer to finish
rx.recv().unwrap();
let lock = arc.read();
assert_eq!(*lock, 10);
}
#[test]
fn test_rw_arc_access_in_unwind() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let _ = thread::spawn(move || {
struct Unwinder {
i: Arc<RwLock<isize>>,
}
impl Drop for Unwinder {
fn drop(&mut self) {
let mut lock = self.i.write();
*lock += 1;
}
}
let _u = Unwinder { i: arc2 };
panic!();
})
.join();
let lock = arc.read();
assert_eq!(*lock, 2);
}
#[test]
fn test_rwlock_unsized() {
let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
{
let b = &mut *rw.write();
b[0] = 4;
b[2] = 5;
}
let comp: &[i32] = &[4, 2, 5];
assert_eq!(&*rw.read(), comp);
}
#[test]
fn test_rwlock_try_read() {
let lock = RwLock::new(0isize);
{
let read_guard = lock.read();
let read_result = lock.try_read();
assert!(
read_result.is_some(),
"try_read should succeed while read_guard is in scope"
);
drop(read_guard);
}
{
let upgrade_guard = lock.upgradable_read();
let read_result = lock.try_read();
assert!(
read_result.is_some(),
"try_read should succeed while upgrade_guard is in scope"
);
drop(upgrade_guard);
}
{
let write_guard = lock.write();
let read_result = lock.try_read();
assert!(
read_result.is_none(),
"try_read should fail while write_guard is in scope"
);
drop(write_guard);
}
}
#[test]
fn test_rwlock_try_write() {
let lock = RwLock::new(0isize);
{
let read_guard = lock.read();
let write_result = lock.try_write();
assert!(
write_result.is_none(),
"try_write should fail while read_guard is in scope"
);
assert!(lock.is_locked());
assert!(!lock.is_locked_exclusive());
drop(read_guard);
}
{
let upgrade_guard = lock.upgradable_read();
let write_result = lock.try_write();
assert!(
write_result.is_none(),
"try_write should fail while upgrade_guard is in scope"
);
assert!(lock.is_locked());
assert!(!lock.is_locked_exclusive());
drop(upgrade_guard);
}
{
let write_guard = lock.write();
let write_result = lock.try_write();
assert!(
write_result.is_none(),
"try_write should fail while write_guard is in scope"
);
assert!(lock.is_locked());
assert!(lock.is_locked_exclusive());
drop(write_guard);
}
}
#[test]
fn test_rwlock_try_upgrade() {
let lock = RwLock::new(0isize);
{
let read_guard = lock.read();
let upgrade_result = lock.try_upgradable_read();
assert!(
upgrade_result.is_some(),
"try_upgradable_read should succeed while read_guard is in scope"
);
drop(read_guard);
}
{
let upgrade_guard = lock.upgradable_read();
let upgrade_result = lock.try_upgradable_read();
assert!(
upgrade_result.is_none(),
"try_upgradable_read should fail while upgrade_guard is in scope"
);
drop(upgrade_guard);
}
{
let write_guard = lock.write();
let upgrade_result = lock.try_upgradable_read();
assert!(
upgrade_result.is_none(),
"try_upgradable should fail while write_guard is in scope"
);
drop(write_guard);
}
}
#[test]
fn test_into_inner() {
let m = RwLock::new(NonCopy(10));
assert_eq!(m.into_inner(), NonCopy(10));
}
#[test]
fn test_into_inner_drop() {
struct Foo(Arc<AtomicUsize>);
impl Drop for Foo {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
let num_drops = Arc::new(AtomicUsize::new(0));
let m = RwLock::new(Foo(num_drops.clone()));
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
{
let _inner = m.into_inner();
assert_eq!(num_drops.load(Ordering::SeqCst), 0);
}
assert_eq!(num_drops.load(Ordering::SeqCst), 1);
}
#[test]
fn test_get_mut() {
let mut m = RwLock::new(NonCopy(10));
*m.get_mut() = NonCopy(20);
assert_eq!(m.into_inner(), NonCopy(20));
}
#[test]
fn test_rwlockguard_sync() {
fn sync<T: Sync>(_: T) {}
let rwlock = RwLock::new(());
sync(rwlock.read());
sync(rwlock.write());
}
#[test]
fn test_rwlock_downgrade() {
let x = Arc::new(RwLock::new(0));
let mut handles = Vec::new();
for _ in 0..8 {
let x = x.clone();
handles.push(thread::spawn(move || {
for _ in 0..100 {
let mut writer = x.write();
*writer += 1;
let cur_val = *writer;
let reader = RwLockWriteGuard::downgrade(writer);
assert_eq!(cur_val, *reader);
}
}));
}
for handle in handles {
handle.join().unwrap()
}
assert_eq!(*x.read(), 800);
}
#[test]
fn test_rwlock_recursive() {
let arc = Arc::new(RwLock::new(1));
let arc2 = arc.clone();
let lock1 = arc.read();
let t = thread::spawn(move || {
let _lock = arc2.write();
});
if cfg!(not(all(target_env = "sgx", target_vendor = "fortanix"))) {
thread::sleep(Duration::from_millis(100));
} else {
// FIXME: https://github.com/fortanix/rust-sgx/issues/31
for _ in 0..100 {
thread::yield_now();
}
}
// A normal read would block here since there is a pending writer
let lock2 = arc.read_recursive();
// Unblock the thread and join it.
drop(lock1);
drop(lock2);
t.join().unwrap();
}
#[test]
fn test_rwlock_debug() {
let x = RwLock::new(vec![0u8, 10]);
assert_eq!(format!("{:?}", x), "RwLock { data: [0, 10] }");
let _lock = x.write();
assert_eq!(format!("{:?}", x), "RwLock { data: <locked> }");
}
#[test]
fn test_clone() {
let rwlock = RwLock::new(Arc::new(1));
let a = rwlock.read_recursive();
let b = a.clone();
assert_eq!(Arc::strong_count(&b), 2);
}
#[cfg(feature = "serde")]
#[test]
fn test_serde() {
let contents: Vec<u8> = vec![0, 1, 2];
let mutex = RwLock::new(contents.clone());
let serialized = serialize(&mutex).unwrap();
let deserialized: RwLock<Vec<u8>> = deserialize(&serialized).unwrap();
assert_eq!(*(mutex.read()), *(deserialized.read()));
assert_eq!(contents, *(deserialized.read()));
}
#[test]
fn test_issue_203() {
struct Bar(RwLock<()>);
impl Drop for Bar {
fn drop(&mut self) {
let _n = self.0.write();
}
}
thread_local! {
static B: Bar = Bar(RwLock::new(()));
}
thread::spawn(|| {
B.with(|_| ());
let a = RwLock::new(());
let _a = a.read();
})
.join()
.unwrap();
}
#[test]
fn test_rw_write_is_locked() {
let lock = RwLock::new(0isize);
{
let _read_guard = lock.read();
assert!(lock.is_locked());
assert!(!lock.is_locked_exclusive());
}
{
let _write_guard = lock.write();
assert!(lock.is_locked());
assert!(lock.is_locked_exclusive());
}
}
#[test]
#[cfg(feature = "arc_lock")]
fn test_issue_430() {
let lock = std::sync::Arc::new(RwLock::new(0));
let mut rl = lock.upgradable_read_arc();
rl.with_upgraded(|_| {
println!("lock upgrade");
});
rl.with_upgraded(|_| {
println!("lock upgrade");
});
drop(lock);
}
}

38
vendor/parking_lot/src/util.rs vendored Normal file
View File

@@ -0,0 +1,38 @@
// 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 std::time::{Duration, Instant};
// Option::unchecked_unwrap
pub trait UncheckedOptionExt<T> {
unsafe fn unchecked_unwrap(self) -> T;
}
impl<T> UncheckedOptionExt<T> for Option<T> {
#[inline]
unsafe fn unchecked_unwrap(self) -> T {
match self {
Some(x) => x,
None => unreachable(),
}
}
}
// hint::unreachable_unchecked() in release mode
#[inline]
unsafe fn unreachable() -> ! {
if cfg!(debug_assertions) {
unreachable!();
} else {
core::hint::unreachable_unchecked()
}
}
#[inline]
pub fn to_deadline(timeout: Duration) -> Option<Instant> {
Instant::now().checked_add(timeout)
}

26
vendor/parking_lot/tests/issue_203.rs vendored Normal file
View File

@@ -0,0 +1,26 @@
use parking_lot::RwLock;
use std::thread;
struct Bar(RwLock<()>);
impl Drop for Bar {
fn drop(&mut self) {
let _n = self.0.write();
}
}
thread_local! {
static B: Bar = Bar(RwLock::new(()));
}
#[test]
fn main() {
thread::spawn(|| {
B.with(|_| ());
let a = RwLock::new(());
let _a = a.read();
})
.join()
.unwrap();
}

15
vendor/parking_lot/tests/issue_392.rs vendored Normal file
View File

@@ -0,0 +1,15 @@
use parking_lot::RwLock;
struct Lock(RwLock<i32>);
#[test]
fn issue_392() {
let lock = Lock(RwLock::new(0));
let mut rl = lock.0.upgradable_read();
rl.with_upgraded(|_| {
println!("lock upgrade");
});
rl.with_upgraded(|_| {
println!("lock upgrade");
});
}