├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── src ├── barrier.rs ├── lib.rs ├── mutex.rs ├── once_cell.rs ├── rwlock.rs ├── rwlock │ ├── futures.rs │ └── raw.rs └── semaphore.rs └── tests ├── barrier.rs ├── common └── mod.rs ├── loom.rs ├── mutex.rs ├── rwlock.rs └── semaphore.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | commit-message: 8 | prefix: '' 9 | labels: [] 10 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | pull_request: 8 | push: 9 | branches: 10 | - master 11 | schedule: 12 | - cron: '0 2 * * 0' 13 | 14 | env: 15 | CARGO_INCREMENTAL: 0 16 | CARGO_NET_GIT_FETCH_WITH_CLI: true 17 | CARGO_NET_RETRY: 10 18 | CARGO_TERM_COLOR: always 19 | RUST_BACKTRACE: 1 20 | RUSTFLAGS: -D warnings 21 | RUSTDOCFLAGS: -D warnings 22 | RUSTUP_MAX_RETRIES: 10 23 | 24 | defaults: 25 | run: 26 | shell: bash 27 | 28 | jobs: 29 | fmt: 30 | uses: smol-rs/.github/.github/workflows/fmt.yml@main 31 | security_audit: 32 | uses: smol-rs/.github/.github/workflows/security_audit.yml@main 33 | permissions: 34 | checks: write 35 | contents: read 36 | issues: write 37 | secrets: inherit 38 | 39 | test: 40 | runs-on: ${{ matrix.os }} 41 | strategy: 42 | fail-fast: false 43 | matrix: 44 | os: [ubuntu-latest] 45 | rust: [nightly, beta, stable] 46 | steps: 47 | - uses: actions/checkout@v4 48 | - name: Install Rust 49 | run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} 50 | - run: rustup target add wasm32-unknown-unknown 51 | - name: Install WASM Test Tools and Cargo Hack 52 | uses: taiki-e/install-action@v2 53 | with: 54 | tool: cargo-hack,wasm-pack 55 | - name: Run cargo check 56 | run: cargo check --all --all-features --all-targets 57 | - run: cargo check --all --no-default-features 58 | - name: Run cargo check (without dev-dependencies to catch missing feature flags) 59 | if: startsWith(matrix.rust, 'nightly') 60 | run: cargo check -Z features=dev_dep 61 | - run: rustup target add thumbv7m-none-eabi 62 | - run: cargo hack build --all --target thumbv7m-none-eabi --no-default-features --no-dev-deps 63 | - name: Run cargo check for WASM 64 | run: cargo check --all --all-features --all-targets --target wasm32-unknown-unknown 65 | - name: Test WASM 66 | run: wasm-pack test --headless --chrome 67 | - run: cargo test --all 68 | 69 | msrv: 70 | runs-on: ubuntu-latest 71 | strategy: 72 | matrix: 73 | # When updating this, the reminder to update the minimum supported 74 | # Rust version in Cargo.toml. 75 | rust: ['1.61'] 76 | steps: 77 | - uses: actions/checkout@v4 78 | - name: Install cargo-hack 79 | uses: taiki-e/install-action@cargo-hack 80 | - run: cargo hack build --rust-version 81 | - run: cargo hack build --no-default-features --rust-version 82 | 83 | clippy: 84 | runs-on: ubuntu-latest 85 | steps: 86 | - uses: actions/checkout@v4 87 | - name: Install Rust 88 | run: rustup update stable 89 | - run: cargo clippy --all-features --all-targets 90 | 91 | loom: 92 | runs-on: ubuntu-latest 93 | steps: 94 | - uses: actions/checkout@v4 95 | - name: Install Rust 96 | run: rustup update stable 97 | - name: Loom tests 98 | run: cargo test --release --test loom --features loom 99 | env: 100 | RUSTFLAGS: "--cfg=loom" 101 | LOOM_MAX_PREEMPTIONS: 4 102 | 103 | miri: 104 | runs-on: ubuntu-latest 105 | steps: 106 | - uses: actions/checkout@v4 107 | - name: Install Rust 108 | run: rustup toolchain install nightly --component miri && rustup default nightly 109 | - run: cargo miri test 110 | env: 111 | # -Zmiri-ignore-leaks is needed because we use detached threads in doctests 112 | MIRIFLAGS: -Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-ignore-leaks 113 | RUSTFLAGS: ${{ env.RUSTFLAGS }} -Z randomize-layout 114 | 115 | doc: 116 | runs-on: ubuntu-latest 117 | steps: 118 | - uses: actions/checkout@v4 119 | - name: Install Rust 120 | run: rustup update stable 121 | - run: cargo doc --all --all-features 122 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | push: 8 | tags: 9 | - v[0-9]+.* 10 | 11 | jobs: 12 | create-release: 13 | if: github.repository_owner == 'smol-rs' 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: taiki-e/create-gh-release-action@v1 18 | with: 19 | changelog: CHANGELOG.md 20 | branch: master 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Version 3.4.0 2 | 3 | - Port to `event-listener` v5.0.0. (#74) 4 | 5 | # Version 3.3.0 6 | 7 | - Add a `forget()` method for semaphore guards. (#73) 8 | - Increase MSRV to v1.60. (#75) 9 | 10 | # Version 3.2.0 11 | 12 | - Add missing methods for blocking on locking with types wrapped in `Arc` (#71). 13 | 14 | # Version 3.1.2 15 | 16 | - Bump `event-listener` to version v4.0.0. (#69) 17 | 18 | # Version 3.1.1 19 | 20 | - Add a note to the documentation comparing this crate against `libstd`'s locks. (#58) 21 | 22 | # Version 3.1.0 23 | 24 | - Add a `Default` implementation for `OnceCell` (#63). 25 | 26 | # Version 3.0.0 27 | 28 | - **Breaking:** Add an enabled-by-default `std` feature that allows using this crate without the standard library. (#43) 29 | - Support blocking and non-blocking operations on the same locks. (#56) 30 | - Switch to a more efficient event notification mechanism. (#43) 31 | 32 | # Version 2.8.0 33 | 34 | - Fix a bug where the `SemaphoreGuard::acquire_arc` future would busy wait under certain conditions (#42). 35 | - Add a `Semaphore::add_permits()` function to increase the number of available permits on the semaphore (#44). 36 | - Make `RwLockReadGuard` covariant over its lifetime (#45) 37 | - Add `RwLockReadGuardArc`, `RwLockWriteGuardArc`, and other reference counted guards for the `RwLock` type (#47). 38 | - Loosen the `Send`/`Sync` bounds on certain future types (#48). 39 | - Fix UB caused by the `MutexGuardArc::source` function allowing the user to drop an object in a different thread than the one it was acquired in (#50). This is a breaking change, but in the name of soundness. Therefore it doesn't break any valid behavior. 40 | - Fix a bug where this crate would not compile properly on `wasm64` (#51). 41 | 42 | # Version 2.7.0 43 | 44 | - Replace some `async` blocks with manual futures (#34) 45 | - Remove our dependency on `futures-lite` (#36) 46 | - Mark guard types with `#[clippy::has_significant_drop]` (#37) 47 | 48 | # Version 2.6.0 49 | 50 | - Add `OnceCell`. (#27) 51 | - Support wasm64. 52 | 53 | # Version 2.5.0 54 | 55 | - Fix an issue where the future returned by `Mutex::lock_arc`/`Semaphore::acquire_arc` holds a reference to `self`. (#20, #21) 56 | 57 | # Version 2.4.0 58 | 59 | - Add WASM support. (#14) 60 | 61 | # Version 2.3.0 62 | 63 | - Merge all subcrates. 64 | 65 | # Version 2.2.0 66 | 67 | - Add functions to upgrade and downgrade `RwLock` guards. 68 | - Make all constructors `const fn`. 69 | 70 | # Version 2.1.3 71 | 72 | - Add `#![forbid(unsafe_code)]`. 73 | 74 | # Version 2.1.2 75 | 76 | - Update dependencies. 77 | 78 | # Version 2.1.1 79 | 80 | - Update crate description. 81 | 82 | # Version 2.1.0 83 | 84 | - Add `Barrier` and `Semaphore`. 85 | 86 | # Version 2.0.1 87 | 88 | - Update crate description. 89 | 90 | # Version 2.0.0 91 | 92 | - Only re-export `async-mutex` and `async-rwlock`. 93 | 94 | # Version 1.1.5 95 | 96 | - Replace the implementation with `async-mutex`. 97 | 98 | # Version 1.1.4 99 | 100 | - Replace `usize::MAX` with `std::usize::MAX`. 101 | 102 | # Version 1.1.3 103 | 104 | - Update dependencies. 105 | 106 | # Version 1.1.2 107 | 108 | - Fix a deadlock issue. 109 | 110 | # Version 1.1.1 111 | 112 | - Fix some typos. 113 | 114 | # Version 1.1.0 115 | 116 | - Make locking fair. 117 | - Add `LockGuard::source()`. 118 | 119 | # Version 1.0.2 120 | 121 | - Bump the `event-listener` version. 122 | - Add tests. 123 | 124 | # Version 1.0.1 125 | 126 | - Update Cargo categories. 127 | 128 | # Version 1.0.0 129 | 130 | - Initial version 131 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "async-lock" 3 | # When publishing a new version: 4 | # - Update CHANGELOG.md 5 | # - Create "v3.x.y" git tag 6 | version = "3.4.0" 7 | authors = ["Stjepan Glavina "] 8 | edition = "2021" 9 | rust-version = "1.60" 10 | description = "Async synchronization primitives" 11 | license = "Apache-2.0 OR MIT" 12 | repository = "https://github.com/smol-rs/async-lock" 13 | keywords = ["lock", "mutex", "rwlock", "semaphore", "barrier"] 14 | categories = ["asynchronous", "concurrency"] 15 | exclude = ["/.*"] 16 | 17 | [dependencies] 18 | event-listener = { version = "5.0.0", default-features = false } 19 | event-listener-strategy = { version = "0.5.0", default-features = false } 20 | pin-project-lite = "0.2.11" 21 | 22 | [target.'cfg(loom)'.dependencies] 23 | loom = { version = "0.7", optional = true } 24 | 25 | [features] 26 | default = ["std"] 27 | std = ["event-listener/std", "event-listener-strategy/std"] 28 | loom = ["event-listener/loom", "dep:loom"] 29 | 30 | [lints.rust] 31 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(loom)'] } 32 | 33 | [dev-dependencies] 34 | fastrand = "2.0.0" 35 | flume = "0.11.0" 36 | futures-lite = "2.0.0" 37 | waker-fn = "1.1.0" 38 | 39 | [target.'cfg(target_family = "wasm")'.dev-dependencies] 40 | wasm-bindgen-test = "0.3" 41 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # async-lock 2 | 3 | [![Build](https://github.com/smol-rs/async-lock/workflows/Build%20and%20test/badge.svg)]( 4 | https://github.com/smol-rs/async-lock/actions) 5 | [![License](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue.svg)]( 6 | https://github.com/smol-rs/async-lock) 7 | [![Cargo](https://img.shields.io/crates/v/async-lock.svg)]( 8 | https://crates.io/crates/async-lock) 9 | [![Documentation](https://docs.rs/async-lock/badge.svg)]( 10 | https://docs.rs/async-lock) 11 | 12 | Async synchronization primitives. 13 | 14 | This crate provides the following primitives: 15 | 16 | * `Barrier` - enables tasks to synchronize all together at the same time. 17 | * `Mutex` - a mutual exclusion lock. 18 | * `RwLock` - a reader-writer lock, allowing any number of readers or a single writer. 19 | * `Semaphore` - limits the number of concurrent operations. 20 | 21 | ## License 22 | 23 | Licensed under either of 24 | 25 | * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 26 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 27 | 28 | at your option. 29 | 30 | #### Contribution 31 | 32 | Unless you explicitly state otherwise, any contribution intentionally submitted 33 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 34 | dual licensed as above, without any additional terms or conditions. 35 | -------------------------------------------------------------------------------- /src/barrier.rs: -------------------------------------------------------------------------------- 1 | use event_listener::{Event, EventListener}; 2 | use event_listener_strategy::{easy_wrapper, EventListenerFuture, Strategy}; 3 | 4 | use core::fmt; 5 | use core::pin::Pin; 6 | use core::task::Poll; 7 | 8 | use crate::futures::Lock; 9 | use crate::Mutex; 10 | 11 | /// A counter to synchronize multiple tasks at the same time. 12 | #[derive(Debug)] 13 | pub struct Barrier { 14 | n: usize, 15 | state: Mutex, 16 | event: Event, 17 | } 18 | 19 | #[derive(Debug)] 20 | struct State { 21 | count: usize, 22 | generation_id: u64, 23 | } 24 | 25 | impl Barrier { 26 | const_fn! { 27 | const_if: #[cfg(not(loom))]; 28 | /// Creates a barrier that can block the given number of tasks. 29 | /// 30 | /// A barrier will block `n`-1 tasks which call [`wait()`] and then wake up all tasks 31 | /// at once when the `n`th task calls [`wait()`]. 32 | /// 33 | /// [`wait()`]: `Barrier::wait()` 34 | /// 35 | /// # Examples 36 | /// 37 | /// ``` 38 | /// use async_lock::Barrier; 39 | /// 40 | /// let barrier = Barrier::new(5); 41 | /// ``` 42 | pub const fn new(n: usize) -> Barrier { 43 | Barrier { 44 | n, 45 | state: Mutex::new(State { 46 | count: 0, 47 | generation_id: 0, 48 | }), 49 | event: Event::new(), 50 | } 51 | } 52 | } 53 | 54 | /// Blocks the current task until all tasks reach this point. 55 | /// 56 | /// Barriers are reusable after all tasks have synchronized, and can be used continuously. 57 | /// 58 | /// Returns a [`BarrierWaitResult`] indicating whether this task is the "leader", meaning the 59 | /// last task to call this method. 60 | /// 61 | /// # Examples 62 | /// 63 | /// ``` 64 | /// use async_lock::Barrier; 65 | /// use futures_lite::future; 66 | /// use std::sync::Arc; 67 | /// use std::thread; 68 | /// 69 | /// let barrier = Arc::new(Barrier::new(5)); 70 | /// 71 | /// for _ in 0..5 { 72 | /// let b = barrier.clone(); 73 | /// thread::spawn(move || { 74 | /// future::block_on(async { 75 | /// // The same messages will be printed together. 76 | /// // There will NOT be interleaving of "before" and "after". 77 | /// println!("before wait"); 78 | /// b.wait().await; 79 | /// println!("after wait"); 80 | /// }); 81 | /// }); 82 | /// } 83 | /// ``` 84 | pub fn wait(&self) -> BarrierWait<'_> { 85 | BarrierWait::_new(BarrierWaitInner { 86 | barrier: self, 87 | lock: Some(self.state.lock()), 88 | evl: None, 89 | state: WaitState::Initial, 90 | }) 91 | } 92 | 93 | /// Blocks the current thread until all tasks reach this point. 94 | /// 95 | /// Barriers are reusable after all tasks have synchronized, and can be used continuously. 96 | /// 97 | /// Returns a [`BarrierWaitResult`] indicating whether this task is the "leader", meaning the 98 | /// last task to call this method. 99 | /// 100 | /// # Blocking 101 | /// 102 | /// Rather than using asynchronous waiting, like the [`wait`][`Barrier::wait`] method, 103 | /// this method will block the current thread until the wait is complete. 104 | /// 105 | /// This method should not be used in an asynchronous context. It is intended to be 106 | /// used in a way that a barrier can be used in both asynchronous and synchronous contexts. 107 | /// Calling this method in an asynchronous context may result in a deadlock. 108 | /// 109 | /// # Examples 110 | /// 111 | /// ``` 112 | /// use async_lock::Barrier; 113 | /// use futures_lite::future; 114 | /// use std::sync::Arc; 115 | /// use std::thread; 116 | /// 117 | /// let barrier = Arc::new(Barrier::new(5)); 118 | /// 119 | /// for _ in 0..5 { 120 | /// let b = barrier.clone(); 121 | /// thread::spawn(move || { 122 | /// // The same messages will be printed together. 123 | /// // There will NOT be interleaving of "before" and "after". 124 | /// println!("before wait"); 125 | /// b.wait_blocking(); 126 | /// println!("after wait"); 127 | /// }); 128 | /// } 129 | /// # // Wait for threads to stop. 130 | /// # std::thread::sleep(std::time::Duration::from_secs(1)); 131 | /// ``` 132 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 133 | pub fn wait_blocking(&self) -> BarrierWaitResult { 134 | self.wait().wait() 135 | } 136 | } 137 | 138 | easy_wrapper! { 139 | /// The future returned by [`Barrier::wait()`]. 140 | pub struct BarrierWait<'a>(BarrierWaitInner<'a> => BarrierWaitResult); 141 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 142 | pub(crate) wait(); 143 | } 144 | 145 | pin_project_lite::pin_project! { 146 | /// The future returned by [`Barrier::wait()`]. 147 | struct BarrierWaitInner<'a> { 148 | // The barrier to wait on. 149 | barrier: &'a Barrier, 150 | 151 | // The ongoing mutex lock operation we are blocking on. 152 | #[pin] 153 | lock: Option>, 154 | 155 | // An event listener for the `barrier.event` event. 156 | evl: Option, 157 | 158 | // The current state of the future. 159 | state: WaitState, 160 | } 161 | } 162 | 163 | impl fmt::Debug for BarrierWait<'_> { 164 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 165 | f.write_str("BarrierWait { .. }") 166 | } 167 | } 168 | 169 | enum WaitState { 170 | /// We are getting the original values of the state. 171 | Initial, 172 | 173 | /// We are waiting for the listener to complete. 174 | Waiting { local_gen: u64 }, 175 | 176 | /// Waiting to re-acquire the lock to check the state again. 177 | Reacquiring { local_gen: u64 }, 178 | } 179 | 180 | impl EventListenerFuture for BarrierWaitInner<'_> { 181 | type Output = BarrierWaitResult; 182 | 183 | fn poll_with_strategy<'a, S: Strategy<'a>>( 184 | self: Pin<&mut Self>, 185 | strategy: &mut S, 186 | cx: &mut S::Context, 187 | ) -> Poll { 188 | let mut this = self.project(); 189 | 190 | loop { 191 | match this.state { 192 | WaitState::Initial => { 193 | // See if the lock is ready yet. 194 | let mut state = ready!(this 195 | .lock 196 | .as_mut() 197 | .as_pin_mut() 198 | .unwrap() 199 | .poll_with_strategy(strategy, cx)); 200 | this.lock.as_mut().set(None); 201 | 202 | let local_gen = state.generation_id; 203 | state.count += 1; 204 | 205 | if state.count < this.barrier.n { 206 | // We need to wait for the event. 207 | *this.evl = Some(this.barrier.event.listen()); 208 | *this.state = WaitState::Waiting { local_gen }; 209 | } else { 210 | // We are the last one. 211 | state.count = 0; 212 | state.generation_id = state.generation_id.wrapping_add(1); 213 | this.barrier.event.notify(usize::MAX); 214 | return Poll::Ready(BarrierWaitResult { is_leader: true }); 215 | } 216 | } 217 | 218 | WaitState::Waiting { local_gen } => { 219 | ready!(strategy.poll(this.evl, cx)); 220 | 221 | // We are now re-acquiring the mutex. 222 | this.lock.as_mut().set(Some(this.barrier.state.lock())); 223 | *this.state = WaitState::Reacquiring { 224 | local_gen: *local_gen, 225 | }; 226 | } 227 | 228 | WaitState::Reacquiring { local_gen } => { 229 | // Acquire the local state again. 230 | let state = ready!(this 231 | .lock 232 | .as_mut() 233 | .as_pin_mut() 234 | .unwrap() 235 | .poll_with_strategy(strategy, cx)); 236 | this.lock.set(None); 237 | 238 | if *local_gen == state.generation_id && state.count < this.barrier.n { 239 | // We need to wait for the event again. 240 | *this.evl = Some(this.barrier.event.listen()); 241 | *this.state = WaitState::Waiting { 242 | local_gen: *local_gen, 243 | }; 244 | } else { 245 | // We are ready, but not the leader. 246 | return Poll::Ready(BarrierWaitResult { is_leader: false }); 247 | } 248 | } 249 | } 250 | } 251 | } 252 | } 253 | 254 | /// Returned by [`Barrier::wait()`] when all tasks have called it. 255 | /// 256 | /// # Examples 257 | /// 258 | /// ``` 259 | /// # futures_lite::future::block_on(async { 260 | /// use async_lock::Barrier; 261 | /// 262 | /// let barrier = Barrier::new(1); 263 | /// let barrier_wait_result = barrier.wait().await; 264 | /// # }); 265 | /// ``` 266 | #[derive(Debug, Clone)] 267 | pub struct BarrierWaitResult { 268 | is_leader: bool, 269 | } 270 | 271 | impl BarrierWaitResult { 272 | /// Returns `true` if this task was the last to call to [`Barrier::wait()`]. 273 | /// 274 | /// # Examples 275 | /// 276 | /// ``` 277 | /// # futures_lite::future::block_on(async { 278 | /// use async_lock::Barrier; 279 | /// use futures_lite::future; 280 | /// 281 | /// let barrier = Barrier::new(2); 282 | /// let (a, b) = future::zip(barrier.wait(), barrier.wait()).await; 283 | /// assert_eq!(a.is_leader(), false); 284 | /// assert_eq!(b.is_leader(), true); 285 | /// # }); 286 | /// ``` 287 | pub fn is_leader(&self) -> bool { 288 | self.is_leader 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Async synchronization primitives. 2 | //! 3 | //! This crate provides the following primitives: 4 | //! 5 | //! * [`Barrier`] - enables tasks to synchronize all together at the same time. 6 | //! * [`Mutex`] - a mutual exclusion lock. 7 | //! * [`RwLock`] - a reader-writer lock, allowing any number of readers or a single writer. 8 | //! * [`Semaphore`] - limits the number of concurrent operations. 9 | //! 10 | //! ## Relationship with `std::sync` 11 | //! 12 | //! In general, you should consider using [`std::sync`] types over types from this crate. 13 | //! 14 | //! There are two primary use cases for types from this crate: 15 | //! 16 | //! - You need to use a synchronization primitive in a `no_std` environment. 17 | //! - You need to hold a lock across an `.await` point. 18 | //! (Holding an [`std::sync`] lock guard across an `.await` will make your future non-`Send`, 19 | //! and is also highly likely to cause deadlocks.) 20 | //! 21 | //! If you already use `libstd` and you aren't holding locks across await points (there is a 22 | //! Clippy lint called [`await_holding_lock`] that emits warnings for this scenario), you should 23 | //! consider [`std::sync`] instead of this crate. Those types are optimized for the currently 24 | //! running operating system, are less complex and are generally much faster. 25 | //! 26 | //! In contrast, `async-lock`'s notification system uses `std::sync::Mutex` under the hood if 27 | //! the `std` feature is enabled, and will fall back to a significantly slower strategy if it is 28 | //! not. So, there are few cases where `async-lock` is a win for performance over [`std::sync`]. 29 | //! 30 | //! [`std::sync`]: https://doc.rust-lang.org/std/sync/index.html 31 | //! [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/stable/index.html#/await_holding_lock 32 | 33 | #![cfg_attr(not(feature = "std"), no_std)] 34 | #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] 35 | #![doc( 36 | html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png" 37 | )] 38 | #![doc( 39 | html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png" 40 | )] 41 | 42 | extern crate alloc; 43 | 44 | /// Simple macro to extract the value of `Poll` or return `Pending`. 45 | /// 46 | /// TODO: Drop in favor of `core::task::ready`, once MSRV is bumped to 1.64. 47 | macro_rules! ready { 48 | ($e:expr) => {{ 49 | use ::core::task::Poll; 50 | 51 | match $e { 52 | Poll::Ready(v) => v, 53 | Poll::Pending => return Poll::Pending, 54 | } 55 | }}; 56 | } 57 | 58 | /// Pins a variable on the stack. 59 | /// 60 | /// TODO: Drop in favor of `core::pin::pin`, once MSRV is bumped to 1.68. 61 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 62 | macro_rules! pin { 63 | ($($x:ident),* $(,)?) => { 64 | $( 65 | let mut $x = $x; 66 | #[allow(unused_mut)] 67 | let mut $x = unsafe { 68 | core::pin::Pin::new_unchecked(&mut $x) 69 | }; 70 | )* 71 | } 72 | } 73 | 74 | /// Make the given function const if the given condition is true. 75 | macro_rules! const_fn { 76 | ( 77 | const_if: #[cfg($($cfg:tt)+)]; 78 | $(#[$($attr:tt)*])* 79 | $vis:vis const fn $($rest:tt)* 80 | ) => { 81 | #[cfg($($cfg)+)] 82 | $(#[$($attr)*])* 83 | $vis const fn $($rest)* 84 | #[cfg(not($($cfg)+))] 85 | $(#[$($attr)*])* 86 | $vis fn $($rest)* 87 | }; 88 | } 89 | 90 | mod barrier; 91 | mod mutex; 92 | mod once_cell; 93 | mod rwlock; 94 | mod semaphore; 95 | 96 | pub use barrier::{Barrier, BarrierWaitResult}; 97 | pub use mutex::{Mutex, MutexGuard, MutexGuardArc}; 98 | pub use once_cell::OnceCell; 99 | pub use rwlock::{ 100 | RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard, 101 | RwLockUpgradableReadGuardArc, RwLockWriteGuard, RwLockWriteGuardArc, 102 | }; 103 | pub use semaphore::{Semaphore, SemaphoreGuard, SemaphoreGuardArc}; 104 | 105 | pub mod futures { 106 | //! Named futures for use with `async_lock` primitives. 107 | 108 | pub use crate::barrier::BarrierWait; 109 | pub use crate::mutex::{Lock, LockArc}; 110 | pub use crate::rwlock::futures::{ 111 | Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, UpgradeArc, Write, WriteArc, 112 | }; 113 | pub use crate::semaphore::{Acquire, AcquireArc}; 114 | } 115 | 116 | #[cfg(not(loom))] 117 | /// Synchronization primitive implementation. 118 | mod sync { 119 | pub(super) use core::sync::atomic; 120 | 121 | pub(super) trait WithMut { 122 | type Output; 123 | 124 | fn with_mut(&mut self, f: F) -> R 125 | where 126 | F: FnOnce(&mut Self::Output) -> R; 127 | } 128 | 129 | impl WithMut for atomic::AtomicUsize { 130 | type Output = usize; 131 | 132 | #[inline] 133 | fn with_mut(&mut self, f: F) -> R 134 | where 135 | F: FnOnce(&mut Self::Output) -> R, 136 | { 137 | f(self.get_mut()) 138 | } 139 | } 140 | } 141 | 142 | #[cfg(loom)] 143 | /// Synchronization primitive implementation. 144 | mod sync { 145 | pub(super) use loom::sync::atomic; 146 | } 147 | 148 | #[cold] 149 | fn abort() -> ! { 150 | // For no_std targets, panicking while panicking is defined as an abort 151 | #[cfg(not(feature = "std"))] 152 | { 153 | struct Bomb; 154 | 155 | impl Drop for Bomb { 156 | fn drop(&mut self) { 157 | panic!("Panicking while panicking to abort") 158 | } 159 | } 160 | 161 | let _bomb = Bomb; 162 | panic!("Panicking while panicking to abort") 163 | } 164 | 165 | // For libstd targets, abort using std::process::abort 166 | #[cfg(feature = "std")] 167 | std::process::abort() 168 | } 169 | -------------------------------------------------------------------------------- /src/mutex.rs: -------------------------------------------------------------------------------- 1 | use core::borrow::Borrow; 2 | use core::cell::UnsafeCell; 3 | use core::fmt; 4 | use core::marker::{PhantomData, PhantomPinned}; 5 | use core::ops::{Deref, DerefMut}; 6 | use core::pin::Pin; 7 | use core::task::Poll; 8 | 9 | use alloc::sync::Arc; 10 | 11 | // We don't use loom::UnsafeCell as that doesn't work with the Mutex API. 12 | use crate::sync::atomic::{AtomicUsize, Ordering}; 13 | 14 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 15 | use std::time::{Duration, Instant}; 16 | 17 | use event_listener::{Event, EventListener}; 18 | use event_listener_strategy::{easy_wrapper, EventListenerFuture}; 19 | 20 | /// An async mutex. 21 | /// 22 | /// The locking mechanism uses eventual fairness to ensure locking will be fair on average without 23 | /// sacrificing performance. This is done by forcing a fair lock whenever a lock operation is 24 | /// starved for longer than 0.5 milliseconds. 25 | /// 26 | /// # Examples 27 | /// 28 | /// ``` 29 | /// # futures_lite::future::block_on(async { 30 | /// use async_lock::Mutex; 31 | /// 32 | /// let m = Mutex::new(1); 33 | /// 34 | /// let mut guard = m.lock().await; 35 | /// *guard = 2; 36 | /// 37 | /// assert!(m.try_lock().is_none()); 38 | /// drop(guard); 39 | /// assert_eq!(*m.try_lock().unwrap(), 2); 40 | /// # }) 41 | /// ``` 42 | pub struct Mutex { 43 | /// Current state of the mutex. 44 | /// 45 | /// The least significant bit is set to 1 if the mutex is locked. 46 | /// The other bits hold the number of starved lock operations. 47 | state: AtomicUsize, 48 | 49 | /// Lock operations waiting for the mutex to be released. 50 | lock_ops: Event, 51 | 52 | /// The value inside the mutex. 53 | data: UnsafeCell, 54 | } 55 | 56 | unsafe impl Send for Mutex {} 57 | unsafe impl Sync for Mutex {} 58 | 59 | impl Mutex { 60 | const_fn! { 61 | const_if: #[cfg(not(loom))]; 62 | /// Creates a new async mutex. 63 | /// 64 | /// # Examples 65 | /// 66 | /// ``` 67 | /// use async_lock::Mutex; 68 | /// 69 | /// let mutex = Mutex::new(0); 70 | /// ``` 71 | pub const fn new(data: T) -> Mutex { 72 | Mutex { 73 | state: AtomicUsize::new(0), 74 | lock_ops: Event::new(), 75 | data: UnsafeCell::new(data), 76 | } 77 | } 78 | } 79 | 80 | /// Consumes the mutex, returning the underlying data. 81 | /// 82 | /// # Examples 83 | /// 84 | /// ``` 85 | /// use async_lock::Mutex; 86 | /// 87 | /// let mutex = Mutex::new(10); 88 | /// assert_eq!(mutex.into_inner(), 10); 89 | /// ``` 90 | pub fn into_inner(self) -> T { 91 | self.data.into_inner() 92 | } 93 | } 94 | 95 | impl Mutex { 96 | /// Acquires the mutex. 97 | /// 98 | /// Returns a guard that releases the mutex when dropped. 99 | /// 100 | /// # Examples 101 | /// 102 | /// ``` 103 | /// # futures_lite::future::block_on(async { 104 | /// use async_lock::Mutex; 105 | /// 106 | /// let mutex = Mutex::new(10); 107 | /// let guard = mutex.lock().await; 108 | /// assert_eq!(*guard, 10); 109 | /// # }) 110 | /// ``` 111 | #[inline] 112 | pub fn lock(&self) -> Lock<'_, T> { 113 | Lock::_new(LockInner { 114 | mutex: self, 115 | acquire_slow: None, 116 | }) 117 | } 118 | 119 | /// Acquires the mutex using the blocking strategy. 120 | /// 121 | /// Returns a guard that releases the mutex when dropped. 122 | /// 123 | /// # Blocking 124 | /// 125 | /// Rather than using asynchronous waiting, like the [`lock`][Mutex::lock] method, 126 | /// this method will block the current thread until the lock is acquired. 127 | /// 128 | /// This method should not be used in an asynchronous context. It is intended to be 129 | /// used in a way that a mutex can be used in both asynchronous and synchronous contexts. 130 | /// Calling this method in an asynchronous context may result in a deadlock. 131 | /// 132 | /// # Examples 133 | /// 134 | /// ``` 135 | /// use async_lock::Mutex; 136 | /// 137 | /// let mutex = Mutex::new(10); 138 | /// let guard = mutex.lock_blocking(); 139 | /// assert_eq!(*guard, 10); 140 | /// ``` 141 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 142 | #[inline] 143 | pub fn lock_blocking(&self) -> MutexGuard<'_, T> { 144 | self.lock().wait() 145 | } 146 | 147 | /// Attempts to acquire the mutex. 148 | /// 149 | /// If the mutex could not be acquired at this time, then [`None`] is returned. Otherwise, a 150 | /// guard is returned that releases the mutex when dropped. 151 | /// 152 | /// # Examples 153 | /// 154 | /// ``` 155 | /// use async_lock::Mutex; 156 | /// 157 | /// let mutex = Mutex::new(10); 158 | /// if let Some(guard) = mutex.try_lock() { 159 | /// assert_eq!(*guard, 10); 160 | /// } 161 | /// # ; 162 | /// ``` 163 | #[inline] 164 | pub fn try_lock(&self) -> Option> { 165 | if self 166 | .state 167 | .compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire) 168 | .is_ok() 169 | { 170 | Some(MutexGuard(self)) 171 | } else { 172 | None 173 | } 174 | } 175 | 176 | /// Returns a mutable reference to the underlying data. 177 | /// 178 | /// Since this call borrows the mutex mutably, no actual locking takes place -- the mutable 179 | /// borrow statically guarantees the mutex is not already acquired. 180 | /// 181 | /// # Examples 182 | /// 183 | /// ``` 184 | /// # futures_lite::future::block_on(async { 185 | /// use async_lock::Mutex; 186 | /// 187 | /// let mut mutex = Mutex::new(0); 188 | /// *mutex.get_mut() = 10; 189 | /// assert_eq!(*mutex.lock().await, 10); 190 | /// # }) 191 | /// ``` 192 | pub fn get_mut(&mut self) -> &mut T { 193 | self.data.get_mut() 194 | } 195 | 196 | /// Unlocks the mutex directly. 197 | /// 198 | /// # Safety 199 | /// 200 | /// This function is intended to be used only in the case where the mutex is locked, 201 | /// and the guard is subsequently forgotten. Calling this while you don't hold a lock 202 | /// on the mutex will likely lead to UB. 203 | pub(crate) unsafe fn unlock_unchecked(&self) { 204 | // Remove the last bit and notify a waiting lock operation. 205 | self.state.fetch_sub(1, Ordering::Release); 206 | self.lock_ops.notify(1); 207 | } 208 | } 209 | 210 | impl Mutex { 211 | /// Acquires the mutex and clones a reference to it. 212 | /// 213 | /// Returns an owned guard that releases the mutex when dropped. 214 | /// 215 | /// # Examples 216 | /// 217 | /// ``` 218 | /// # futures_lite::future::block_on(async { 219 | /// use async_lock::Mutex; 220 | /// use std::sync::Arc; 221 | /// 222 | /// let mutex = Arc::new(Mutex::new(10)); 223 | /// let guard = mutex.lock_arc().await; 224 | /// assert_eq!(*guard, 10); 225 | /// # }) 226 | /// ``` 227 | #[inline] 228 | pub fn lock_arc(self: &Arc) -> LockArc { 229 | LockArc::_new(LockArcInnards::Unpolled { 230 | mutex: Some(self.clone()), 231 | }) 232 | } 233 | 234 | /// Acquires the mutex and clones a reference to it using the blocking strategy. 235 | /// 236 | /// Returns an owned guard that releases the mutex when dropped. 237 | /// 238 | /// # Blocking 239 | /// 240 | /// Rather than using asynchronous waiting, like the [`lock_arc`][Mutex::lock_arc] method, 241 | /// this method will block the current thread until the lock is acquired. 242 | /// 243 | /// This method should not be used in an asynchronous context. It is intended to be 244 | /// used in a way that a mutex can be used in both asynchronous and synchronous contexts. 245 | /// Calling this method in an asynchronous context may result in a deadlock. 246 | /// 247 | /// # Examples 248 | /// 249 | /// ``` 250 | /// use async_lock::Mutex; 251 | /// use std::sync::Arc; 252 | /// 253 | /// let mutex = Arc::new(Mutex::new(10)); 254 | /// let guard = mutex.lock_arc_blocking(); 255 | /// assert_eq!(*guard, 10); 256 | /// ``` 257 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 258 | #[inline] 259 | pub fn lock_arc_blocking(self: &Arc) -> MutexGuardArc { 260 | self.lock_arc().wait() 261 | } 262 | 263 | /// Attempts to acquire the mutex and clone a reference to it. 264 | /// 265 | /// If the mutex could not be acquired at this time, then [`None`] is returned. Otherwise, an 266 | /// owned guard is returned that releases the mutex when dropped. 267 | /// 268 | /// # Examples 269 | /// 270 | /// ``` 271 | /// use async_lock::Mutex; 272 | /// use std::sync::Arc; 273 | /// 274 | /// let mutex = Arc::new(Mutex::new(10)); 275 | /// if let Some(guard) = mutex.try_lock() { 276 | /// assert_eq!(*guard, 10); 277 | /// } 278 | /// # ; 279 | /// ``` 280 | #[inline] 281 | pub fn try_lock_arc(self: &Arc) -> Option> { 282 | if self 283 | .state 284 | .compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire) 285 | .is_ok() 286 | { 287 | Some(MutexGuardArc(self.clone())) 288 | } else { 289 | None 290 | } 291 | } 292 | } 293 | 294 | impl fmt::Debug for Mutex { 295 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 296 | struct Locked; 297 | impl fmt::Debug for Locked { 298 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 299 | f.write_str("") 300 | } 301 | } 302 | 303 | match self.try_lock() { 304 | None => f.debug_struct("Mutex").field("data", &Locked).finish(), 305 | Some(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), 306 | } 307 | } 308 | } 309 | 310 | impl From for Mutex { 311 | fn from(val: T) -> Mutex { 312 | Mutex::new(val) 313 | } 314 | } 315 | 316 | impl Default for Mutex { 317 | fn default() -> Mutex { 318 | Mutex::new(Default::default()) 319 | } 320 | } 321 | 322 | easy_wrapper! { 323 | /// The future returned by [`Mutex::lock`]. 324 | pub struct Lock<'a, T: ?Sized>(LockInner<'a, T> => MutexGuard<'a, T>); 325 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 326 | pub(crate) wait(); 327 | } 328 | 329 | pin_project_lite::pin_project! { 330 | /// Inner future for acquiring the mutex. 331 | struct LockInner<'a, T: ?Sized> { 332 | // Reference to the mutex. 333 | mutex: &'a Mutex, 334 | 335 | // The future that waits for the mutex to become available. 336 | #[pin] 337 | acquire_slow: Option, T>>, 338 | } 339 | } 340 | 341 | unsafe impl Send for Lock<'_, T> {} 342 | unsafe impl Sync for Lock<'_, T> {} 343 | 344 | impl fmt::Debug for Lock<'_, T> { 345 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 346 | f.write_str("Lock { .. }") 347 | } 348 | } 349 | 350 | impl<'a, T: ?Sized> EventListenerFuture for LockInner<'a, T> { 351 | type Output = MutexGuard<'a, T>; 352 | 353 | #[inline] 354 | fn poll_with_strategy<'x, S: event_listener_strategy::Strategy<'x>>( 355 | self: Pin<&mut Self>, 356 | strategy: &mut S, 357 | context: &mut S::Context, 358 | ) -> Poll { 359 | let mut this = self.project(); 360 | 361 | // This may seem weird, but the borrow checker complains otherwise. 362 | if this.acquire_slow.is_none() { 363 | match this.mutex.try_lock() { 364 | Some(guard) => return Poll::Ready(guard), 365 | None => { 366 | this.acquire_slow.set(Some(AcquireSlow::new(this.mutex))); 367 | } 368 | } 369 | } 370 | 371 | ready!(this 372 | .acquire_slow 373 | .as_pin_mut() 374 | .unwrap() 375 | .poll_with_strategy(strategy, context)); 376 | Poll::Ready(MutexGuard(this.mutex)) 377 | } 378 | } 379 | 380 | easy_wrapper! { 381 | /// The future returned by [`Mutex::lock_arc`]. 382 | pub struct LockArc(LockArcInnards => MutexGuardArc); 383 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 384 | pub(crate) wait(); 385 | } 386 | 387 | pin_project_lite::pin_project! { 388 | #[project = LockArcInnardsProj] 389 | enum LockArcInnards { 390 | /// We have not tried to poll the fast path yet. 391 | Unpolled { mutex: Option>> }, 392 | 393 | /// We are acquiring the mutex through the slow path. 394 | AcquireSlow { 395 | #[pin] 396 | inner: AcquireSlow>, T> 397 | }, 398 | } 399 | } 400 | 401 | unsafe impl Send for LockArc {} 402 | unsafe impl Sync for LockArc {} 403 | 404 | impl fmt::Debug for LockArcInnards { 405 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 406 | f.write_str("LockArc { .. }") 407 | } 408 | } 409 | 410 | impl EventListenerFuture for LockArcInnards { 411 | type Output = MutexGuardArc; 412 | 413 | fn poll_with_strategy<'a, S: event_listener_strategy::Strategy<'a>>( 414 | mut self: Pin<&mut Self>, 415 | strategy: &mut S, 416 | context: &mut S::Context, 417 | ) -> Poll { 418 | // Set the inner future if needed. 419 | if let LockArcInnardsProj::Unpolled { mutex } = self.as_mut().project() { 420 | let mutex = mutex.take().expect("mutex taken more than once"); 421 | 422 | // Try the fast path before trying to register slowly. 423 | if let Some(guard) = mutex.try_lock_arc() { 424 | return Poll::Ready(guard); 425 | } 426 | 427 | // Set the inner future to the slow acquire path. 428 | self.as_mut().set(LockArcInnards::AcquireSlow { 429 | inner: AcquireSlow::new(mutex), 430 | }); 431 | } 432 | 433 | // Poll the inner future. 434 | let value = match self.project() { 435 | LockArcInnardsProj::AcquireSlow { inner } => { 436 | ready!(inner.poll_with_strategy(strategy, context)) 437 | } 438 | _ => unreachable!(), 439 | }; 440 | 441 | Poll::Ready(MutexGuardArc(value)) 442 | } 443 | } 444 | 445 | pin_project_lite::pin_project! { 446 | /// Future for acquiring the mutex slowly. 447 | struct AcquireSlow>, T: ?Sized> { 448 | // Reference to the mutex. 449 | mutex: Option, 450 | 451 | // The event listener waiting on the mutex. 452 | listener: Option, 453 | 454 | // The point at which the mutex lock was started. 455 | start: Start, 456 | 457 | // This lock operation is starving. 458 | starved: bool, 459 | 460 | // Capture the `T` lifetime. 461 | #[pin] 462 | _marker: PhantomData, 463 | 464 | // Keeping this type `!Unpin` enables future optimizations. 465 | #[pin] 466 | _pin: PhantomPinned 467 | } 468 | 469 | impl>> PinnedDrop for AcquireSlow { 470 | fn drop(this: Pin<&mut Self>) { 471 | // Make sure the starvation counter is decremented. 472 | this.take_mutex(); 473 | } 474 | } 475 | } 476 | 477 | /// `pin_project_lite` doesn't support `#[cfg]` yet, so we have to do this manually. 478 | struct Start { 479 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 480 | start: Option, 481 | } 482 | 483 | impl>> AcquireSlow { 484 | /// Create a new `AcquireSlow` future. 485 | #[cold] 486 | fn new(mutex: B) -> Self { 487 | AcquireSlow { 488 | mutex: Some(mutex), 489 | listener: None, 490 | start: Start { 491 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 492 | start: None, 493 | }, 494 | starved: false, 495 | _marker: PhantomData, 496 | _pin: PhantomPinned, 497 | } 498 | } 499 | 500 | /// Take the mutex reference out, decrementing the counter if necessary. 501 | fn take_mutex(self: Pin<&mut Self>) -> Option { 502 | let this = self.project(); 503 | let mutex = this.mutex.take(); 504 | 505 | if *this.starved { 506 | if let Some(mutex) = mutex.as_ref() { 507 | // Decrement this counter before we exit. 508 | mutex.borrow().state.fetch_sub(2, Ordering::Release); 509 | } 510 | } 511 | 512 | mutex 513 | } 514 | } 515 | 516 | impl>> EventListenerFuture for AcquireSlow { 517 | type Output = B; 518 | 519 | #[cold] 520 | fn poll_with_strategy<'a, S: event_listener_strategy::Strategy<'a>>( 521 | mut self: Pin<&mut Self>, 522 | strategy: &mut S, 523 | context: &mut S::Context, 524 | ) -> Poll { 525 | let this = self.as_mut().project(); 526 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 527 | let start = *this.start.start.get_or_insert_with(Instant::now); 528 | let mutex = Borrow::>::borrow( 529 | this.mutex.as_ref().expect("future polled after completion"), 530 | ); 531 | 532 | // Only use this hot loop if we aren't currently starved. 533 | if !*this.starved { 534 | loop { 535 | // Start listening for events. 536 | if this.listener.is_none() { 537 | *this.listener = Some(mutex.lock_ops.listen()); 538 | 539 | // Try locking if nobody is being starved. 540 | match mutex 541 | .state 542 | .compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire) 543 | .unwrap_or_else(|x| x) 544 | { 545 | // Lock acquired! 546 | 0 => return Poll::Ready(self.take_mutex().unwrap()), 547 | 548 | // Lock is held and nobody is starved. 549 | 1 => {} 550 | 551 | // Somebody is starved. 552 | _ => break, 553 | } 554 | } else { 555 | ready!(strategy.poll(this.listener, context)); 556 | 557 | // Try locking if nobody is being starved. 558 | match mutex 559 | .state 560 | .compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire) 561 | .unwrap_or_else(|x| x) 562 | { 563 | // Lock acquired! 564 | 0 => return Poll::Ready(self.take_mutex().unwrap()), 565 | 566 | // Lock is held and nobody is starved. 567 | 1 => {} 568 | 569 | // Somebody is starved. 570 | _ => { 571 | // Notify the first listener in line because we probably received a 572 | // notification that was meant for a starved task. 573 | mutex.lock_ops.notify(1); 574 | break; 575 | } 576 | } 577 | 578 | // If waiting for too long, fall back to a fairer locking strategy that will prevent 579 | // newer lock operations from starving us forever. 580 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 581 | if start.elapsed() > Duration::from_micros(500) { 582 | break; 583 | } 584 | } 585 | } 586 | 587 | // Increment the number of starved lock operations. 588 | if mutex.state.fetch_add(2, Ordering::Release) > usize::MAX / 2 { 589 | // In case of potential overflow, abort. 590 | crate::abort(); 591 | } 592 | 593 | // Indicate that we are now starving and will use a fairer locking strategy. 594 | *this.starved = true; 595 | } 596 | 597 | // Fairer locking loop. 598 | loop { 599 | if this.listener.is_none() { 600 | // Start listening for events. 601 | *this.listener = Some(mutex.lock_ops.listen()); 602 | 603 | // Try locking if nobody else is being starved. 604 | match mutex 605 | .state 606 | .compare_exchange(2, 2 | 1, Ordering::Acquire, Ordering::Acquire) 607 | .unwrap_or_else(|x| x) 608 | { 609 | // Lock acquired! 610 | 2 => return Poll::Ready(self.take_mutex().unwrap()), 611 | 612 | // Lock is held by someone. 613 | s if s % 2 == 1 => {} 614 | 615 | // Lock is available. 616 | _ => { 617 | // Be fair: notify the first listener and then go wait in line. 618 | mutex.lock_ops.notify(1); 619 | } 620 | } 621 | } else { 622 | // Wait for a notification. 623 | ready!(strategy.poll(this.listener, context)); 624 | 625 | // Try acquiring the lock without waiting for others. 626 | if mutex.state.fetch_or(1, Ordering::Acquire) % 2 == 0 { 627 | return Poll::Ready(self.take_mutex().unwrap()); 628 | } 629 | } 630 | } 631 | } 632 | } 633 | 634 | /// A guard that releases the mutex when dropped. 635 | #[clippy::has_significant_drop] 636 | pub struct MutexGuard<'a, T: ?Sized>(&'a Mutex); 637 | 638 | unsafe impl Send for MutexGuard<'_, T> {} 639 | unsafe impl Sync for MutexGuard<'_, T> {} 640 | 641 | impl<'a, T: ?Sized> MutexGuard<'a, T> { 642 | /// Returns a reference to the mutex a guard came from. 643 | /// 644 | /// # Examples 645 | /// 646 | /// ``` 647 | /// # futures_lite::future::block_on(async { 648 | /// use async_lock::{Mutex, MutexGuard}; 649 | /// 650 | /// let mutex = Mutex::new(10i32); 651 | /// let guard = mutex.lock().await; 652 | /// dbg!(MutexGuard::source(&guard)); 653 | /// # }) 654 | /// ``` 655 | pub fn source(guard: &MutexGuard<'a, T>) -> &'a Mutex { 656 | guard.0 657 | } 658 | } 659 | 660 | impl Drop for MutexGuard<'_, T> { 661 | #[inline] 662 | fn drop(&mut self) { 663 | // SAFETY: we are dropping the mutex guard, therefore unlocking the mutex. 664 | unsafe { 665 | self.0.unlock_unchecked(); 666 | } 667 | } 668 | } 669 | 670 | impl fmt::Debug for MutexGuard<'_, T> { 671 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 672 | fmt::Debug::fmt(&**self, f) 673 | } 674 | } 675 | 676 | impl fmt::Display for MutexGuard<'_, T> { 677 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 678 | (**self).fmt(f) 679 | } 680 | } 681 | 682 | impl Deref for MutexGuard<'_, T> { 683 | type Target = T; 684 | 685 | fn deref(&self) -> &T { 686 | unsafe { &*self.0.data.get() } 687 | } 688 | } 689 | 690 | impl DerefMut for MutexGuard<'_, T> { 691 | fn deref_mut(&mut self) -> &mut T { 692 | unsafe { &mut *self.0.data.get() } 693 | } 694 | } 695 | 696 | /// An owned guard that releases the mutex when dropped. 697 | #[clippy::has_significant_drop] 698 | pub struct MutexGuardArc(Arc>); 699 | 700 | unsafe impl Send for MutexGuardArc {} 701 | unsafe impl Sync for MutexGuardArc {} 702 | 703 | impl MutexGuardArc { 704 | /// Returns a reference to the mutex a guard came from. 705 | /// 706 | /// # Examples 707 | /// 708 | /// ``` 709 | /// # futures_lite::future::block_on(async { 710 | /// use async_lock::{Mutex, MutexGuardArc}; 711 | /// use std::sync::Arc; 712 | /// 713 | /// let mutex = Arc::new(Mutex::new(10i32)); 714 | /// let guard = mutex.lock_arc().await; 715 | /// dbg!(MutexGuardArc::source(&guard)); 716 | /// # }) 717 | /// ``` 718 | pub fn source(guard: &Self) -> &Arc> 719 | where 720 | // Required because `MutexGuardArc` implements `Sync` regardless of whether `T` is `Send`, 721 | // but this method allows dropping `T` from a different thead than it was created in. 722 | T: Send, 723 | { 724 | &guard.0 725 | } 726 | } 727 | 728 | impl Drop for MutexGuardArc { 729 | #[inline] 730 | fn drop(&mut self) { 731 | // SAFETY: we are dropping the mutex guard, therefore unlocking the mutex. 732 | unsafe { 733 | self.0.unlock_unchecked(); 734 | } 735 | } 736 | } 737 | 738 | impl fmt::Debug for MutexGuardArc { 739 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 740 | fmt::Debug::fmt(&**self, f) 741 | } 742 | } 743 | 744 | impl fmt::Display for MutexGuardArc { 745 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 746 | (**self).fmt(f) 747 | } 748 | } 749 | 750 | impl Deref for MutexGuardArc { 751 | type Target = T; 752 | 753 | fn deref(&self) -> &T { 754 | unsafe { &*self.0.data.get() } 755 | } 756 | } 757 | 758 | impl DerefMut for MutexGuardArc { 759 | fn deref_mut(&mut self) -> &mut T { 760 | unsafe { &mut *self.0.data.get() } 761 | } 762 | } 763 | -------------------------------------------------------------------------------- /src/once_cell.rs: -------------------------------------------------------------------------------- 1 | use core::cell::UnsafeCell; 2 | use core::convert::Infallible; 3 | use core::fmt; 4 | use core::future::Future; 5 | use core::mem::{forget, MaybeUninit}; 6 | use core::ptr; 7 | 8 | use crate::sync::atomic::{AtomicUsize, Ordering}; 9 | 10 | #[cfg(not(loom))] 11 | use crate::sync::WithMut; 12 | 13 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 14 | use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; 15 | 16 | use event_listener::Event; 17 | use event_listener_strategy::{NonBlocking, Strategy}; 18 | 19 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 20 | use event_listener::Listener; 21 | 22 | /// The current state of the `OnceCell`. 23 | #[derive(Copy, Clone, PartialEq, Eq)] 24 | #[repr(usize)] 25 | enum State { 26 | /// The `OnceCell` is uninitialized. 27 | Uninitialized = 0, 28 | /// The `OnceCell` is being initialized. 29 | Initializing = 1, 30 | /// The `OnceCell` is initialized. 31 | Initialized = 2, 32 | } 33 | 34 | impl From for State { 35 | fn from(val: usize) -> Self { 36 | match val { 37 | 0 => State::Uninitialized, 38 | 1 => State::Initializing, 39 | 2 => State::Initialized, 40 | _ => unreachable!("Invalid state"), 41 | } 42 | } 43 | } 44 | 45 | impl From for usize { 46 | fn from(val: State) -> Self { 47 | val as usize 48 | } 49 | } 50 | 51 | /// A memory location that can be written to at most once. 52 | /// 53 | /// A `OnceCell` can be used to store a single value, and only once. However, 54 | /// once the value is stored, it can be accessed directly through a reference 55 | /// instead of needing an RAII guard like `Mutex` or `RwLock`. 56 | /// 57 | /// # Examples 58 | /// 59 | /// This structure is useful for a variety of patterns, most notably for one-time 60 | /// initialization. 61 | /// 62 | /// ```rust 63 | /// use async_lock::OnceCell; 64 | /// 65 | /// # struct Foobar; 66 | /// 67 | /// async fn very_expensive_initialization() -> Foobar { 68 | /// // Imagine this is very expensive to initialize, 69 | /// // for instance, it requires a network request or 70 | /// // a database call. 71 | /// # Foobar 72 | /// } 73 | /// 74 | /// struct LazyFoobar { 75 | /// inner: OnceCell, 76 | /// } 77 | /// 78 | /// impl LazyFoobar { 79 | /// fn new() -> Self { 80 | /// Self { 81 | /// inner: OnceCell::new(), 82 | /// } 83 | /// } 84 | /// 85 | /// async fn load(&self) -> &Foobar { 86 | /// self.inner.get_or_init(|| async { 87 | /// very_expensive_initialization().await 88 | /// }).await 89 | /// } 90 | /// } 91 | /// ``` 92 | pub struct OnceCell { 93 | /// Listeners waiting for a chance to initialize the cell. 94 | /// 95 | /// These are the users of get_or_init() and similar functions. 96 | active_initializers: Event, 97 | 98 | /// Listeners waiting for the cell to be initialized. 99 | /// 100 | /// These are the users of wait(). 101 | passive_waiters: Event, 102 | 103 | /// State associated with the cell. 104 | state: AtomicUsize, 105 | 106 | /// The value of the cell. 107 | value: UnsafeCell>, 108 | } 109 | 110 | unsafe impl Send for OnceCell {} 111 | unsafe impl Sync for OnceCell {} 112 | 113 | impl OnceCell { 114 | const_fn! { 115 | const_if: #[cfg(not(loom))]; 116 | /// Create a new, uninitialized `OnceCell`. 117 | /// 118 | /// # Example 119 | /// 120 | /// ```rust 121 | /// use async_lock::OnceCell; 122 | /// 123 | /// let cell = OnceCell::new(); 124 | /// # cell.set_blocking(1); 125 | /// ``` 126 | pub const fn new() -> Self { 127 | Self { 128 | active_initializers: Event::new(), 129 | passive_waiters: Event::new(), 130 | state: AtomicUsize::new(State::Uninitialized as _), 131 | value: UnsafeCell::new(MaybeUninit::uninit()), 132 | } 133 | } 134 | } 135 | 136 | /// Tell whether or not the cell is initialized. 137 | /// 138 | /// This may not always be accurate. For instance, it is possible for 139 | /// another thread to initialize the cell between the time when this 140 | /// function is called and the time when the result is actually used. 141 | /// 142 | /// # Example 143 | /// 144 | /// ```rust 145 | /// use async_lock::OnceCell; 146 | /// 147 | /// # futures_lite::future::block_on(async { 148 | /// let cell = OnceCell::new(); 149 | /// assert!(!cell.is_initialized()); 150 | /// cell.set(1).await; 151 | /// assert!(cell.is_initialized()); 152 | /// # }); 153 | /// ``` 154 | pub fn is_initialized(&self) -> bool { 155 | State::from(self.state.load(Ordering::Acquire)) == State::Initialized 156 | } 157 | 158 | /// Get a reference to the inner value, or `None` if the value 159 | /// is not yet initialized. 160 | /// 161 | /// # Example 162 | /// 163 | /// ```rust 164 | /// use async_lock::OnceCell; 165 | /// 166 | /// # futures_lite::future::block_on(async { 167 | /// let cell = OnceCell::new(); 168 | /// assert!(cell.get().is_none()); 169 | /// cell.set(1).await; 170 | /// assert_eq!(cell.get(), Some(&1)); 171 | /// # }); 172 | /// ``` 173 | pub fn get(&self) -> Option<&T> { 174 | if self.is_initialized() { 175 | // SAFETY: We know that the value is initialized, so it is safe to 176 | // read it. 177 | Some(unsafe { self.get_unchecked() }) 178 | } else { 179 | None 180 | } 181 | } 182 | 183 | /// Get a mutable reference to the inner value, or `None` if the value 184 | /// is not yet initialized. 185 | /// 186 | /// This function is useful for initializing the value inside the cell 187 | /// when we still have a mutable reference to the cell. 188 | /// 189 | /// # Example 190 | /// 191 | /// ```rust 192 | /// use async_lock::OnceCell; 193 | /// 194 | /// # futures_lite::future::block_on(async { 195 | /// let mut cell = OnceCell::new(); 196 | /// assert!(cell.get_mut().is_none()); 197 | /// cell.set(1).await; 198 | /// assert_eq!(cell.get_mut(), Some(&mut 1)); 199 | /// *cell.get_mut().unwrap() = 2; 200 | /// assert_eq!(cell.get(), Some(&2)); 201 | /// # }); 202 | /// ``` 203 | pub fn get_mut(&mut self) -> Option<&mut T> { 204 | self.state.with_mut(|state| { 205 | if State::from(*state) == State::Initialized { 206 | // SAFETY: We know that the value is initialized, so it is safe to 207 | // read it. 208 | Some(unsafe { &mut *self.value.get().cast() }) 209 | } else { 210 | None 211 | } 212 | }) 213 | } 214 | 215 | /// Take the value out of this `OnceCell`, moving it back to the uninitialized 216 | /// state. 217 | /// 218 | /// # Example 219 | /// 220 | /// ```rust 221 | /// use async_lock::OnceCell; 222 | /// 223 | /// # futures_lite::future::block_on(async { 224 | /// let mut cell = OnceCell::new(); 225 | /// cell.set(1).await; 226 | /// assert_eq!(cell.take(), Some(1)); 227 | /// assert!(!cell.is_initialized()); 228 | /// # }); 229 | /// ``` 230 | pub fn take(&mut self) -> Option { 231 | self.state.with_mut(|state| { 232 | if State::from(*state) == State::Initialized { 233 | // SAFETY: We know that the value is initialized, so it is safe to 234 | // read it. 235 | let value = unsafe { ptr::read(self.value.get().cast()) }; 236 | *state = State::Uninitialized.into(); 237 | Some(value) 238 | } else { 239 | None 240 | } 241 | }) 242 | } 243 | 244 | /// Convert this `OnceCell` into the inner value, if it is initialized. 245 | /// 246 | /// # Example 247 | /// 248 | /// ```rust 249 | /// use async_lock::OnceCell; 250 | /// 251 | /// # futures_lite::future::block_on(async { 252 | /// let cell = OnceCell::new(); 253 | /// cell.set(1).await; 254 | /// assert_eq!(cell.into_inner(), Some(1)); 255 | /// # }); 256 | /// ``` 257 | pub fn into_inner(mut self) -> Option { 258 | self.take() 259 | } 260 | 261 | /// Wait for the cell to be initialized, and then return a reference to the 262 | /// inner value. 263 | /// 264 | /// # Example 265 | /// 266 | /// ```rust 267 | /// use async_lock::OnceCell; 268 | /// use std::sync::Arc; 269 | /// use std::time::Duration; 270 | /// use std::thread::{sleep, spawn}; 271 | /// 272 | /// let cell = Arc::new(OnceCell::new()); 273 | /// let cell2 = cell.clone(); 274 | /// 275 | /// spawn(move || { 276 | /// sleep(Duration::from_millis(5)); 277 | /// cell2.set_blocking(1); 278 | /// }); 279 | /// 280 | /// # futures_lite::future::block_on(async { 281 | /// assert_eq!(cell.wait().await, &1); 282 | /// # }); 283 | /// ``` 284 | pub async fn wait(&self) -> &T { 285 | // Fast path: see if the value is already initialized. 286 | if let Some(value) = self.get() { 287 | return value; 288 | } 289 | 290 | // Slow path: wait for the value to be initialized. 291 | event_listener::listener!(self.passive_waiters => listener); 292 | 293 | // Try again. 294 | if let Some(value) = self.get() { 295 | return value; 296 | } 297 | 298 | listener.await; 299 | debug_assert!(self.is_initialized()); 300 | 301 | // SAFETY: We know that the value is initialized, so it is safe to 302 | // read it. 303 | unsafe { self.get_unchecked() } 304 | } 305 | 306 | /// Wait for the cell to be initialized, and then return a reference to the 307 | /// inner value. 308 | /// 309 | /// # Blocking 310 | /// 311 | /// In contrast to the `wait` method, this method blocks the current thread of 312 | /// execution instead of awaiting. 313 | /// 314 | /// This method should not be used in an asynchronous context. It is intended 315 | /// to be used such that a `OnceCell` can be used in both asynchronous and synchronous contexts. 316 | /// Calling this method in an asynchronous context may result in deadlocks. 317 | /// 318 | /// # Example 319 | /// 320 | /// ```rust 321 | /// use async_lock::OnceCell; 322 | /// use std::sync::Arc; 323 | /// use std::time::Duration; 324 | /// use std::thread::{sleep, spawn}; 325 | /// 326 | /// let cell = Arc::new(OnceCell::new()); 327 | /// let cell2 = cell.clone(); 328 | /// 329 | /// spawn(move || { 330 | /// sleep(Duration::from_millis(5)); 331 | /// cell2.set_blocking(1); 332 | /// }); 333 | /// 334 | /// assert_eq!(cell.wait_blocking(), &1); 335 | /// ``` 336 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 337 | pub fn wait_blocking(&self) -> &T { 338 | // Fast path: see if the value is already initialized. 339 | if let Some(value) = self.get() { 340 | return value; 341 | } 342 | 343 | // Slow path: wait for the value to be initialized. 344 | event_listener::listener!(self.passive_waiters => listener); 345 | 346 | // Try again. 347 | if let Some(value) = self.get() { 348 | return value; 349 | } 350 | 351 | listener.wait(); 352 | debug_assert!(self.is_initialized()); 353 | 354 | // SAFETY: We know that the value is initialized, so it is safe to 355 | // read it. 356 | unsafe { self.get_unchecked() } 357 | } 358 | 359 | /// Either get the value or initialize it with the given closure. 360 | /// 361 | /// The cell will not be initialized if the closure returns an error. 362 | /// 363 | /// # Example 364 | /// 365 | /// ```rust 366 | /// use async_lock::OnceCell; 367 | /// # 368 | /// # // Prevent explicit value errors. 369 | /// # fn _explicit(_: &Result<&i32, ()>) {} 370 | /// 371 | /// # futures_lite::future::block_on(async { 372 | /// let cell = OnceCell::new(); 373 | /// 374 | /// let result = cell.get_or_try_init(|| async { Err(()) }).await; 375 | /// assert!(result.is_err()); 376 | /// 377 | /// let result = cell.get_or_try_init(|| async { Ok(1) }).await; 378 | /// # _explicit(&result); 379 | /// assert_eq!(result.unwrap(), &1); 380 | /// 381 | /// let result = cell.get_or_try_init(|| async { Err(()) }).await; 382 | /// 383 | /// assert_eq!(result.unwrap(), &1); 384 | /// # }); 385 | /// ``` 386 | pub async fn get_or_try_init>>( 387 | &self, 388 | closure: impl FnOnce() -> Fut, 389 | ) -> Result<&T, E> { 390 | // Fast path: see if the value is already initialized. 391 | if let Some(value) = self.get() { 392 | return Ok(value); 393 | } 394 | 395 | // Slow path: initialize the value. 396 | self.initialize_or_wait(closure, &mut NonBlocking::default()) 397 | .await?; 398 | debug_assert!(self.is_initialized()); 399 | 400 | // SAFETY: We know that the value is initialized, so it is safe to 401 | // read it. 402 | Ok(unsafe { self.get_unchecked() }) 403 | } 404 | 405 | /// Either get the value or initialize it with the given closure. 406 | /// 407 | /// The cell will not be initialized if the closure returns an error. 408 | /// 409 | /// # Blocking 410 | /// 411 | /// In contrast to the `get_or_try_init` method, this method blocks the current thread of 412 | /// execution instead of awaiting. 413 | /// 414 | /// This method should not be used in an asynchronous context. It is intended 415 | /// to be used such that a `OnceCell` can be used in both asynchronous and synchronous contexts. 416 | /// Calling this method in an asynchronous context may result in deadlocks. 417 | /// 418 | /// # Example 419 | /// 420 | /// ```rust 421 | /// use async_lock::OnceCell; 422 | /// # 423 | /// # // Prevent explicit type errors. 424 | /// # fn _explicit(_: &Result<&i32, ()>) {} 425 | /// 426 | /// let cell = OnceCell::new(); 427 | /// 428 | /// let result = cell.get_or_try_init_blocking(|| Err(())); 429 | /// assert!(result.is_err()); 430 | /// 431 | /// let result = cell.get_or_try_init_blocking(|| Ok(1)); 432 | /// # _explicit(&result); 433 | /// assert_eq!(result.unwrap(), &1); 434 | /// 435 | /// let result = cell.get_or_try_init_blocking(|| Err(())); 436 | /// 437 | /// assert_eq!(result.unwrap(), &1); 438 | /// ``` 439 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 440 | pub fn get_or_try_init_blocking( 441 | &self, 442 | closure: impl FnOnce() -> Result, 443 | ) -> Result<&T, E> { 444 | // Fast path: see if the value is already initialized. 445 | if let Some(value) = self.get() { 446 | return Ok(value); 447 | } 448 | 449 | // Slow path: initialize the value. 450 | // The futures provided should never block, so we can use `now_or_never`. 451 | now_or_never(self.initialize_or_wait( 452 | move || core::future::ready(closure()), 453 | &mut event_listener_strategy::Blocking::default(), 454 | ))?; 455 | debug_assert!(self.is_initialized()); 456 | 457 | // SAFETY: We know that the value is initialized, so it is safe to 458 | // read it. 459 | Ok(unsafe { self.get_unchecked() }) 460 | } 461 | 462 | /// Either get the value or initialize it with the given closure. 463 | /// 464 | /// Many tasks may call this function, but the value will only be set once 465 | /// and only one closure will be invoked. 466 | /// 467 | /// # Example 468 | /// 469 | /// ```rust 470 | /// use async_lock::OnceCell; 471 | /// 472 | /// # futures_lite::future::block_on(async { 473 | /// let cell = OnceCell::new(); 474 | /// assert_eq!(cell.get_or_init(|| async { 1 }).await, &1); 475 | /// assert_eq!(cell.get_or_init(|| async { 2 }).await, &1); 476 | /// # }); 477 | /// ``` 478 | pub async fn get_or_init>(&self, closure: impl FnOnce() -> Fut) -> &T { 479 | // false positive: https://github.com/rust-lang/rust/issues/129352 480 | #[allow(unreachable_patterns)] 481 | match self 482 | .get_or_try_init(move || async move { 483 | let result: Result = Ok(closure().await); 484 | result 485 | }) 486 | .await 487 | { 488 | Ok(value) => value, 489 | Err(infallible) => match infallible {}, 490 | } 491 | } 492 | 493 | /// Either get the value or initialize it with the given closure. 494 | /// 495 | /// Many tasks may call this function, but the value will only be set once 496 | /// and only one closure will be invoked. 497 | /// 498 | /// # Blocking 499 | /// 500 | /// In contrast to the `get_or_init` method, this method blocks the current thread of 501 | /// execution instead of awaiting. 502 | /// 503 | /// This method should not be used in an asynchronous context. It is intended 504 | /// to be used such that a `OnceCell` can be used in both asynchronous and synchronous contexts. 505 | /// Calling this method in an asynchronous context may result in deadlocks. 506 | /// 507 | /// # Example 508 | /// 509 | /// ```rust 510 | /// use async_lock::OnceCell; 511 | /// 512 | /// let cell = OnceCell::new(); 513 | /// assert_eq!(cell.get_or_init_blocking(|| 1), &1); 514 | /// assert_eq!(cell.get_or_init_blocking(|| 2), &1); 515 | /// ``` 516 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 517 | pub fn get_or_init_blocking(&self, closure: impl FnOnce() -> T + Unpin) -> &T { 518 | let result = self.get_or_try_init_blocking(move || { 519 | let result: Result = Ok(closure()); 520 | result 521 | }); 522 | 523 | // false positive: https://github.com/rust-lang/rust/issues/129352 524 | #[allow(unreachable_patterns)] 525 | match result { 526 | Ok(value) => value, 527 | Err(infallible) => match infallible {}, 528 | } 529 | } 530 | 531 | /// Try to set the value of the cell. 532 | /// 533 | /// If the cell is already initialized, this method returns the original 534 | /// value back. 535 | /// 536 | /// # Example 537 | /// 538 | /// ```rust 539 | /// use async_lock::OnceCell; 540 | /// 541 | /// # futures_lite::future::block_on(async { 542 | /// let cell = OnceCell::new(); 543 | /// 544 | /// assert_eq!(cell.set(1).await, Ok(&1)); 545 | /// assert_eq!(cell.get(), Some(&1)); 546 | /// assert_eq!(cell.set(2).await, Err(2)); 547 | /// # }); 548 | /// ``` 549 | pub async fn set(&self, value: T) -> Result<&T, T> { 550 | let mut value = Some(value); 551 | self.get_or_init(|| async { value.take().unwrap() }).await; 552 | 553 | match value { 554 | Some(value) => Err(value), 555 | None => { 556 | // SAFETY: value was taken, so we are initialized 557 | Ok(unsafe { self.get_unchecked() }) 558 | } 559 | } 560 | } 561 | 562 | /// Try to set the value of the cell. 563 | /// 564 | /// If the cell is already initialized, this method returns the original 565 | /// value back. 566 | /// 567 | /// # Blocking 568 | /// 569 | /// In contrast to the `set` method, this method blocks the current thread of 570 | /// execution instead of awaiting. 571 | /// 572 | /// This method should not be used in an asynchronous context. It is intended 573 | /// to be used such that a `OnceCell` can be used in both asynchronous and synchronous contexts. 574 | /// Calling this method in an asynchronous context may result in deadlocks. 575 | /// 576 | /// # Example 577 | /// 578 | /// ```rust 579 | /// use async_lock::OnceCell; 580 | /// 581 | /// let cell = OnceCell::new(); 582 | /// 583 | /// assert_eq!(cell.set_blocking(1), Ok(&1)); 584 | /// assert_eq!(cell.get(), Some(&1)); 585 | /// assert_eq!(cell.set_blocking(2), Err(2)); 586 | /// ``` 587 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 588 | pub fn set_blocking(&self, value: T) -> Result<&T, T> { 589 | let mut value = Some(value); 590 | self.get_or_init_blocking(|| value.take().unwrap()); 591 | 592 | match value { 593 | Some(value) => Err(value), 594 | None => { 595 | // SAFETY: value was taken, so we are initialized 596 | Ok(unsafe { self.get_unchecked() }) 597 | } 598 | } 599 | } 600 | 601 | /// Wait for the cell to be initialized, optionally using a closure 602 | /// to initialize the cell if it is not initialized yet. 603 | #[cold] 604 | async fn initialize_or_wait>, F: FnOnce() -> Fut>( 605 | &self, 606 | closure: F, 607 | strategy: &mut impl for<'a> Strategy<'a>, 608 | ) -> Result<(), E> { 609 | // The event listener we're currently waiting on. 610 | let mut event_listener = None; 611 | 612 | let mut closure = Some(closure); 613 | 614 | loop { 615 | // Check the current state of the cell. 616 | let state = self.state.load(Ordering::Acquire); 617 | 618 | // Determine what we should do based on our state. 619 | match state.into() { 620 | State::Initialized => { 621 | // The cell is initialized now, so we can return. 622 | return Ok(()); 623 | } 624 | State::Initializing => { 625 | // The cell is currently initializing, or the cell is uninitialized 626 | // but we do not have the ability to initialize it. 627 | // 628 | // We need to wait the initialization to complete. 629 | if let Some(listener) = event_listener.take() { 630 | strategy.wait(listener).await; 631 | } else { 632 | event_listener = Some(self.active_initializers.listen()); 633 | } 634 | } 635 | State::Uninitialized => { 636 | // Try to move the cell into the initializing state. 637 | if self 638 | .state 639 | .compare_exchange( 640 | State::Uninitialized.into(), 641 | State::Initializing.into(), 642 | Ordering::AcqRel, 643 | Ordering::Acquire, 644 | ) 645 | .is_err() 646 | { 647 | // The cell was initialized while we were trying to 648 | // initialize it. 649 | continue; 650 | } 651 | 652 | // Now that we have an exclusive lock on the cell's value, 653 | // we can try to initialize it. 654 | let _guard = Guard(self); 655 | let initializer = closure.take().unwrap(); 656 | match (initializer)().await { 657 | Ok(value) => { 658 | // Write the value into the cell and update the state. 659 | unsafe { 660 | ptr::write(self.value.get().cast(), value); 661 | } 662 | forget(_guard); 663 | self.state 664 | .store(State::Initialized.into(), Ordering::Release); 665 | 666 | // Notify the listeners that the value is initialized. 667 | self.active_initializers.notify_additional(usize::MAX); 668 | self.passive_waiters.notify_additional(usize::MAX); 669 | 670 | return Ok(()); 671 | } 672 | Err(err) => { 673 | // Update the state to indicate that the value is 674 | // uninitialized. 675 | drop(_guard); 676 | 677 | return Err(err); 678 | } 679 | } 680 | } 681 | } 682 | } 683 | 684 | /// Set the cell's state back to `UNINITIALIZED on drop. 685 | /// 686 | /// If the closure panics, this ensures that the cell's state is set back to 687 | /// `UNINITIALIZED` and that the next listener is notified. 688 | struct Guard<'a, T>(&'a OnceCell); 689 | 690 | impl Drop for Guard<'_, T> { 691 | fn drop(&mut self) { 692 | self.0 693 | .state 694 | .store(State::Uninitialized.into(), Ordering::Release); 695 | 696 | // Notify the next initializer that it's their turn. 697 | self.0.active_initializers.notify(1); 698 | } 699 | } 700 | } 701 | 702 | /// Get a reference to the inner value. 703 | /// 704 | /// # Safety 705 | /// 706 | /// The caller must ensure that the cell is initialized. 707 | /// 708 | /// # Example 709 | /// 710 | /// ```rust 711 | /// use async_lock::OnceCell; 712 | /// 713 | /// # futures_lite::future::block_on(async { 714 | /// let cell = OnceCell::new(); 715 | /// cell.set(1).await; 716 | /// 717 | /// // SAFETY: We know that the value is initialized, so it is safe to 718 | /// // read it. 719 | /// assert_eq!(unsafe { cell.get_unchecked() }, &1); 720 | /// # }); 721 | /// ``` 722 | pub unsafe fn get_unchecked(&self) -> &T { 723 | // SAFETY: The caller asserts that the value is initialized 724 | &*self.value.get().cast() 725 | } 726 | } 727 | 728 | impl From for OnceCell { 729 | /// Create a new, initialized `OnceCell` from an existing value. 730 | /// 731 | /// # Example 732 | /// 733 | /// ```rust 734 | /// use async_lock::OnceCell; 735 | /// 736 | /// let cell = OnceCell::from(42); 737 | /// assert_eq!(cell.get(), Some(&42)); 738 | /// ``` 739 | fn from(value: T) -> Self { 740 | Self { 741 | active_initializers: Event::new(), 742 | passive_waiters: Event::new(), 743 | state: AtomicUsize::new(State::Initialized.into()), 744 | value: UnsafeCell::new(MaybeUninit::new(value)), 745 | } 746 | } 747 | } 748 | 749 | impl fmt::Debug for OnceCell { 750 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 751 | struct Inner<'a, T>(&'a OnceCell); 752 | 753 | impl fmt::Debug for Inner<'_, T> { 754 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 755 | match self.0.state.load(Ordering::Acquire).into() { 756 | State::Uninitialized => f.write_str(""), 757 | State::Initializing => f.write_str(""), 758 | State::Initialized => { 759 | // SAFETY: "value" is initialized. 760 | let value = unsafe { self.0.get_unchecked() }; 761 | fmt::Debug::fmt(value, f) 762 | } 763 | } 764 | } 765 | } 766 | 767 | f.debug_tuple("OnceCell").field(&Inner(self)).finish() 768 | } 769 | } 770 | 771 | impl Drop for OnceCell { 772 | fn drop(&mut self) { 773 | self.state.with_mut(|state| { 774 | if State::from(*state) == State::Initialized { 775 | // SAFETY: We know that the value is initialized, so it is safe to 776 | // drop it. 777 | unsafe { self.value.get().cast::().drop_in_place() } 778 | } 779 | }); 780 | } 781 | } 782 | 783 | impl Default for OnceCell { 784 | // Calls `OnceCell::new`. 785 | #[inline] 786 | fn default() -> Self { 787 | Self::new() 788 | } 789 | } 790 | 791 | /// Either return the result of a future now, or panic. 792 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 793 | fn now_or_never(f: impl Future) -> T { 794 | const NOOP_WAKER: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); 795 | 796 | unsafe fn wake(_: *const ()) {} 797 | unsafe fn wake_by_ref(_: *const ()) {} 798 | unsafe fn clone(_: *const ()) -> RawWaker { 799 | RawWaker::new(ptr::null(), &NOOP_WAKER) 800 | } 801 | unsafe fn drop(_: *const ()) {} 802 | 803 | pin!(f); 804 | 805 | let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &NOOP_WAKER)) }; 806 | 807 | // Poll the future exactly once. 808 | let mut cx = Context::from_waker(&waker); 809 | 810 | match f.poll(&mut cx) { 811 | Poll::Ready(value) => value, 812 | Poll::Pending => unreachable!("future not ready"), 813 | } 814 | } 815 | -------------------------------------------------------------------------------- /src/rwlock.rs: -------------------------------------------------------------------------------- 1 | use core::cell::UnsafeCell; 2 | use core::fmt; 3 | use core::mem::{self, ManuallyDrop}; 4 | use core::ops::{Deref, DerefMut}; 5 | use core::ptr::{self, NonNull}; 6 | 7 | use alloc::sync::Arc; 8 | 9 | pub(crate) mod futures; 10 | mod raw; 11 | 12 | use self::futures::{ 13 | Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, UpgradeArc, Write, WriteArc, 14 | }; 15 | use self::raw::{RawRwLock, RawUpgrade}; 16 | 17 | /// An async reader-writer lock. 18 | /// 19 | /// This type of lock allows multiple readers or one writer at any point in time. 20 | /// 21 | /// The locking strategy is write-preferring, which means writers are never starved. 22 | /// Releasing a write lock wakes the next blocked reader and the next blocked writer. 23 | /// 24 | /// # Examples 25 | /// 26 | /// ``` 27 | /// # futures_lite::future::block_on(async { 28 | /// use async_lock::RwLock; 29 | /// 30 | /// let lock = RwLock::new(5); 31 | /// 32 | /// // Multiple read locks can be held at a time. 33 | /// let r1 = lock.read().await; 34 | /// let r2 = lock.read().await; 35 | /// assert_eq!(*r1, 5); 36 | /// assert_eq!(*r2, 5); 37 | /// drop((r1, r2)); 38 | /// 39 | /// // Only one write lock can be held at a time. 40 | /// let mut w = lock.write().await; 41 | /// *w += 1; 42 | /// assert_eq!(*w, 6); 43 | /// # }) 44 | /// ``` 45 | pub struct RwLock { 46 | /// The underlying locking implementation. 47 | /// Doesn't depend on `T`. 48 | raw: RawRwLock, 49 | 50 | /// The inner value. 51 | value: UnsafeCell, 52 | } 53 | 54 | unsafe impl Send for RwLock {} 55 | unsafe impl Sync for RwLock {} 56 | 57 | impl RwLock { 58 | const_fn! { 59 | const_if: #[cfg(not(loom))]; 60 | /// Creates a new reader-writer lock. 61 | /// 62 | /// # Examples 63 | /// 64 | /// ``` 65 | /// use async_lock::RwLock; 66 | /// 67 | /// let lock = RwLock::new(0); 68 | /// ``` 69 | #[must_use] 70 | #[inline] 71 | pub const fn new(t: T) -> RwLock { 72 | RwLock { 73 | raw: RawRwLock::new(), 74 | value: UnsafeCell::new(t), 75 | } 76 | } 77 | } 78 | 79 | /// Unwraps the lock and returns the inner value. 80 | /// 81 | /// # Examples 82 | /// 83 | /// ``` 84 | /// use async_lock::RwLock; 85 | /// 86 | /// let lock = RwLock::new(5); 87 | /// assert_eq!(lock.into_inner(), 5); 88 | /// ``` 89 | #[must_use] 90 | #[inline] 91 | pub fn into_inner(self) -> T { 92 | self.value.into_inner() 93 | } 94 | 95 | /// Attempts to acquire an an owned, reference-counted read lock. 96 | /// 97 | /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a 98 | /// guard is returned that releases the lock when dropped. 99 | /// 100 | /// # Examples 101 | /// 102 | /// ``` 103 | /// # futures_lite::future::block_on(async { 104 | /// use std::sync::Arc; 105 | /// use async_lock::RwLock; 106 | /// 107 | /// let lock = Arc::new(RwLock::new(1)); 108 | /// 109 | /// let reader = lock.read_arc().await; 110 | /// assert_eq!(*reader, 1); 111 | /// 112 | /// assert!(lock.try_read_arc().is_some()); 113 | /// # }) 114 | /// ``` 115 | #[inline] 116 | pub fn try_read_arc(self: &Arc) -> Option> { 117 | if self.raw.try_read() { 118 | let arc = self.clone(); 119 | 120 | // SAFETY: we previously acquired a read lock. 121 | Some(unsafe { RwLockReadGuardArc::from_arc(arc) }) 122 | } else { 123 | None 124 | } 125 | } 126 | 127 | /// Acquires an owned, reference-counted read lock. 128 | /// 129 | /// Returns a guard that releases the lock when dropped. 130 | /// 131 | /// Note that attempts to acquire a read lock will block if there are also concurrent attempts 132 | /// to acquire a write lock. 133 | /// 134 | /// # Examples 135 | /// 136 | /// ``` 137 | /// # futures_lite::future::block_on(async { 138 | /// use std::sync::Arc; 139 | /// use async_lock::RwLock; 140 | /// 141 | /// let lock = Arc::new(RwLock::new(1)); 142 | /// 143 | /// let reader = lock.read_arc().await; 144 | /// assert_eq!(*reader, 1); 145 | /// 146 | /// assert!(lock.try_read_arc().is_some()); 147 | /// # }) 148 | /// ``` 149 | #[inline] 150 | pub fn read_arc<'a>(self: &'a Arc) -> ReadArc<'a, T> { 151 | ReadArc::new(self.raw.read(), self) 152 | } 153 | 154 | /// Acquires an owned, reference-counted read lock. 155 | /// 156 | /// Returns a guard that releases the lock when dropped. 157 | /// 158 | /// Note that attempts to acquire a read lock will block if there are also concurrent attempts 159 | /// to acquire a write lock. 160 | /// 161 | /// # Blocking 162 | /// 163 | /// Rather than using asynchronous waiting, like the [`read_arc`][`RwLock::read_arc`] method, 164 | /// this method will block the current thread until the read lock is acquired. 165 | /// 166 | /// This method should not be used in an asynchronous context. It is intended to be 167 | /// used in a way that a lock can be used in both asynchronous and synchronous contexts. 168 | /// Calling this method in an asynchronous context may result in a deadlock. 169 | /// 170 | /// # Examples 171 | /// 172 | /// ``` 173 | /// use std::sync::Arc; 174 | /// use async_lock::RwLock; 175 | /// 176 | /// let lock = Arc::new(RwLock::new(1)); 177 | /// 178 | /// let reader = lock.read_arc_blocking(); 179 | /// assert_eq!(*reader, 1); 180 | /// 181 | /// assert!(lock.try_read().is_some()); 182 | /// ``` 183 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 184 | #[inline] 185 | pub fn read_arc_blocking(self: &Arc) -> RwLockReadGuardArc { 186 | self.read_arc().wait() 187 | } 188 | } 189 | 190 | impl RwLock { 191 | /// Attempts to acquire a read lock. 192 | /// 193 | /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a 194 | /// guard is returned that releases the lock when dropped. 195 | /// 196 | /// # Examples 197 | /// 198 | /// ``` 199 | /// # futures_lite::future::block_on(async { 200 | /// use async_lock::RwLock; 201 | /// 202 | /// let lock = RwLock::new(1); 203 | /// 204 | /// let reader = lock.read().await; 205 | /// assert_eq!(*reader, 1); 206 | /// 207 | /// assert!(lock.try_read().is_some()); 208 | /// # }) 209 | /// ``` 210 | #[inline] 211 | pub fn try_read(&self) -> Option> { 212 | if self.raw.try_read() { 213 | Some(RwLockReadGuard { 214 | lock: &self.raw, 215 | value: self.value.get(), 216 | }) 217 | } else { 218 | None 219 | } 220 | } 221 | 222 | /// Acquires a read lock. 223 | /// 224 | /// Returns a guard that releases the lock when dropped. 225 | /// 226 | /// Note that attempts to acquire a read lock will block if there are also concurrent attempts 227 | /// to acquire a write lock. 228 | /// 229 | /// # Examples 230 | /// 231 | /// ``` 232 | /// # futures_lite::future::block_on(async { 233 | /// use async_lock::RwLock; 234 | /// 235 | /// let lock = RwLock::new(1); 236 | /// 237 | /// let reader = lock.read().await; 238 | /// assert_eq!(*reader, 1); 239 | /// 240 | /// assert!(lock.try_read().is_some()); 241 | /// # }) 242 | /// ``` 243 | #[inline] 244 | pub fn read(&self) -> Read<'_, T> { 245 | Read::new(self.raw.read(), self.value.get()) 246 | } 247 | 248 | /// Acquires a read lock. 249 | /// 250 | /// Returns a guard that releases the lock when dropped. 251 | /// 252 | /// Note that attempts to acquire a read lock will block if there are also concurrent attempts 253 | /// to acquire a write lock. 254 | /// 255 | /// # Blocking 256 | /// 257 | /// Rather than using asynchronous waiting, like the [`read`][`RwLock::read`] method, 258 | /// this method will block the current thread until the read lock is acquired. 259 | /// 260 | /// This method should not be used in an asynchronous context. It is intended to be 261 | /// used in a way that a lock can be used in both asynchronous and synchronous contexts. 262 | /// Calling this method in an asynchronous context may result in a deadlock. 263 | /// 264 | /// # Examples 265 | /// 266 | /// ``` 267 | /// use async_lock::RwLock; 268 | /// 269 | /// let lock = RwLock::new(1); 270 | /// 271 | /// let reader = lock.read_blocking(); 272 | /// assert_eq!(*reader, 1); 273 | /// 274 | /// assert!(lock.try_read().is_some()); 275 | /// ``` 276 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 277 | #[inline] 278 | pub fn read_blocking(&self) -> RwLockReadGuard<'_, T> { 279 | self.read().wait() 280 | } 281 | 282 | /// Attempts to acquire a read lock with the possibility to upgrade to a write lock. 283 | /// 284 | /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a 285 | /// guard is returned that releases the lock when dropped. 286 | /// 287 | /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there 288 | /// can be at most one upgradable read lock at a time. 289 | /// 290 | /// # Examples 291 | /// 292 | /// ``` 293 | /// # futures_lite::future::block_on(async { 294 | /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; 295 | /// 296 | /// let lock = RwLock::new(1); 297 | /// 298 | /// let reader = lock.upgradable_read().await; 299 | /// assert_eq!(*reader, 1); 300 | /// assert_eq!(*lock.try_read().unwrap(), 1); 301 | /// 302 | /// let mut writer = RwLockUpgradableReadGuard::upgrade(reader).await; 303 | /// *writer = 2; 304 | /// # }) 305 | /// ``` 306 | #[inline] 307 | pub fn try_upgradable_read(&self) -> Option> { 308 | if self.raw.try_upgradable_read() { 309 | Some(RwLockUpgradableReadGuard { 310 | lock: &self.raw, 311 | value: self.value.get(), 312 | }) 313 | } else { 314 | None 315 | } 316 | } 317 | 318 | /// Acquires a read lock with the possibility to upgrade to a write lock. 319 | /// 320 | /// Returns a guard that releases the lock when dropped. 321 | /// 322 | /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there 323 | /// can be at most one upgradable read lock at a time. 324 | /// 325 | /// Note that attempts to acquire an upgradable read lock will block if there are concurrent 326 | /// attempts to acquire another upgradable read lock or a write lock. 327 | /// 328 | /// # Examples 329 | /// 330 | /// ``` 331 | /// # futures_lite::future::block_on(async { 332 | /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; 333 | /// 334 | /// let lock = RwLock::new(1); 335 | /// 336 | /// let reader = lock.upgradable_read().await; 337 | /// assert_eq!(*reader, 1); 338 | /// assert_eq!(*lock.try_read().unwrap(), 1); 339 | /// 340 | /// let mut writer = RwLockUpgradableReadGuard::upgrade(reader).await; 341 | /// *writer = 2; 342 | /// # }) 343 | /// ``` 344 | #[inline] 345 | pub fn upgradable_read(&self) -> UpgradableRead<'_, T> { 346 | UpgradableRead::new(self.raw.upgradable_read(), self.value.get()) 347 | } 348 | 349 | /// Attempts to acquire a read lock with the possibility to upgrade to a write lock. 350 | /// 351 | /// Returns a guard that releases the lock when dropped. 352 | /// 353 | /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there 354 | /// can be at most one upgradable read lock at a time. 355 | /// 356 | /// Note that attempts to acquire an upgradable read lock will block if there are concurrent 357 | /// attempts to acquire another upgradable read lock or a write lock. 358 | /// 359 | /// # Blocking 360 | /// 361 | /// Rather than using asynchronous waiting, like the [`upgradable_read`][`RwLock::upgradable_read`] 362 | /// method, this method will block the current thread until the read lock is acquired. 363 | /// 364 | /// This method should not be used in an asynchronous context. It is intended to be 365 | /// used in a way that a lock can be used in both asynchronous and synchronous contexts. 366 | /// Calling this method in an asynchronous context may result in a deadlock. 367 | /// 368 | /// # Examples 369 | /// 370 | /// ``` 371 | /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; 372 | /// 373 | /// let lock = RwLock::new(1); 374 | /// 375 | /// let reader = lock.upgradable_read_blocking(); 376 | /// assert_eq!(*reader, 1); 377 | /// assert_eq!(*lock.try_read().unwrap(), 1); 378 | /// 379 | /// let mut writer = RwLockUpgradableReadGuard::upgrade_blocking(reader); 380 | /// *writer = 2; 381 | /// ``` 382 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 383 | #[inline] 384 | pub fn upgradable_read_blocking(&self) -> RwLockUpgradableReadGuard<'_, T> { 385 | self.upgradable_read().wait() 386 | } 387 | 388 | /// Attempts to acquire an owned, reference-counted read lock 389 | /// with the possibility to upgrade to a write lock. 390 | /// 391 | /// Returns a guard that releases the lock when dropped. 392 | /// 393 | /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there 394 | /// can be at most one upgradable read lock at a time. 395 | /// 396 | /// Note that attempts to acquire an upgradable read lock will block if there are concurrent 397 | /// attempts to acquire another upgradable read lock or a write lock. 398 | /// 399 | /// # Blocking 400 | /// 401 | /// Rather than using asynchronous waiting, like the [`upgradable_read_arc`][`RwLock::upgradable_read_arc`] 402 | /// method, this method will block the current thread until the read lock is acquired. 403 | /// 404 | /// This method should not be used in an asynchronous context. It is intended to be 405 | /// used in a way that a lock can be used in both asynchronous and synchronous contexts. 406 | /// Calling this method in an asynchronous context may result in a deadlock. 407 | /// 408 | /// # Examples 409 | /// 410 | /// ``` 411 | /// use std::sync::Arc; 412 | /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; 413 | /// 414 | /// let lock = Arc::new(RwLock::new(1)); 415 | /// 416 | /// let reader = lock.upgradable_read_arc_blocking(); 417 | /// assert_eq!(*reader, 1); 418 | /// assert_eq!(*lock.try_read().unwrap(), 1); 419 | /// 420 | /// let mut writer = RwLockUpgradableReadGuardArc::upgrade_blocking(reader); 421 | /// *writer = 2; 422 | /// ``` 423 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 424 | #[inline] 425 | pub fn upgradable_read_arc_blocking(self: &Arc) -> RwLockUpgradableReadGuardArc { 426 | self.upgradable_read_arc().wait() 427 | } 428 | 429 | /// Attempts to acquire an owned, reference-counted read lock with the possibility to 430 | /// upgrade to a write lock. 431 | /// 432 | /// If a read lock could not be acquired at this time, then [`None`] is returned. Otherwise, a 433 | /// guard is returned that releases the lock when dropped. 434 | /// 435 | /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there 436 | /// can be at most one upgradable read lock at a time. 437 | /// 438 | /// # Examples 439 | /// 440 | /// ``` 441 | /// # futures_lite::future::block_on(async { 442 | /// use std::sync::Arc; 443 | /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; 444 | /// 445 | /// let lock = Arc::new(RwLock::new(1)); 446 | /// 447 | /// let reader = lock.upgradable_read_arc().await; 448 | /// assert_eq!(*reader, 1); 449 | /// assert_eq!(*lock.try_read_arc().unwrap(), 1); 450 | /// 451 | /// let mut writer = RwLockUpgradableReadGuardArc::upgrade(reader).await; 452 | /// *writer = 2; 453 | /// # }) 454 | /// ``` 455 | #[inline] 456 | pub fn try_upgradable_read_arc(self: &Arc) -> Option> { 457 | if self.raw.try_upgradable_read() { 458 | Some(RwLockUpgradableReadGuardArc { lock: self.clone() }) 459 | } else { 460 | None 461 | } 462 | } 463 | 464 | /// Acquires an owned, reference-counted read lock with the possibility 465 | /// to upgrade to a write lock. 466 | /// 467 | /// Returns a guard that releases the lock when dropped. 468 | /// 469 | /// Upgradable read lock reserves the right to be upgraded to a write lock, which means there 470 | /// can be at most one upgradable read lock at a time. 471 | /// 472 | /// Note that attempts to acquire an upgradable read lock will block if there are concurrent 473 | /// attempts to acquire another upgradable read lock or a write lock. 474 | /// 475 | /// # Examples 476 | /// 477 | /// ``` 478 | /// # futures_lite::future::block_on(async { 479 | /// use std::sync::Arc; 480 | /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; 481 | /// 482 | /// let lock = Arc::new(RwLock::new(1)); 483 | /// 484 | /// let reader = lock.upgradable_read_arc().await; 485 | /// assert_eq!(*reader, 1); 486 | /// assert_eq!(*lock.try_read_arc().unwrap(), 1); 487 | /// 488 | /// let mut writer = RwLockUpgradableReadGuardArc::upgrade(reader).await; 489 | /// *writer = 2; 490 | /// # }) 491 | /// ``` 492 | #[inline] 493 | pub fn upgradable_read_arc<'a>(self: &'a Arc) -> UpgradableReadArc<'a, T> { 494 | UpgradableReadArc::new(self.raw.upgradable_read(), self) 495 | } 496 | 497 | /// Attempts to acquire a write lock. 498 | /// 499 | /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, a 500 | /// guard is returned that releases the lock when dropped. 501 | /// 502 | /// # Examples 503 | /// 504 | /// ``` 505 | /// # futures_lite::future::block_on(async { 506 | /// use async_lock::RwLock; 507 | /// 508 | /// let lock = RwLock::new(1); 509 | /// 510 | /// assert!(lock.try_write().is_some()); 511 | /// let reader = lock.read().await; 512 | /// assert!(lock.try_write().is_none()); 513 | /// # }) 514 | /// ``` 515 | #[inline] 516 | pub fn try_write(&self) -> Option> { 517 | if self.raw.try_write() { 518 | Some(RwLockWriteGuard { 519 | lock: &self.raw, 520 | value: self.value.get(), 521 | }) 522 | } else { 523 | None 524 | } 525 | } 526 | 527 | /// Acquires a write lock. 528 | /// 529 | /// Returns a guard that releases the lock when dropped. 530 | /// 531 | /// # Examples 532 | /// 533 | /// ``` 534 | /// # futures_lite::future::block_on(async { 535 | /// use async_lock::RwLock; 536 | /// 537 | /// let lock = RwLock::new(1); 538 | /// 539 | /// let writer = lock.write().await; 540 | /// assert!(lock.try_read().is_none()); 541 | /// # }) 542 | /// ``` 543 | #[inline] 544 | pub fn write(&self) -> Write<'_, T> { 545 | Write::new(self.raw.write(), self.value.get()) 546 | } 547 | 548 | /// Acquires a write lock. 549 | /// 550 | /// Returns a guard that releases the lock when dropped. 551 | /// 552 | /// # Blocking 553 | /// 554 | /// Rather than using asynchronous waiting, like the [`write`] method, this method will 555 | /// block the current thread until the write lock is acquired. 556 | /// 557 | /// This method should not be used in an asynchronous context. It is intended to be 558 | /// used in a way that a lock can be used in both asynchronous and synchronous contexts. 559 | /// Calling this method in an asynchronous context may result in a deadlock. 560 | /// 561 | /// # Examples 562 | /// 563 | /// ``` 564 | /// use async_lock::RwLock; 565 | /// 566 | /// let lock = RwLock::new(1); 567 | /// 568 | /// let writer = lock.write_blocking(); 569 | /// assert!(lock.try_read().is_none()); 570 | /// ``` 571 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 572 | #[inline] 573 | pub fn write_blocking(&self) -> RwLockWriteGuard<'_, T> { 574 | self.write().wait() 575 | } 576 | 577 | /// Attempts to acquire an owned, reference-counted write lock. 578 | /// 579 | /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, a 580 | /// guard is returned that releases the lock when dropped. 581 | /// 582 | /// # Examples 583 | /// 584 | /// ``` 585 | /// # futures_lite::future::block_on(async { 586 | /// use std::sync::Arc; 587 | /// use async_lock::RwLock; 588 | /// 589 | /// let lock = Arc::new(RwLock::new(1)); 590 | /// 591 | /// assert!(lock.try_write_arc().is_some()); 592 | /// let reader = lock.read_arc().await; 593 | /// assert!(lock.try_write_arc().is_none()); 594 | /// # }) 595 | /// ``` 596 | #[inline] 597 | pub fn try_write_arc(self: &Arc) -> Option> { 598 | if self.raw.try_write() { 599 | Some(RwLockWriteGuardArc { lock: self.clone() }) 600 | } else { 601 | None 602 | } 603 | } 604 | 605 | /// Acquires an owned, reference-counted write lock. 606 | /// 607 | /// Returns a guard that releases the lock when dropped. 608 | /// 609 | /// # Examples 610 | /// 611 | /// ``` 612 | /// # futures_lite::future::block_on(async { 613 | /// use std::sync::Arc; 614 | /// use async_lock::RwLock; 615 | /// 616 | /// let lock = Arc::new(RwLock::new(1)); 617 | /// 618 | /// let writer = lock.write_arc().await; 619 | /// assert!(lock.try_read_arc().is_none()); 620 | /// # }) 621 | /// ``` 622 | #[inline] 623 | pub fn write_arc<'a>(self: &'a Arc) -> WriteArc<'a, T> { 624 | WriteArc::new(self.raw.write(), self) 625 | } 626 | 627 | /// Acquires an owned, reference-counted write lock. 628 | /// 629 | /// Returns a guard that releases the lock when dropped. 630 | /// 631 | /// # Blocking 632 | /// 633 | /// Rather than using asynchronous waiting, like the [`write_arc`][RwLock::write_arc] method, this method will 634 | /// block the current thread until the write lock is acquired. 635 | /// 636 | /// This method should not be used in an asynchronous context. It is intended to be 637 | /// used in a way that a lock can be used in both asynchronous and synchronous contexts. 638 | /// Calling this method in an asynchronous context may result in a deadlock. 639 | /// 640 | /// # Examples 641 | /// 642 | /// ``` 643 | /// use std::sync::Arc; 644 | /// use async_lock::RwLock; 645 | /// 646 | /// let lock = Arc::new(RwLock::new(1)); 647 | /// 648 | /// let writer = lock.write_arc_blocking(); 649 | /// assert!(lock.try_read().is_none()); 650 | /// ``` 651 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 652 | #[inline] 653 | pub fn write_arc_blocking(self: &Arc) -> RwLockWriteGuardArc { 654 | self.write_arc().wait() 655 | } 656 | 657 | /// Returns a mutable reference to the inner value. 658 | /// 659 | /// Since this call borrows the lock mutably, no actual locking takes place. The mutable borrow 660 | /// statically guarantees no locks exist. 661 | /// 662 | /// # Examples 663 | /// 664 | /// ``` 665 | /// # futures_lite::future::block_on(async { 666 | /// use async_lock::RwLock; 667 | /// 668 | /// let mut lock = RwLock::new(1); 669 | /// 670 | /// *lock.get_mut() = 2; 671 | /// assert_eq!(*lock.read().await, 2); 672 | /// # }) 673 | /// ``` 674 | #[must_use] 675 | #[inline] 676 | pub fn get_mut(&mut self) -> &mut T { 677 | unsafe { &mut *self.value.get() } 678 | } 679 | } 680 | 681 | impl fmt::Debug for RwLock { 682 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 683 | struct Locked; 684 | impl fmt::Debug for Locked { 685 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 686 | f.write_str("") 687 | } 688 | } 689 | 690 | match self.try_read() { 691 | None => f.debug_struct("RwLock").field("value", &Locked).finish(), 692 | Some(guard) => f.debug_struct("RwLock").field("value", &&*guard).finish(), 693 | } 694 | } 695 | } 696 | 697 | impl From for RwLock { 698 | #[inline] 699 | fn from(val: T) -> RwLock { 700 | RwLock::new(val) 701 | } 702 | } 703 | 704 | impl Default for RwLock { 705 | #[inline] 706 | fn default() -> RwLock { 707 | RwLock::new(Default::default()) 708 | } 709 | } 710 | 711 | /// A guard that releases the read lock when dropped. 712 | #[clippy::has_significant_drop] 713 | pub struct RwLockReadGuard<'a, T: ?Sized> { 714 | /// Reference to underlying locking implementation. 715 | /// Doesn't depend on `T`. 716 | lock: &'a RawRwLock, 717 | 718 | /// Pointer to the value protected by the lock. Covariant in `T`. 719 | value: *const T, 720 | } 721 | 722 | unsafe impl Send for RwLockReadGuard<'_, T> {} 723 | unsafe impl Sync for RwLockReadGuard<'_, T> {} 724 | 725 | impl Drop for RwLockReadGuard<'_, T> { 726 | #[inline] 727 | fn drop(&mut self) { 728 | // SAFETY: we are dropping a read guard. 729 | unsafe { 730 | self.lock.read_unlock(); 731 | } 732 | } 733 | } 734 | 735 | impl fmt::Debug for RwLockReadGuard<'_, T> { 736 | #[inline] 737 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 738 | fmt::Debug::fmt(&**self, f) 739 | } 740 | } 741 | 742 | impl fmt::Display for RwLockReadGuard<'_, T> { 743 | #[inline] 744 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 745 | (**self).fmt(f) 746 | } 747 | } 748 | 749 | impl Deref for RwLockReadGuard<'_, T> { 750 | type Target = T; 751 | 752 | #[inline] 753 | fn deref(&self) -> &T { 754 | unsafe { &*self.value } 755 | } 756 | } 757 | 758 | /// An owned, reference-counting guard that releases the read lock when dropped. 759 | #[clippy::has_significant_drop] 760 | pub struct RwLockReadGuardArc { 761 | /// **WARNING**: This doesn't actually point to a `T`! 762 | /// It points to a `RwLock`, via a pointer obtained with `Arc::into_raw`. 763 | /// We lie for covariance. 764 | lock: NonNull, 765 | } 766 | 767 | unsafe impl Send for RwLockReadGuardArc {} 768 | unsafe impl Sync for RwLockReadGuardArc {} 769 | 770 | impl RwLockReadGuardArc { 771 | /// Constructs the underlying `Arc` back from the underlying `RwLock`. 772 | /// 773 | /// # Safety 774 | /// 775 | /// Both the returned `Arc` and the guard will decrement their reference 776 | /// counts on drop! So one of the two must be forgotten. 777 | #[inline] 778 | unsafe fn inner_arc(guard: &Self) -> ManuallyDrop>> { 779 | ManuallyDrop::new(Arc::from_raw(guard.lock.as_ptr().cast())) 780 | } 781 | 782 | /// Constructs a guard from the underlying `Arc`. 783 | /// 784 | /// # Safety 785 | /// 786 | /// A read lock must be acquired before calling this. 787 | #[inline] 788 | unsafe fn from_arc(arc: Arc>) -> Self { 789 | let ptr = Arc::into_raw(arc); 790 | 791 | Self { 792 | lock: NonNull::new(ptr as *mut RwLock as *mut T).unwrap(), 793 | } 794 | } 795 | } 796 | 797 | impl Drop for RwLockReadGuardArc { 798 | #[inline] 799 | fn drop(&mut self) { 800 | // SAFETY: we are in `drop`, decrementing the reference count 801 | // on purpose. 802 | // We hold a read lock on the `RwLock`. 803 | unsafe { 804 | let arc = ManuallyDrop::into_inner(Self::inner_arc(self)); 805 | arc.raw.read_unlock(); 806 | } 807 | } 808 | } 809 | 810 | impl fmt::Debug for RwLockReadGuardArc { 811 | #[inline] 812 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 813 | fmt::Debug::fmt(&**self, f) 814 | } 815 | } 816 | 817 | impl fmt::Display for RwLockReadGuardArc { 818 | #[inline] 819 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 820 | (**self).fmt(f) 821 | } 822 | } 823 | 824 | impl Deref for RwLockReadGuardArc { 825 | type Target = T; 826 | 827 | #[inline] 828 | fn deref(&self) -> &T { 829 | // SAFETY: we use `ManuallyDrop` to avoid double-drop. 830 | // We hold a read lock on the `RwLock`. 831 | unsafe { 832 | let arc = Self::inner_arc(self); 833 | &*arc.value.get() 834 | } 835 | } 836 | } 837 | 838 | /// A guard that releases the upgradable read lock when dropped. 839 | #[clippy::has_significant_drop] 840 | pub struct RwLockUpgradableReadGuard<'a, T: ?Sized> { 841 | /// Reference to underlying locking implementation. 842 | /// Doesn't depend on `T`. 843 | /// This guard holds a lock on the witer mutex! 844 | lock: &'a RawRwLock, 845 | 846 | /// Pointer to the value protected by the lock. Invariant in `T` 847 | /// as the upgradable lock could provide write access. 848 | value: *mut T, 849 | } 850 | 851 | impl Drop for RwLockUpgradableReadGuard<'_, T> { 852 | #[inline] 853 | fn drop(&mut self) { 854 | // SAFETY: we are dropping an upgradable read guard. 855 | unsafe { 856 | self.lock.upgradable_read_unlock(); 857 | } 858 | } 859 | } 860 | 861 | unsafe impl Send for RwLockUpgradableReadGuard<'_, T> {} 862 | unsafe impl Sync for RwLockUpgradableReadGuard<'_, T> {} 863 | 864 | impl<'a, T: ?Sized> RwLockUpgradableReadGuard<'a, T> { 865 | /// Downgrades into a regular reader guard. 866 | /// 867 | /// # Examples 868 | /// 869 | /// ``` 870 | /// # futures_lite::future::block_on(async { 871 | /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; 872 | /// 873 | /// let lock = RwLock::new(1); 874 | /// 875 | /// let reader = lock.upgradable_read().await; 876 | /// assert_eq!(*reader, 1); 877 | /// 878 | /// assert!(lock.try_upgradable_read().is_none()); 879 | /// 880 | /// let reader = RwLockUpgradableReadGuard::downgrade(reader); 881 | /// 882 | /// assert!(lock.try_upgradable_read().is_some()); 883 | /// # }) 884 | /// ``` 885 | #[inline] 886 | pub fn downgrade(guard: Self) -> RwLockReadGuard<'a, T> { 887 | let upgradable = ManuallyDrop::new(guard); 888 | 889 | // SAFETY: `guard` is an upgradable read lock. 890 | unsafe { 891 | upgradable.lock.downgrade_upgradable_read(); 892 | }; 893 | 894 | RwLockReadGuard { 895 | lock: upgradable.lock, 896 | value: upgradable.value, 897 | } 898 | } 899 | 900 | /// Attempts to upgrade into a write lock. 901 | /// 902 | /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, 903 | /// an upgraded guard is returned that releases the write lock when dropped. 904 | /// 905 | /// This function can only fail if there are other active read locks. 906 | /// 907 | /// # Examples 908 | /// 909 | /// ``` 910 | /// # futures_lite::future::block_on(async { 911 | /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; 912 | /// 913 | /// let lock = RwLock::new(1); 914 | /// 915 | /// let reader = lock.upgradable_read().await; 916 | /// assert_eq!(*reader, 1); 917 | /// 918 | /// let reader2 = lock.read().await; 919 | /// let reader = RwLockUpgradableReadGuard::try_upgrade(reader).unwrap_err(); 920 | /// 921 | /// drop(reader2); 922 | /// let writer = RwLockUpgradableReadGuard::try_upgrade(reader).unwrap(); 923 | /// # }) 924 | /// ``` 925 | #[inline] 926 | pub fn try_upgrade(guard: Self) -> Result, Self> { 927 | // If there are no readers, grab the write lock. 928 | // SAFETY: `guard` is an upgradable read guard 929 | if unsafe { guard.lock.try_upgrade() } { 930 | let reader = ManuallyDrop::new(guard); 931 | 932 | Ok(RwLockWriteGuard { 933 | lock: reader.lock, 934 | value: reader.value, 935 | }) 936 | } else { 937 | Err(guard) 938 | } 939 | } 940 | 941 | /// Upgrades into a write lock. 942 | /// 943 | /// # Examples 944 | /// 945 | /// ``` 946 | /// # futures_lite::future::block_on(async { 947 | /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; 948 | /// 949 | /// let lock = RwLock::new(1); 950 | /// 951 | /// let reader = lock.upgradable_read().await; 952 | /// assert_eq!(*reader, 1); 953 | /// 954 | /// let mut writer = RwLockUpgradableReadGuard::upgrade(reader).await; 955 | /// *writer = 2; 956 | /// # }) 957 | /// ``` 958 | #[inline] 959 | pub fn upgrade(guard: Self) -> Upgrade<'a, T> { 960 | let reader = ManuallyDrop::new(guard); 961 | 962 | Upgrade::new( 963 | // SAFETY: `reader` is an upgradable read guard 964 | unsafe { reader.lock.upgrade() }, 965 | reader.value, 966 | ) 967 | } 968 | 969 | /// Upgrades into a write lock. 970 | /// 971 | /// # Blocking 972 | /// 973 | /// This function will block the current thread until it is able to acquire the write lock. 974 | /// 975 | /// # Examples 976 | /// 977 | /// ``` 978 | /// use async_lock::{RwLock, RwLockUpgradableReadGuard}; 979 | /// 980 | /// let lock = RwLock::new(1); 981 | /// 982 | /// let reader = lock.upgradable_read_blocking(); 983 | /// assert_eq!(*reader, 1); 984 | /// 985 | /// let mut writer = RwLockUpgradableReadGuard::upgrade_blocking(reader); 986 | /// *writer = 2; 987 | /// ``` 988 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 989 | #[inline] 990 | pub fn upgrade_blocking(guard: Self) -> RwLockWriteGuard<'a, T> { 991 | RwLockUpgradableReadGuard::upgrade(guard).wait() 992 | } 993 | } 994 | 995 | impl fmt::Debug for RwLockUpgradableReadGuard<'_, T> { 996 | #[inline] 997 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 998 | fmt::Debug::fmt(&**self, f) 999 | } 1000 | } 1001 | 1002 | impl fmt::Display for RwLockUpgradableReadGuard<'_, T> { 1003 | #[inline] 1004 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1005 | (**self).fmt(f) 1006 | } 1007 | } 1008 | 1009 | impl Deref for RwLockUpgradableReadGuard<'_, T> { 1010 | type Target = T; 1011 | 1012 | #[inline] 1013 | fn deref(&self) -> &T { 1014 | unsafe { &*self.value } 1015 | } 1016 | } 1017 | 1018 | /// An owned, reference-counting guard that releases the upgradable read lock when dropped. 1019 | #[clippy::has_significant_drop] 1020 | pub struct RwLockUpgradableReadGuardArc { 1021 | /// We want invariance, so no need for pointer tricks. 1022 | lock: Arc>, 1023 | } 1024 | 1025 | impl Drop for RwLockUpgradableReadGuardArc { 1026 | #[inline] 1027 | fn drop(&mut self) { 1028 | // SAFETY: we are dropping an upgradable read guard. 1029 | unsafe { 1030 | self.lock.raw.upgradable_read_unlock(); 1031 | } 1032 | } 1033 | } 1034 | 1035 | unsafe impl Send for RwLockUpgradableReadGuardArc {} 1036 | unsafe impl Sync for RwLockUpgradableReadGuardArc {} 1037 | 1038 | impl fmt::Debug for RwLockUpgradableReadGuardArc { 1039 | #[inline] 1040 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1041 | fmt::Debug::fmt(&**self, f) 1042 | } 1043 | } 1044 | 1045 | impl fmt::Display for RwLockUpgradableReadGuardArc { 1046 | #[inline] 1047 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1048 | (**self).fmt(f) 1049 | } 1050 | } 1051 | 1052 | impl Deref for RwLockUpgradableReadGuardArc { 1053 | type Target = T; 1054 | 1055 | #[inline] 1056 | fn deref(&self) -> &T { 1057 | unsafe { &*self.lock.value.get() } 1058 | } 1059 | } 1060 | 1061 | impl RwLockUpgradableReadGuardArc { 1062 | /// Downgrades into a regular reader guard. 1063 | /// 1064 | /// # Examples 1065 | /// 1066 | /// ``` 1067 | /// # futures_lite::future::block_on(async { 1068 | /// use std::sync::Arc; 1069 | /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; 1070 | /// 1071 | /// let lock = Arc::new(RwLock::new(1)); 1072 | /// 1073 | /// let reader = lock.upgradable_read_arc().await; 1074 | /// assert_eq!(*reader, 1); 1075 | /// 1076 | /// assert!(lock.try_upgradable_read_arc().is_none()); 1077 | /// 1078 | /// let reader = RwLockUpgradableReadGuardArc::downgrade(reader); 1079 | /// 1080 | /// assert!(lock.try_upgradable_read_arc().is_some()); 1081 | /// # }) 1082 | /// ``` 1083 | #[inline] 1084 | pub fn downgrade(guard: Self) -> RwLockReadGuardArc { 1085 | // SAFETY: we hold an upgradable read lock, which we are downgrading. 1086 | unsafe { 1087 | guard.lock.raw.downgrade_upgradable_read(); 1088 | } 1089 | 1090 | // SAFETY: we just downgraded to a read lock. 1091 | unsafe { RwLockReadGuardArc::from_arc(Self::into_arc(guard)) } 1092 | } 1093 | } 1094 | 1095 | impl RwLockUpgradableReadGuardArc { 1096 | /// Consumes the lock (without dropping) and returns the underlying `Arc`. 1097 | #[inline] 1098 | fn into_arc(guard: Self) -> Arc> { 1099 | let guard = ManuallyDrop::new(guard); 1100 | // SAFETY: `guard` is not used after this 1101 | unsafe { ptr::read(&guard.lock) } 1102 | } 1103 | 1104 | /// Attempts to upgrade into a write lock. 1105 | /// 1106 | /// If a write lock could not be acquired at this time, then [`None`] is returned. Otherwise, 1107 | /// an upgraded guard is returned that releases the write lock when dropped. 1108 | /// 1109 | /// This function can only fail if there are other active read locks. 1110 | /// 1111 | /// # Examples 1112 | /// 1113 | /// ``` 1114 | /// # futures_lite::future::block_on(async { 1115 | /// use std::sync::Arc; 1116 | /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; 1117 | /// 1118 | /// let lock = Arc::new(RwLock::new(1)); 1119 | /// 1120 | /// let reader = lock.upgradable_read_arc().await; 1121 | /// assert_eq!(*reader, 1); 1122 | /// 1123 | /// let reader2 = lock.read_arc().await; 1124 | /// let reader = RwLockUpgradableReadGuardArc::try_upgrade(reader).unwrap_err(); 1125 | /// 1126 | /// drop(reader2); 1127 | /// let writer = RwLockUpgradableReadGuardArc::try_upgrade(reader).unwrap(); 1128 | /// # }) 1129 | /// ``` 1130 | #[inline] 1131 | pub fn try_upgrade(guard: Self) -> Result, Self> { 1132 | // SAFETY: We hold an upgradable read guard. 1133 | if unsafe { guard.lock.raw.try_upgrade() } { 1134 | Ok(RwLockWriteGuardArc { 1135 | lock: Self::into_arc(guard), 1136 | }) 1137 | } else { 1138 | Err(guard) 1139 | } 1140 | } 1141 | 1142 | /// Upgrades into a write lock. 1143 | /// 1144 | /// # Examples 1145 | /// 1146 | /// ``` 1147 | /// # futures_lite::future::block_on(async { 1148 | /// use std::sync::Arc; 1149 | /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; 1150 | /// 1151 | /// let lock = Arc::new(RwLock::new(1)); 1152 | /// 1153 | /// let reader = lock.upgradable_read_arc().await; 1154 | /// assert_eq!(*reader, 1); 1155 | /// 1156 | /// let mut writer = RwLockUpgradableReadGuardArc::upgrade(reader).await; 1157 | /// *writer = 2; 1158 | /// # }) 1159 | /// ``` 1160 | #[inline] 1161 | pub fn upgrade(guard: Self) -> UpgradeArc { 1162 | // We need to do some ugly lying about lifetimes; 1163 | // See the comment on the `raw` field of `ArcUpgrade` 1164 | // for an explanation. 1165 | 1166 | // SAFETY: we hold an upgradable read guard. 1167 | let raw: RawUpgrade<'_> = unsafe { guard.lock.raw.upgrade() }; 1168 | 1169 | // SAFETY: see above explanation. 1170 | let raw: RawUpgrade<'static> = unsafe { mem::transmute(raw) }; 1171 | 1172 | unsafe { 1173 | UpgradeArc::new( 1174 | ManuallyDrop::new(raw), 1175 | ManuallyDrop::new(Self::into_arc(guard)), 1176 | ) 1177 | } 1178 | } 1179 | 1180 | /// Upgrades into a write lock. 1181 | /// 1182 | /// # Blocking 1183 | /// 1184 | /// This function will block the current thread until it is able to acquire the write lock. 1185 | /// 1186 | /// # Examples 1187 | /// 1188 | /// ``` 1189 | /// use std::sync::Arc; 1190 | /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc}; 1191 | /// 1192 | /// let lock = Arc::new(RwLock::new(1)); 1193 | /// 1194 | /// let reader = lock.upgradable_read_arc_blocking(); 1195 | /// assert_eq!(*reader, 1); 1196 | /// 1197 | /// let mut writer = RwLockUpgradableReadGuardArc::upgrade_blocking(reader); 1198 | /// *writer = 2; 1199 | /// ``` 1200 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 1201 | #[inline] 1202 | pub fn upgrade_blocking(guard: Self) -> RwLockWriteGuardArc { 1203 | RwLockUpgradableReadGuardArc::upgrade(guard).wait() 1204 | } 1205 | } 1206 | 1207 | /// A guard that releases the write lock when dropped. 1208 | #[clippy::has_significant_drop] 1209 | pub struct RwLockWriteGuard<'a, T: ?Sized> { 1210 | /// Reference to underlying locking implementation. 1211 | /// Doesn't depend on `T`. 1212 | /// This guard holds a lock on the witer mutex! 1213 | lock: &'a RawRwLock, 1214 | 1215 | /// Pointer to the value protected by the lock. Invariant in `T`. 1216 | value: *mut T, 1217 | } 1218 | 1219 | unsafe impl Send for RwLockWriteGuard<'_, T> {} 1220 | unsafe impl Sync for RwLockWriteGuard<'_, T> {} 1221 | 1222 | impl Drop for RwLockWriteGuard<'_, T> { 1223 | #[inline] 1224 | fn drop(&mut self) { 1225 | // SAFETY: we are dropping a write lock 1226 | unsafe { 1227 | self.lock.write_unlock(); 1228 | } 1229 | } 1230 | } 1231 | 1232 | impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { 1233 | /// Downgrades into a regular reader guard. 1234 | /// 1235 | /// # Examples 1236 | /// 1237 | /// ``` 1238 | /// # futures_lite::future::block_on(async { 1239 | /// use async_lock::{RwLock, RwLockWriteGuard}; 1240 | /// 1241 | /// let lock = RwLock::new(1); 1242 | /// 1243 | /// let mut writer = lock.write().await; 1244 | /// *writer += 1; 1245 | /// 1246 | /// assert!(lock.try_read().is_none()); 1247 | /// 1248 | /// let reader = RwLockWriteGuard::downgrade(writer); 1249 | /// assert_eq!(*reader, 2); 1250 | /// 1251 | /// assert!(lock.try_read().is_some()); 1252 | /// # }) 1253 | /// ``` 1254 | #[inline] 1255 | pub fn downgrade(guard: Self) -> RwLockReadGuard<'a, T> { 1256 | let write = ManuallyDrop::new(guard); 1257 | 1258 | // SAFETY: `write` is a write guard 1259 | unsafe { 1260 | write.lock.downgrade_write(); 1261 | } 1262 | 1263 | RwLockReadGuard { 1264 | lock: write.lock, 1265 | value: write.value, 1266 | } 1267 | } 1268 | 1269 | /// Downgrades into an upgradable reader guard. 1270 | /// 1271 | /// # Examples 1272 | /// 1273 | /// ``` 1274 | /// # futures_lite::future::block_on(async { 1275 | /// use async_lock::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard}; 1276 | /// 1277 | /// let lock = RwLock::new(1); 1278 | /// 1279 | /// let mut writer = lock.write().await; 1280 | /// *writer += 1; 1281 | /// 1282 | /// assert!(lock.try_read().is_none()); 1283 | /// 1284 | /// let reader = RwLockWriteGuard::downgrade_to_upgradable(writer); 1285 | /// assert_eq!(*reader, 2); 1286 | /// 1287 | /// assert!(lock.try_write().is_none()); 1288 | /// assert!(lock.try_read().is_some()); 1289 | /// 1290 | /// assert!(RwLockUpgradableReadGuard::try_upgrade(reader).is_ok()) 1291 | /// # }) 1292 | /// ``` 1293 | #[inline] 1294 | pub fn downgrade_to_upgradable(guard: Self) -> RwLockUpgradableReadGuard<'a, T> { 1295 | let write = ManuallyDrop::new(guard); 1296 | 1297 | // SAFETY: `write` is a write guard 1298 | unsafe { 1299 | write.lock.downgrade_to_upgradable(); 1300 | } 1301 | 1302 | RwLockUpgradableReadGuard { 1303 | lock: write.lock, 1304 | value: write.value, 1305 | } 1306 | } 1307 | } 1308 | 1309 | impl fmt::Debug for RwLockWriteGuard<'_, T> { 1310 | #[inline] 1311 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1312 | fmt::Debug::fmt(&**self, f) 1313 | } 1314 | } 1315 | 1316 | impl fmt::Display for RwLockWriteGuard<'_, T> { 1317 | #[inline] 1318 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1319 | (**self).fmt(f) 1320 | } 1321 | } 1322 | 1323 | impl Deref for RwLockWriteGuard<'_, T> { 1324 | type Target = T; 1325 | 1326 | #[inline] 1327 | fn deref(&self) -> &T { 1328 | unsafe { &*self.value } 1329 | } 1330 | } 1331 | 1332 | impl DerefMut for RwLockWriteGuard<'_, T> { 1333 | #[inline] 1334 | fn deref_mut(&mut self) -> &mut T { 1335 | unsafe { &mut *self.value } 1336 | } 1337 | } 1338 | 1339 | /// An owned, reference-counted guard that releases the write lock when dropped. 1340 | #[clippy::has_significant_drop] 1341 | pub struct RwLockWriteGuardArc { 1342 | lock: Arc>, 1343 | } 1344 | 1345 | unsafe impl Send for RwLockWriteGuardArc {} 1346 | unsafe impl Sync for RwLockWriteGuardArc {} 1347 | 1348 | impl Drop for RwLockWriteGuardArc { 1349 | #[inline] 1350 | fn drop(&mut self) { 1351 | // SAFETY: we are dropping a write lock. 1352 | unsafe { 1353 | self.lock.raw.write_unlock(); 1354 | } 1355 | } 1356 | } 1357 | 1358 | impl RwLockWriteGuardArc { 1359 | /// Downgrades into a regular reader guard. 1360 | /// 1361 | /// # Examples 1362 | /// 1363 | /// ``` 1364 | /// # futures_lite::future::block_on(async { 1365 | /// use std::sync::Arc; 1366 | /// use async_lock::{RwLock, RwLockWriteGuardArc}; 1367 | /// 1368 | /// let lock = Arc::new(RwLock::new(1)); 1369 | /// 1370 | /// let mut writer = lock.write_arc().await; 1371 | /// *writer += 1; 1372 | /// 1373 | /// assert!(lock.try_read_arc().is_none()); 1374 | /// 1375 | /// let reader = RwLockWriteGuardArc::downgrade(writer); 1376 | /// assert_eq!(*reader, 2); 1377 | /// 1378 | /// assert!(lock.try_read_arc().is_some()); 1379 | /// # }) 1380 | /// ``` 1381 | #[inline] 1382 | pub fn downgrade(guard: Self) -> RwLockReadGuardArc { 1383 | // SAFETY: `write` is a write guard 1384 | unsafe { 1385 | guard.lock.raw.downgrade_write(); 1386 | } 1387 | 1388 | // SAFETY: we just downgraded to a read lock 1389 | unsafe { RwLockReadGuardArc::from_arc(Self::into_arc(guard)) } 1390 | } 1391 | } 1392 | 1393 | impl RwLockWriteGuardArc { 1394 | /// Consumes the lock (without dropping) and returns the underlying `Arc`. 1395 | #[inline] 1396 | fn into_arc(guard: Self) -> Arc> { 1397 | let guard = ManuallyDrop::new(guard); 1398 | // SAFETY: `guard` is not used after this 1399 | unsafe { ptr::read(&guard.lock) } 1400 | } 1401 | 1402 | /// Downgrades into an upgradable reader guard. 1403 | /// 1404 | /// # Examples 1405 | /// 1406 | /// ``` 1407 | /// # futures_lite::future::block_on(async { 1408 | /// use std::sync::Arc; 1409 | /// use async_lock::{RwLock, RwLockUpgradableReadGuardArc, RwLockWriteGuardArc}; 1410 | /// 1411 | /// let lock = Arc::new(RwLock::new(1)); 1412 | /// 1413 | /// let mut writer = lock.write_arc().await; 1414 | /// *writer += 1; 1415 | /// 1416 | /// assert!(lock.try_read_arc().is_none()); 1417 | /// 1418 | /// let reader = RwLockWriteGuardArc::downgrade_to_upgradable(writer); 1419 | /// assert_eq!(*reader, 2); 1420 | /// 1421 | /// assert!(lock.try_write_arc().is_none()); 1422 | /// assert!(lock.try_read_arc().is_some()); 1423 | /// 1424 | /// assert!(RwLockUpgradableReadGuardArc::try_upgrade(reader).is_ok()) 1425 | /// # }) 1426 | /// ``` 1427 | #[inline] 1428 | pub fn downgrade_to_upgradable(guard: Self) -> RwLockUpgradableReadGuardArc { 1429 | // SAFETY: `guard` is a write guard 1430 | unsafe { 1431 | guard.lock.raw.downgrade_to_upgradable(); 1432 | } 1433 | 1434 | RwLockUpgradableReadGuardArc { 1435 | lock: Self::into_arc(guard), 1436 | } 1437 | } 1438 | } 1439 | 1440 | impl fmt::Debug for RwLockWriteGuardArc { 1441 | #[inline] 1442 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1443 | fmt::Debug::fmt(&**self, f) 1444 | } 1445 | } 1446 | 1447 | impl fmt::Display for RwLockWriteGuardArc { 1448 | #[inline] 1449 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1450 | (**self).fmt(f) 1451 | } 1452 | } 1453 | 1454 | impl Deref for RwLockWriteGuardArc { 1455 | type Target = T; 1456 | 1457 | #[inline] 1458 | fn deref(&self) -> &T { 1459 | unsafe { &*self.lock.value.get() } 1460 | } 1461 | } 1462 | 1463 | impl DerefMut for RwLockWriteGuardArc { 1464 | #[inline] 1465 | fn deref_mut(&mut self) -> &mut T { 1466 | unsafe { &mut *self.lock.value.get() } 1467 | } 1468 | } 1469 | -------------------------------------------------------------------------------- /src/rwlock/futures.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | use core::mem::ManuallyDrop; 3 | use core::pin::Pin; 4 | use core::task::Poll; 5 | 6 | use alloc::sync::Arc; 7 | 8 | use super::raw::{RawRead, RawUpgradableRead, RawUpgrade, RawWrite}; 9 | use super::{ 10 | RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard, 11 | RwLockUpgradableReadGuardArc, RwLockWriteGuard, RwLockWriteGuardArc, 12 | }; 13 | 14 | use event_listener_strategy::{easy_wrapper, EventListenerFuture, Strategy}; 15 | 16 | easy_wrapper! { 17 | /// The future returned by [`RwLock::read`]. 18 | pub struct Read<'a, T: ?Sized>(ReadInner<'a, T> => RwLockReadGuard<'a, T>); 19 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 20 | pub(crate) wait(); 21 | } 22 | 23 | pin_project_lite::pin_project! { 24 | /// The future returned by [`RwLock::read`]. 25 | struct ReadInner<'a, T: ?Sized> { 26 | // Raw read lock acquisition future, doesn't depend on `T`. 27 | #[pin] 28 | pub(super) raw: RawRead<'a>, 29 | 30 | // Pointer to the value protected by the lock. Covariant in `T`. 31 | pub(super) value: *const T, 32 | } 33 | } 34 | 35 | unsafe impl Send for ReadInner<'_, T> {} 36 | unsafe impl Sync for ReadInner<'_, T> {} 37 | 38 | impl<'x, T: ?Sized> Read<'x, T> { 39 | #[inline] 40 | pub(super) fn new(raw: RawRead<'x>, value: *const T) -> Self { 41 | Self::_new(ReadInner { raw, value }) 42 | } 43 | } 44 | 45 | impl fmt::Debug for Read<'_, T> { 46 | #[inline] 47 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 48 | f.write_str("Read { .. }") 49 | } 50 | } 51 | 52 | impl<'a, T: ?Sized> EventListenerFuture for ReadInner<'a, T> { 53 | type Output = RwLockReadGuard<'a, T>; 54 | 55 | #[inline] 56 | fn poll_with_strategy<'x, S: Strategy<'x>>( 57 | self: Pin<&mut Self>, 58 | strategy: &mut S, 59 | cx: &mut S::Context, 60 | ) -> Poll { 61 | let mut this = self.project(); 62 | ready!(this.raw.as_mut().poll_with_strategy(strategy, cx)); 63 | 64 | Poll::Ready(RwLockReadGuard { 65 | lock: this.raw.lock, 66 | value: *this.value, 67 | }) 68 | } 69 | } 70 | 71 | easy_wrapper! { 72 | /// The future returned by [`RwLock::read_arc`]. 73 | pub struct ReadArc<'a, T>(ReadArcInner<'a, T> => RwLockReadGuardArc); 74 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 75 | pub(crate) wait(); 76 | } 77 | 78 | pin_project_lite::pin_project! { 79 | /// The future returned by [`RwLock::read_arc`]. 80 | struct ReadArcInner<'a, T> { 81 | // Raw read lock acquisition future, doesn't depend on `T`. 82 | #[pin] 83 | pub(super) raw: RawRead<'a>, 84 | 85 | // FIXME: Could be covariant in T 86 | pub(super) lock: &'a Arc>, 87 | } 88 | } 89 | 90 | unsafe impl Send for ReadArcInner<'_, T> {} 91 | unsafe impl Sync for ReadArcInner<'_, T> {} 92 | 93 | impl<'x, T> ReadArc<'x, T> { 94 | #[inline] 95 | pub(super) fn new(raw: RawRead<'x>, lock: &'x Arc>) -> Self { 96 | Self::_new(ReadArcInner { raw, lock }) 97 | } 98 | } 99 | 100 | impl fmt::Debug for ReadArc<'_, T> { 101 | #[inline] 102 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 103 | f.write_str("ReadArc { .. }") 104 | } 105 | } 106 | 107 | impl EventListenerFuture for ReadArcInner<'_, T> { 108 | type Output = RwLockReadGuardArc; 109 | 110 | #[inline] 111 | fn poll_with_strategy<'x, S: Strategy<'x>>( 112 | self: Pin<&mut Self>, 113 | strategy: &mut S, 114 | cx: &mut S::Context, 115 | ) -> Poll { 116 | let mut this = self.project(); 117 | ready!(this.raw.as_mut().poll_with_strategy(strategy, cx)); 118 | 119 | // SAFETY: we just acquired a read lock 120 | Poll::Ready(unsafe { RwLockReadGuardArc::from_arc(this.lock.clone()) }) 121 | } 122 | } 123 | 124 | easy_wrapper! { 125 | /// The future returned by [`RwLock::upgradable_read`]. 126 | pub struct UpgradableRead<'a, T: ?Sized>( 127 | UpgradableReadInner<'a, T> => RwLockUpgradableReadGuard<'a, T> 128 | ); 129 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 130 | pub(crate) wait(); 131 | } 132 | 133 | pin_project_lite::pin_project! { 134 | /// The future returned by [`RwLock::upgradable_read`]. 135 | struct UpgradableReadInner<'a, T: ?Sized> { 136 | // Raw upgradable read lock acquisition future, doesn't depend on `T`. 137 | #[pin] 138 | pub(super) raw: RawUpgradableRead<'a>, 139 | 140 | // Pointer to the value protected by the lock. Invariant in `T` 141 | // as the upgradable lock could provide write access. 142 | pub(super) value: *mut T, 143 | } 144 | } 145 | 146 | unsafe impl Send for UpgradableReadInner<'_, T> {} 147 | unsafe impl Sync for UpgradableReadInner<'_, T> {} 148 | 149 | impl<'x, T: ?Sized> UpgradableRead<'x, T> { 150 | #[inline] 151 | pub(super) fn new(raw: RawUpgradableRead<'x>, value: *mut T) -> Self { 152 | Self::_new(UpgradableReadInner { raw, value }) 153 | } 154 | } 155 | 156 | impl fmt::Debug for UpgradableRead<'_, T> { 157 | #[inline] 158 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 159 | f.write_str("UpgradableRead { .. }") 160 | } 161 | } 162 | 163 | impl<'a, T: ?Sized> EventListenerFuture for UpgradableReadInner<'a, T> { 164 | type Output = RwLockUpgradableReadGuard<'a, T>; 165 | 166 | #[inline] 167 | fn poll_with_strategy<'x, S: Strategy<'x>>( 168 | self: Pin<&mut Self>, 169 | strategy: &mut S, 170 | cx: &mut S::Context, 171 | ) -> Poll { 172 | let mut this = self.project(); 173 | ready!(this.raw.as_mut().poll_with_strategy(strategy, cx)); 174 | 175 | Poll::Ready(RwLockUpgradableReadGuard { 176 | lock: this.raw.lock, 177 | value: *this.value, 178 | }) 179 | } 180 | } 181 | 182 | easy_wrapper! { 183 | /// The future returned by [`RwLock::upgradable_read_arc`]. 184 | pub struct UpgradableReadArc<'a, T: ?Sized>( 185 | UpgradableReadArcInner<'a, T> => RwLockUpgradableReadGuardArc 186 | ); 187 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 188 | pub(crate) wait(); 189 | } 190 | 191 | pin_project_lite::pin_project! { 192 | /// The future returned by [`RwLock::upgradable_read_arc`]. 193 | struct UpgradableReadArcInner<'a, T: ?Sized> { 194 | // Raw upgradable read lock acquisition future, doesn't depend on `T`. 195 | #[pin] 196 | pub(super) raw: RawUpgradableRead<'a>, 197 | 198 | pub(super) lock: &'a Arc>, 199 | } 200 | } 201 | 202 | unsafe impl Send for UpgradableReadArcInner<'_, T> {} 203 | unsafe impl Sync for UpgradableReadArcInner<'_, T> {} 204 | 205 | impl<'x, T: ?Sized> UpgradableReadArc<'x, T> { 206 | #[inline] 207 | pub(super) fn new(raw: RawUpgradableRead<'x>, lock: &'x Arc>) -> Self { 208 | Self::_new(UpgradableReadArcInner { raw, lock }) 209 | } 210 | } 211 | 212 | impl fmt::Debug for UpgradableReadArc<'_, T> { 213 | #[inline] 214 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 215 | f.write_str("UpgradableReadArc { .. }") 216 | } 217 | } 218 | 219 | impl EventListenerFuture for UpgradableReadArcInner<'_, T> { 220 | type Output = RwLockUpgradableReadGuardArc; 221 | 222 | #[inline] 223 | fn poll_with_strategy<'x, S: Strategy<'x>>( 224 | self: Pin<&mut Self>, 225 | strategy: &mut S, 226 | cx: &mut S::Context, 227 | ) -> Poll { 228 | let mut this = self.project(); 229 | ready!(this.raw.as_mut().poll_with_strategy(strategy, cx)); 230 | Poll::Ready(RwLockUpgradableReadGuardArc { 231 | lock: this.lock.clone(), 232 | }) 233 | } 234 | } 235 | 236 | easy_wrapper! { 237 | /// The future returned by [`RwLock::write`]. 238 | pub struct Write<'a, T: ?Sized>(WriteInner<'a, T> => RwLockWriteGuard<'a, T>); 239 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 240 | pub(crate) wait(); 241 | } 242 | 243 | pin_project_lite::pin_project! { 244 | /// The future returned by [`RwLock::write`]. 245 | struct WriteInner<'a, T: ?Sized> { 246 | // Raw write lock acquisition future, doesn't depend on `T`. 247 | #[pin] 248 | pub(super) raw: RawWrite<'a>, 249 | 250 | // Pointer to the value protected by the lock. Invariant in `T`. 251 | pub(super) value: *mut T, 252 | } 253 | } 254 | 255 | unsafe impl Send for WriteInner<'_, T> {} 256 | unsafe impl Sync for WriteInner<'_, T> {} 257 | 258 | impl<'x, T: ?Sized> Write<'x, T> { 259 | #[inline] 260 | pub(super) fn new(raw: RawWrite<'x>, value: *mut T) -> Self { 261 | Self::_new(WriteInner { raw, value }) 262 | } 263 | } 264 | 265 | impl fmt::Debug for Write<'_, T> { 266 | #[inline] 267 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 268 | f.write_str("Write { .. }") 269 | } 270 | } 271 | 272 | impl<'a, T: ?Sized> EventListenerFuture for WriteInner<'a, T> { 273 | type Output = RwLockWriteGuard<'a, T>; 274 | 275 | #[inline] 276 | fn poll_with_strategy<'x, S: Strategy<'x>>( 277 | self: Pin<&mut Self>, 278 | strategy: &mut S, 279 | cx: &mut S::Context, 280 | ) -> Poll { 281 | let mut this = self.project(); 282 | ready!(this.raw.as_mut().poll_with_strategy(strategy, cx)); 283 | 284 | Poll::Ready(RwLockWriteGuard { 285 | lock: this.raw.lock, 286 | value: *this.value, 287 | }) 288 | } 289 | } 290 | 291 | easy_wrapper! { 292 | /// The future returned by [`RwLock::write_arc`]. 293 | pub struct WriteArc<'a, T: ?Sized>(WriteArcInner<'a, T> => RwLockWriteGuardArc); 294 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 295 | pub(crate) wait(); 296 | } 297 | 298 | pin_project_lite::pin_project! { 299 | /// The future returned by [`RwLock::write_arc`]. 300 | struct WriteArcInner<'a, T: ?Sized> { 301 | // Raw write lock acquisition future, doesn't depend on `T`. 302 | #[pin] 303 | pub(super) raw: RawWrite<'a>, 304 | 305 | pub(super) lock: &'a Arc>, 306 | } 307 | } 308 | 309 | unsafe impl Send for WriteArcInner<'_, T> {} 310 | unsafe impl Sync for WriteArcInner<'_, T> {} 311 | 312 | impl<'x, T: ?Sized> WriteArc<'x, T> { 313 | #[inline] 314 | pub(super) fn new(raw: RawWrite<'x>, lock: &'x Arc>) -> Self { 315 | Self::_new(WriteArcInner { raw, lock }) 316 | } 317 | } 318 | 319 | impl fmt::Debug for WriteArc<'_, T> { 320 | #[inline] 321 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 322 | f.write_str("WriteArc { .. }") 323 | } 324 | } 325 | 326 | impl EventListenerFuture for WriteArcInner<'_, T> { 327 | type Output = RwLockWriteGuardArc; 328 | 329 | #[inline] 330 | fn poll_with_strategy<'x, S: Strategy<'x>>( 331 | self: Pin<&mut Self>, 332 | strategy: &mut S, 333 | cx: &mut S::Context, 334 | ) -> Poll { 335 | let mut this = self.project(); 336 | ready!(this.raw.as_mut().poll_with_strategy(strategy, cx)); 337 | 338 | Poll::Ready(RwLockWriteGuardArc { 339 | lock: this.lock.clone(), 340 | }) 341 | } 342 | } 343 | 344 | easy_wrapper! { 345 | /// The future returned by [`RwLockUpgradableReadGuard::upgrade`]. 346 | pub struct Upgrade<'a, T: ?Sized>(UpgradeInner<'a, T> => RwLockWriteGuard<'a, T>); 347 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 348 | pub(crate) wait(); 349 | } 350 | 351 | pin_project_lite::pin_project! { 352 | /// The future returned by [`RwLockUpgradableReadGuard::upgrade`]. 353 | struct UpgradeInner<'a, T: ?Sized> { 354 | // Raw read lock upgrade future, doesn't depend on `T`. 355 | #[pin] 356 | pub(super) raw: RawUpgrade<'a>, 357 | 358 | // Pointer to the value protected by the lock. Invariant in `T`. 359 | pub(super) value: *mut T, 360 | } 361 | } 362 | 363 | unsafe impl Send for UpgradeInner<'_, T> {} 364 | unsafe impl Sync for UpgradeInner<'_, T> {} 365 | 366 | impl<'x, T: ?Sized> Upgrade<'x, T> { 367 | #[inline] 368 | pub(super) fn new(raw: RawUpgrade<'x>, value: *mut T) -> Self { 369 | Self::_new(UpgradeInner { raw, value }) 370 | } 371 | } 372 | 373 | impl fmt::Debug for Upgrade<'_, T> { 374 | #[inline] 375 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 376 | f.debug_struct("Upgrade").finish() 377 | } 378 | } 379 | 380 | impl<'a, T: ?Sized> EventListenerFuture for UpgradeInner<'a, T> { 381 | type Output = RwLockWriteGuard<'a, T>; 382 | 383 | #[inline] 384 | fn poll_with_strategy<'x, S: Strategy<'x>>( 385 | self: Pin<&mut Self>, 386 | strategy: &mut S, 387 | cx: &mut S::Context, 388 | ) -> Poll { 389 | let mut this = self.project(); 390 | let lock = ready!(this.raw.as_mut().poll_with_strategy(strategy, cx)); 391 | 392 | Poll::Ready(RwLockWriteGuard { 393 | lock, 394 | value: *this.value, 395 | }) 396 | } 397 | } 398 | 399 | easy_wrapper! { 400 | /// The future returned by [`RwLockUpgradableReadGuardArc::upgrade`]. 401 | pub struct UpgradeArc(UpgradeArcInner => RwLockWriteGuardArc); 402 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 403 | pub(crate) wait(); 404 | } 405 | 406 | pin_project_lite::pin_project! { 407 | /// The future returned by [`RwLockUpgradableReadGuardArc::upgrade`]. 408 | struct UpgradeArcInner { 409 | // Raw read lock upgrade future, doesn't depend on `T`. 410 | // `'static` is a lie, this field is actually referencing the 411 | // `Arc` data. But since this struct also stores said `Arc`, we know 412 | // this value will be alive as long as the struct is. 413 | // 414 | // Yes, one field of the `ArcUpgrade` struct is referencing another. 415 | // Such self-references are usually not sound without pinning. 416 | // However, in this case, there is an indirection via the heap; 417 | // moving the `ArcUpgrade` won't move the heap allocation of the `Arc`, 418 | // so the reference inside `RawUpgrade` isn't invalidated. 419 | #[pin] 420 | pub(super) raw: ManuallyDrop>, 421 | 422 | // Pointer to the value protected by the lock. Invariant in `T`. 423 | pub(super) lock: ManuallyDrop>>, 424 | } 425 | 426 | impl PinnedDrop for UpgradeArcInner { 427 | fn drop(this: Pin<&mut Self>) { 428 | let this = this.project(); 429 | let is_ready = this.raw.is_ready(); 430 | 431 | // SAFETY: The drop impl for raw assumes that it is pinned. 432 | unsafe { 433 | ManuallyDrop::drop(this.raw.get_unchecked_mut()); 434 | } 435 | 436 | if !is_ready { 437 | // SAFETY: we drop the `Arc` (decrementing the reference count) 438 | // only if this future was cancelled before returning an 439 | // upgraded lock. 440 | unsafe { 441 | ManuallyDrop::drop(this.lock); 442 | }; 443 | } 444 | } 445 | } 446 | } 447 | 448 | impl UpgradeArc { 449 | #[inline] 450 | pub(super) unsafe fn new( 451 | raw: ManuallyDrop>, 452 | lock: ManuallyDrop>>, 453 | ) -> Self { 454 | Self::_new(UpgradeArcInner { raw, lock }) 455 | } 456 | } 457 | 458 | impl fmt::Debug for UpgradeArc { 459 | #[inline] 460 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 461 | f.debug_struct("ArcUpgrade").finish() 462 | } 463 | } 464 | 465 | impl EventListenerFuture for UpgradeArcInner { 466 | type Output = RwLockWriteGuardArc; 467 | 468 | #[inline] 469 | fn poll_with_strategy<'x, S: Strategy<'x>>( 470 | self: Pin<&mut Self>, 471 | strategy: &mut S, 472 | cx: &mut S::Context, 473 | ) -> Poll { 474 | let this = self.project(); 475 | unsafe { 476 | // SAFETY: Practically, this is a pin projection. 477 | ready!(Pin::new_unchecked(&mut **this.raw.get_unchecked_mut()) 478 | .poll_with_strategy(strategy, cx)); 479 | } 480 | 481 | Poll::Ready(RwLockWriteGuardArc { 482 | lock: unsafe { ManuallyDrop::take(this.lock) }, 483 | }) 484 | } 485 | } 486 | -------------------------------------------------------------------------------- /src/rwlock/raw.rs: -------------------------------------------------------------------------------- 1 | //! Raw, unsafe reader-writer locking implementation, 2 | //! doesn't depend on the data protected by the lock. 3 | //! [`RwLock`](super::RwLock) is implemented in terms of this. 4 | //! 5 | //! Splitting the implementation this way allows instantiating 6 | //! the locking code only once, and also lets us make 7 | //! [`RwLockReadGuard`](super::RwLockReadGuard) covariant in `T`. 8 | 9 | use core::marker::PhantomPinned; 10 | use core::mem::forget; 11 | use core::pin::Pin; 12 | use core::task::Poll; 13 | 14 | use crate::sync::atomic::{AtomicUsize, Ordering}; 15 | 16 | use event_listener::{Event, EventListener}; 17 | use event_listener_strategy::{EventListenerFuture, Strategy}; 18 | 19 | use crate::futures::Lock; 20 | use crate::Mutex; 21 | 22 | const WRITER_BIT: usize = 1; 23 | const ONE_READER: usize = 2; 24 | 25 | /// A "raw" RwLock that doesn't hold any data. 26 | pub(super) struct RawRwLock { 27 | /// Acquired by the writer. 28 | mutex: Mutex<()>, 29 | 30 | /// Event triggered when the last reader is dropped. 31 | no_readers: Event, 32 | 33 | /// Event triggered when the writer is dropped. 34 | no_writer: Event, 35 | 36 | /// Current state of the lock. 37 | /// 38 | /// The least significant bit (`WRITER_BIT`) is set to 1 when a writer is holding the lock or 39 | /// trying to acquire it. 40 | /// 41 | /// The upper bits contain the number of currently active readers. Each active reader 42 | /// increments the state by `ONE_READER`. 43 | state: AtomicUsize, 44 | } 45 | 46 | impl RawRwLock { 47 | const_fn! { 48 | const_if: #[cfg(not(loom))]; 49 | #[inline] 50 | pub(super) const fn new() -> Self { 51 | RawRwLock { 52 | mutex: Mutex::new(()), 53 | no_readers: Event::new(), 54 | no_writer: Event::new(), 55 | state: AtomicUsize::new(0), 56 | } 57 | } 58 | } 59 | 60 | /// Returns `true` iff a read lock was successfully acquired. 61 | pub(super) fn try_read(&self) -> bool { 62 | let mut state = self.state.load(Ordering::Acquire); 63 | 64 | loop { 65 | // If there's a writer holding the lock or attempting to acquire it, we cannot acquire 66 | // a read lock here. 67 | if state & WRITER_BIT != 0 { 68 | return false; 69 | } 70 | 71 | // Make sure the number of readers doesn't overflow. 72 | if state > isize::MAX as usize { 73 | crate::abort(); 74 | } 75 | 76 | // Increment the number of readers. 77 | match self.state.compare_exchange( 78 | state, 79 | state + ONE_READER, 80 | Ordering::AcqRel, 81 | Ordering::Acquire, 82 | ) { 83 | Ok(_) => return true, 84 | Err(s) => state = s, 85 | } 86 | } 87 | } 88 | 89 | #[inline] 90 | pub(super) fn read(&self) -> RawRead<'_> { 91 | RawRead { 92 | lock: self, 93 | state: self.state.load(Ordering::Acquire), 94 | listener: None, 95 | _pin: PhantomPinned, 96 | } 97 | } 98 | 99 | /// Returns `true` iff an upgradable read lock was successfully acquired. 100 | pub(super) fn try_upgradable_read(&self) -> bool { 101 | // First try grabbing the mutex. 102 | let lock = if let Some(lock) = self.mutex.try_lock() { 103 | lock 104 | } else { 105 | return false; 106 | }; 107 | 108 | forget(lock); 109 | 110 | let mut state = self.state.load(Ordering::Acquire); 111 | 112 | // Make sure the number of readers doesn't overflow. 113 | if state > isize::MAX as usize { 114 | crate::abort(); 115 | } 116 | 117 | // Increment the number of readers. 118 | loop { 119 | match self.state.compare_exchange( 120 | state, 121 | state + ONE_READER, 122 | Ordering::AcqRel, 123 | Ordering::Acquire, 124 | ) { 125 | Ok(_) => return true, 126 | Err(s) => state = s, 127 | } 128 | } 129 | } 130 | 131 | #[inline] 132 | pub(super) fn upgradable_read(&self) -> RawUpgradableRead<'_> { 133 | RawUpgradableRead { 134 | lock: self, 135 | acquire: self.mutex.lock(), 136 | } 137 | } 138 | 139 | /// Returns `true` iff a write lock was successfully acquired. 140 | pub(super) fn try_write(&self) -> bool { 141 | // First try grabbing the mutex. 142 | let lock = if let Some(lock) = self.mutex.try_lock() { 143 | lock 144 | } else { 145 | return false; 146 | }; 147 | 148 | // If there are no readers, grab the write lock. 149 | if self 150 | .state 151 | .compare_exchange(0, WRITER_BIT, Ordering::AcqRel, Ordering::Acquire) 152 | .is_ok() 153 | { 154 | forget(lock); 155 | true 156 | } else { 157 | drop(lock); 158 | false 159 | } 160 | } 161 | 162 | #[inline] 163 | pub(super) fn write(&self) -> RawWrite<'_> { 164 | RawWrite { 165 | lock: self, 166 | no_readers: None, 167 | state: WriteState::Acquiring { 168 | lock: self.mutex.lock(), 169 | }, 170 | } 171 | } 172 | 173 | /// Returns `true` iff a the upgradable read lock was successfully upgraded to a write lock. 174 | /// 175 | /// # Safety 176 | /// 177 | /// Caller must hold an upgradable read lock. 178 | /// This will attempt to upgrade it to a write lock. 179 | pub(super) unsafe fn try_upgrade(&self) -> bool { 180 | self.state 181 | .compare_exchange(ONE_READER, WRITER_BIT, Ordering::AcqRel, Ordering::Acquire) 182 | .is_ok() 183 | } 184 | 185 | /// # Safety 186 | /// 187 | /// Caller must hold an upgradable read lock. 188 | /// This will upgrade it to a write lock. 189 | pub(super) unsafe fn upgrade(&self) -> RawUpgrade<'_> { 190 | // Set `WRITER_BIT` and decrement the number of readers at the same time. 191 | self.state 192 | .fetch_sub(ONE_READER - WRITER_BIT, Ordering::SeqCst); 193 | 194 | RawUpgrade { 195 | lock: Some(self), 196 | listener: None, 197 | _pin: PhantomPinned, 198 | } 199 | } 200 | 201 | /// # Safety 202 | /// 203 | /// Caller must hold an upgradable read lock. 204 | /// This will downgrade it to a standard read lock. 205 | #[inline] 206 | pub(super) unsafe fn downgrade_upgradable_read(&self) { 207 | self.mutex.unlock_unchecked(); 208 | } 209 | 210 | /// # Safety 211 | /// 212 | /// Caller must hold a write lock. 213 | /// This will downgrade it to a read lock. 214 | pub(super) unsafe fn downgrade_write(&self) { 215 | // Atomically downgrade state. 216 | self.state 217 | .fetch_add(ONE_READER - WRITER_BIT, Ordering::SeqCst); 218 | 219 | // Release the writer mutex. 220 | self.mutex.unlock_unchecked(); 221 | 222 | // Trigger the "no writer" event. 223 | self.no_writer.notify(1); 224 | } 225 | 226 | /// # Safety 227 | /// 228 | /// Caller must hold a write lock. 229 | /// This will downgrade it to an upgradable read lock. 230 | pub(super) unsafe fn downgrade_to_upgradable(&self) { 231 | // Atomically downgrade state. 232 | self.state 233 | .fetch_add(ONE_READER - WRITER_BIT, Ordering::SeqCst); 234 | } 235 | 236 | /// # Safety 237 | /// 238 | /// Caller must hold a read lock . 239 | /// This will unlock that lock. 240 | pub(super) unsafe fn read_unlock(&self) { 241 | // Decrement the number of readers. 242 | if self.state.fetch_sub(ONE_READER, Ordering::SeqCst) & !WRITER_BIT == ONE_READER { 243 | // If this was the last reader, trigger the "no readers" event. 244 | self.no_readers.notify(1); 245 | } 246 | } 247 | 248 | /// # Safety 249 | /// 250 | /// Caller must hold an upgradable read lock. 251 | /// This will unlock that lock. 252 | pub(super) unsafe fn upgradable_read_unlock(&self) { 253 | // Decrement the number of readers. 254 | if self.state.fetch_sub(ONE_READER, Ordering::SeqCst) & !WRITER_BIT == ONE_READER { 255 | // If this was the last reader, trigger the "no readers" event. 256 | self.no_readers.notify(1); 257 | } 258 | 259 | // SAFETY: upgradable read guards acquire the writer mutex upon creation. 260 | self.mutex.unlock_unchecked(); 261 | } 262 | 263 | /// # Safety 264 | /// 265 | /// Caller must hold a write lock. 266 | /// This will unlock that lock. 267 | pub(super) unsafe fn write_unlock(&self) { 268 | // Unset `WRITER_BIT`. 269 | self.state.fetch_and(!WRITER_BIT, Ordering::SeqCst); 270 | // Trigger the "no writer" event. 271 | self.no_writer.notify(1); 272 | 273 | // Release the writer lock. 274 | // SAFETY: `RwLockWriteGuard` always holds a lock on writer mutex. 275 | self.mutex.unlock_unchecked(); 276 | } 277 | } 278 | 279 | pin_project_lite::pin_project! { 280 | /// The future returned by [`RawRwLock::read`]. 281 | 282 | pub(super) struct RawRead<'a> { 283 | // The lock that is being acquired. 284 | pub(super) lock: &'a RawRwLock, 285 | 286 | // The last-observed state of the lock. 287 | state: usize, 288 | 289 | // The listener for the "no writers" event. 290 | listener: Option, 291 | 292 | // Making this type `!Unpin` enables future optimizations. 293 | #[pin] 294 | _pin: PhantomPinned 295 | } 296 | } 297 | 298 | impl EventListenerFuture for RawRead<'_> { 299 | type Output = (); 300 | 301 | fn poll_with_strategy<'x, S: Strategy<'x>>( 302 | self: Pin<&mut Self>, 303 | strategy: &mut S, 304 | cx: &mut S::Context, 305 | ) -> Poll<()> { 306 | let this = self.project(); 307 | 308 | loop { 309 | if *this.state & WRITER_BIT == 0 { 310 | // Make sure the number of readers doesn't overflow. 311 | if *this.state > isize::MAX as usize { 312 | crate::abort(); 313 | } 314 | 315 | // If nobody is holding a write lock or attempting to acquire it, increment the 316 | // number of readers. 317 | match this.lock.state.compare_exchange( 318 | *this.state, 319 | *this.state + ONE_READER, 320 | Ordering::AcqRel, 321 | Ordering::Acquire, 322 | ) { 323 | Ok(_) => return Poll::Ready(()), 324 | Err(s) => *this.state = s, 325 | } 326 | } else { 327 | // Start listening for "no writer" events. 328 | let load_ordering = if this.listener.is_none() { 329 | *this.listener = Some(this.lock.no_writer.listen()); 330 | 331 | // Make sure there really is no writer. 332 | Ordering::SeqCst 333 | } else { 334 | // Wait for the writer to finish. 335 | ready!(strategy.poll(this.listener, cx)); 336 | 337 | // Notify the next reader waiting in list. 338 | this.lock.no_writer.notify(1); 339 | 340 | // Check the state again. 341 | Ordering::Acquire 342 | }; 343 | 344 | // Reload the state. 345 | *this.state = this.lock.state.load(load_ordering); 346 | } 347 | } 348 | } 349 | } 350 | 351 | pin_project_lite::pin_project! { 352 | /// The future returned by [`RawRwLock::upgradable_read`]. 353 | pub(super) struct RawUpgradableRead<'a> { 354 | // The lock that is being acquired. 355 | pub(super) lock: &'a RawRwLock, 356 | 357 | // The mutex we are trying to acquire. 358 | #[pin] 359 | acquire: Lock<'a, ()>, 360 | } 361 | } 362 | 363 | impl EventListenerFuture for RawUpgradableRead<'_> { 364 | type Output = (); 365 | 366 | fn poll_with_strategy<'x, S: Strategy<'x>>( 367 | self: Pin<&mut Self>, 368 | strategy: &mut S, 369 | cx: &mut S::Context, 370 | ) -> Poll<()> { 371 | let this = self.project(); 372 | 373 | // Acquire the mutex. 374 | let mutex_guard = ready!(this.acquire.poll_with_strategy(strategy, cx)); 375 | forget(mutex_guard); 376 | 377 | // Load the current state. 378 | let mut state = this.lock.state.load(Ordering::Acquire); 379 | 380 | // Make sure the number of readers doesn't overflow. 381 | if state > isize::MAX as usize { 382 | crate::abort(); 383 | } 384 | 385 | // Increment the number of readers. 386 | loop { 387 | match this.lock.state.compare_exchange( 388 | state, 389 | state + ONE_READER, 390 | Ordering::AcqRel, 391 | Ordering::Acquire, 392 | ) { 393 | Ok(_) => { 394 | return Poll::Ready(()); 395 | } 396 | Err(s) => state = s, 397 | } 398 | } 399 | } 400 | } 401 | 402 | pin_project_lite::pin_project! { 403 | /// The future returned by [`RawRwLock::write`]. 404 | 405 | pub(super) struct RawWrite<'a> { 406 | // The lock that is being acquired. 407 | pub(super) lock: &'a RawRwLock, 408 | 409 | // Our listener for the "no readers" event. 410 | no_readers: Option, 411 | 412 | // Current state of this future. 413 | #[pin] 414 | state: WriteState<'a>, 415 | } 416 | 417 | impl PinnedDrop for RawWrite<'_> { 418 | fn drop(this: Pin<&mut Self>) { 419 | let this = this.project(); 420 | 421 | if matches!(this.state.project(), WriteStateProj::WaitingReaders) { 422 | // Safety: we hold a write lock, more or less. 423 | unsafe { 424 | this.lock.write_unlock(); 425 | } 426 | } 427 | } 428 | } 429 | } 430 | 431 | pin_project_lite::pin_project! { 432 | #[project = WriteStateProj] 433 | #[project_replace = WriteStateProjReplace] 434 | enum WriteState<'a> { 435 | // We are currently acquiring the inner mutex. 436 | Acquiring { #[pin] lock: Lock<'a, ()> }, 437 | 438 | // We are currently waiting for readers to finish. 439 | WaitingReaders, 440 | 441 | // The future has completed. 442 | Acquired, 443 | } 444 | } 445 | 446 | impl EventListenerFuture for RawWrite<'_> { 447 | type Output = (); 448 | 449 | fn poll_with_strategy<'x, S: Strategy<'x>>( 450 | self: Pin<&mut Self>, 451 | strategy: &mut S, 452 | cx: &mut S::Context, 453 | ) -> Poll<()> { 454 | let mut this = self.project(); 455 | 456 | loop { 457 | match this.state.as_mut().project() { 458 | WriteStateProj::Acquiring { lock } => { 459 | // First grab the mutex. 460 | let mutex_guard = ready!(lock.poll_with_strategy(strategy, cx)); 461 | forget(mutex_guard); 462 | 463 | // Set `WRITER_BIT` and create a guard that unsets it in case this future is canceled. 464 | let new_state = this.lock.state.fetch_or(WRITER_BIT, Ordering::SeqCst); 465 | 466 | // If we just acquired the lock, return. 467 | if new_state == WRITER_BIT { 468 | this.state.as_mut().set(WriteState::Acquired); 469 | return Poll::Ready(()); 470 | } 471 | 472 | // Start waiting for the readers to finish. 473 | *this.no_readers = Some(this.lock.no_readers.listen()); 474 | this.state.as_mut().set(WriteState::WaitingReaders); 475 | } 476 | 477 | WriteStateProj::WaitingReaders => { 478 | let load_ordering = if this.no_readers.is_some() { 479 | Ordering::Acquire 480 | } else { 481 | Ordering::SeqCst 482 | }; 483 | 484 | // Check the state again. 485 | if this.lock.state.load(load_ordering) == WRITER_BIT { 486 | // We are the only ones holding the lock, return `Ready`. 487 | this.state.as_mut().set(WriteState::Acquired); 488 | return Poll::Ready(()); 489 | } 490 | 491 | // Wait for the readers to finish. 492 | if this.no_readers.is_none() { 493 | // Register a listener. 494 | *this.no_readers = Some(this.lock.no_readers.listen()); 495 | } else { 496 | // Wait for the readers to finish. 497 | ready!(strategy.poll(this.no_readers, cx)); 498 | }; 499 | } 500 | WriteStateProj::Acquired => panic!("Write lock already acquired"), 501 | } 502 | } 503 | } 504 | } 505 | 506 | pin_project_lite::pin_project! { 507 | /// The future returned by [`RawRwLock::upgrade`]. 508 | 509 | pub(super) struct RawUpgrade<'a> { 510 | lock: Option<&'a RawRwLock>, 511 | 512 | // The event listener we are waiting on. 513 | listener: Option, 514 | 515 | // Keeping this future `!Unpin` enables future optimizations. 516 | #[pin] 517 | _pin: PhantomPinned 518 | } 519 | 520 | impl PinnedDrop for RawUpgrade<'_> { 521 | fn drop(this: Pin<&mut Self>) { 522 | let this = this.project(); 523 | if let Some(lock) = this.lock { 524 | // SAFETY: we are dropping the future that would give us a write lock, 525 | // so we don't need said lock anymore. 526 | unsafe { 527 | lock.write_unlock(); 528 | } 529 | } 530 | } 531 | } 532 | } 533 | 534 | impl<'a> EventListenerFuture for RawUpgrade<'a> { 535 | type Output = &'a RawRwLock; 536 | 537 | fn poll_with_strategy<'x, S: Strategy<'x>>( 538 | self: Pin<&mut Self>, 539 | strategy: &mut S, 540 | cx: &mut S::Context, 541 | ) -> Poll<&'a RawRwLock> { 542 | let this = self.project(); 543 | let lock = this.lock.expect("cannot poll future after completion"); 544 | 545 | // If there are readers, we need to wait for them to finish. 546 | loop { 547 | let load_ordering = if this.listener.is_some() { 548 | Ordering::Acquire 549 | } else { 550 | Ordering::SeqCst 551 | }; 552 | 553 | // See if the number of readers is zero. 554 | let state = lock.state.load(load_ordering); 555 | if state == WRITER_BIT { 556 | break; 557 | } 558 | 559 | // If there are readers, wait for them to finish. 560 | if this.listener.is_none() { 561 | // Start listening for "no readers" events. 562 | *this.listener = Some(lock.no_readers.listen()); 563 | } else { 564 | // Wait for the readers to finish. 565 | ready!(strategy.poll(this.listener, cx)); 566 | }; 567 | } 568 | 569 | // We are done. 570 | Poll::Ready(this.lock.take().unwrap()) 571 | } 572 | } 573 | 574 | impl RawUpgrade<'_> { 575 | /// Whether the future returned `Poll::Ready(..)` at some point. 576 | #[inline] 577 | pub(super) fn is_ready(&self) -> bool { 578 | self.lock.is_none() 579 | } 580 | } 581 | -------------------------------------------------------------------------------- /src/semaphore.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | use core::marker::PhantomPinned; 3 | use core::mem; 4 | use core::pin::Pin; 5 | use core::task::Poll; 6 | 7 | use crate::sync::atomic::{AtomicUsize, Ordering}; 8 | 9 | use alloc::sync::Arc; 10 | 11 | use event_listener::{Event, EventListener}; 12 | use event_listener_strategy::{easy_wrapper, EventListenerFuture, Strategy}; 13 | 14 | /// A counter for limiting the number of concurrent operations. 15 | #[derive(Debug)] 16 | pub struct Semaphore { 17 | count: AtomicUsize, 18 | event: Event, 19 | } 20 | 21 | impl Semaphore { 22 | const_fn! { 23 | const_if: #[cfg(not(loom))]; 24 | /// Creates a new semaphore with a limit of `n` concurrent operations. 25 | /// 26 | /// # Examples 27 | /// 28 | /// ``` 29 | /// use async_lock::Semaphore; 30 | /// 31 | /// let s = Semaphore::new(5); 32 | /// ``` 33 | pub const fn new(n: usize) -> Semaphore { 34 | Semaphore { 35 | count: AtomicUsize::new(n), 36 | event: Event::new(), 37 | } 38 | } 39 | } 40 | 41 | /// Attempts to get a permit for a concurrent operation. 42 | /// 43 | /// If the permit could not be acquired at this time, then [`None`] is returned. Otherwise, a 44 | /// guard is returned that releases the mutex when dropped. 45 | /// 46 | /// # Examples 47 | /// 48 | /// ``` 49 | /// use async_lock::Semaphore; 50 | /// 51 | /// let s = Semaphore::new(2); 52 | /// 53 | /// let g1 = s.try_acquire().unwrap(); 54 | /// let g2 = s.try_acquire().unwrap(); 55 | /// 56 | /// assert!(s.try_acquire().is_none()); 57 | /// drop(g2); 58 | /// assert!(s.try_acquire().is_some()); 59 | /// ``` 60 | pub fn try_acquire(&self) -> Option> { 61 | let mut count = self.count.load(Ordering::Acquire); 62 | loop { 63 | if count == 0 { 64 | return None; 65 | } 66 | 67 | match self.count.compare_exchange_weak( 68 | count, 69 | count - 1, 70 | Ordering::AcqRel, 71 | Ordering::Acquire, 72 | ) { 73 | Ok(_) => return Some(SemaphoreGuard(self)), 74 | Err(c) => count = c, 75 | } 76 | } 77 | } 78 | 79 | /// Waits for a permit for a concurrent operation. 80 | /// 81 | /// Returns a guard that releases the permit when dropped. 82 | /// 83 | /// # Examples 84 | /// 85 | /// ``` 86 | /// # futures_lite::future::block_on(async { 87 | /// use async_lock::Semaphore; 88 | /// 89 | /// let s = Semaphore::new(2); 90 | /// let guard = s.acquire().await; 91 | /// # }); 92 | /// ``` 93 | pub fn acquire(&self) -> Acquire<'_> { 94 | Acquire::_new(AcquireInner { 95 | semaphore: self, 96 | listener: None, 97 | _pin: PhantomPinned, 98 | }) 99 | } 100 | 101 | /// Waits for a permit for a concurrent operation. 102 | /// 103 | /// Returns a guard that releases the permit when dropped. 104 | /// 105 | /// # Blocking 106 | /// 107 | /// Rather than using asynchronous waiting, like the [`acquire`][Semaphore::acquire] method, 108 | /// this method will block the current thread until the permit is acquired. 109 | /// 110 | /// This method should not be used in an asynchronous context. It is intended to be 111 | /// used in a way that a semaphore can be used in both asynchronous and synchronous contexts. 112 | /// Calling this method in an asynchronous context may result in a deadlock. 113 | /// 114 | /// # Examples 115 | /// 116 | /// ``` 117 | /// use async_lock::Semaphore; 118 | /// 119 | /// let s = Semaphore::new(2); 120 | /// let guard = s.acquire_blocking(); 121 | /// ``` 122 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 123 | #[inline] 124 | pub fn acquire_blocking(&self) -> SemaphoreGuard<'_> { 125 | self.acquire().wait() 126 | } 127 | 128 | /// Attempts to get an owned permit for a concurrent operation. 129 | /// 130 | /// If the permit could not be acquired at this time, then [`None`] is returned. Otherwise, an 131 | /// owned guard is returned that releases the mutex when dropped. 132 | /// 133 | /// # Examples 134 | /// 135 | /// ``` 136 | /// use async_lock::Semaphore; 137 | /// use std::sync::Arc; 138 | /// 139 | /// let s = Arc::new(Semaphore::new(2)); 140 | /// 141 | /// let g1 = s.try_acquire_arc().unwrap(); 142 | /// let g2 = s.try_acquire_arc().unwrap(); 143 | /// 144 | /// assert!(s.try_acquire_arc().is_none()); 145 | /// drop(g2); 146 | /// assert!(s.try_acquire_arc().is_some()); 147 | /// ``` 148 | pub fn try_acquire_arc(self: &Arc) -> Option { 149 | let mut count = self.count.load(Ordering::Acquire); 150 | loop { 151 | if count == 0 { 152 | return None; 153 | } 154 | 155 | match self.count.compare_exchange_weak( 156 | count, 157 | count - 1, 158 | Ordering::AcqRel, 159 | Ordering::Acquire, 160 | ) { 161 | Ok(_) => return Some(SemaphoreGuardArc(Some(self.clone()))), 162 | Err(c) => count = c, 163 | } 164 | } 165 | } 166 | 167 | /// Waits for an owned permit for a concurrent operation. 168 | /// 169 | /// Returns a guard that releases the permit when dropped. 170 | /// 171 | /// # Examples 172 | /// 173 | /// ``` 174 | /// # futures_lite::future::block_on(async { 175 | /// use async_lock::Semaphore; 176 | /// use std::sync::Arc; 177 | /// 178 | /// let s = Arc::new(Semaphore::new(2)); 179 | /// let guard = s.acquire_arc().await; 180 | /// # }); 181 | /// ``` 182 | pub fn acquire_arc(self: &Arc) -> AcquireArc { 183 | AcquireArc::_new(AcquireArcInner { 184 | semaphore: self.clone(), 185 | listener: None, 186 | _pin: PhantomPinned, 187 | }) 188 | } 189 | 190 | /// Waits for an owned permit for a concurrent operation. 191 | /// 192 | /// Returns a guard that releases the permit when dropped. 193 | /// 194 | /// # Blocking 195 | /// 196 | /// Rather than using asynchronous waiting, like the [`acquire_arc`][Semaphore::acquire_arc] method, 197 | /// this method will block the current thread until the permit is acquired. 198 | /// 199 | /// This method should not be used in an asynchronous context. It is intended to be 200 | /// used in a way that a semaphore can be used in both asynchronous and synchronous contexts. 201 | /// Calling this method in an asynchronous context may result in a deadlock. 202 | /// 203 | /// # Examples 204 | /// 205 | /// ``` 206 | /// use std::sync::Arc; 207 | /// use async_lock::Semaphore; 208 | /// 209 | /// let s = Arc::new(Semaphore::new(2)); 210 | /// let guard = s.acquire_arc_blocking(); 211 | /// ``` 212 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 213 | #[inline] 214 | pub fn acquire_arc_blocking(self: &Arc) -> SemaphoreGuardArc { 215 | self.acquire_arc().wait() 216 | } 217 | 218 | /// Adds `n` additional permits to the semaphore. 219 | /// 220 | /// # Examples 221 | /// 222 | /// ``` 223 | /// use async_lock::Semaphore; 224 | /// 225 | /// # futures_lite::future::block_on(async { 226 | /// let s = Semaphore::new(1); 227 | /// 228 | /// let _guard = s.acquire().await; 229 | /// assert!(s.try_acquire().is_none()); 230 | /// 231 | /// s.add_permits(2); 232 | /// 233 | /// let _guard = s.acquire().await; 234 | /// let _guard = s.acquire().await; 235 | /// # }); 236 | /// ``` 237 | pub fn add_permits(&self, n: usize) { 238 | self.count.fetch_add(n, Ordering::AcqRel); 239 | self.event.notify(n); 240 | } 241 | } 242 | 243 | easy_wrapper! { 244 | /// The future returned by [`Semaphore::acquire`]. 245 | pub struct Acquire<'a>(AcquireInner<'a> => SemaphoreGuard<'a>); 246 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 247 | pub(crate) wait(); 248 | } 249 | 250 | pin_project_lite::pin_project! { 251 | struct AcquireInner<'a> { 252 | // The semaphore being acquired. 253 | semaphore: &'a Semaphore, 254 | 255 | // The listener waiting on the semaphore. 256 | listener: Option, 257 | 258 | // Keeping this future `!Unpin` enables future optimizations. 259 | #[pin] 260 | _pin: PhantomPinned 261 | } 262 | } 263 | 264 | impl fmt::Debug for Acquire<'_> { 265 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 266 | f.write_str("Acquire { .. }") 267 | } 268 | } 269 | 270 | impl<'a> EventListenerFuture for AcquireInner<'a> { 271 | type Output = SemaphoreGuard<'a>; 272 | 273 | fn poll_with_strategy<'x, S: Strategy<'x>>( 274 | self: Pin<&mut Self>, 275 | strategy: &mut S, 276 | cx: &mut S::Context, 277 | ) -> Poll { 278 | let this = self.project(); 279 | 280 | loop { 281 | match this.semaphore.try_acquire() { 282 | Some(guard) => return Poll::Ready(guard), 283 | None => { 284 | // Wait on the listener. 285 | if this.listener.is_none() { 286 | *this.listener = Some(this.semaphore.event.listen()); 287 | } else { 288 | ready!(strategy.poll(this.listener, cx)); 289 | } 290 | } 291 | } 292 | } 293 | } 294 | } 295 | 296 | easy_wrapper! { 297 | /// The future returned by [`Semaphore::acquire_arc`]. 298 | pub struct AcquireArc(AcquireArcInner => SemaphoreGuardArc); 299 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 300 | pub(crate) wait(); 301 | } 302 | 303 | pin_project_lite::pin_project! { 304 | struct AcquireArcInner { 305 | // The semaphore being acquired. 306 | semaphore: Arc, 307 | 308 | // The listener waiting on the semaphore. 309 | listener: Option, 310 | 311 | // Keeping this future `!Unpin` enables future optimizations. 312 | #[pin] 313 | _pin: PhantomPinned 314 | } 315 | } 316 | 317 | impl fmt::Debug for AcquireArc { 318 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 319 | f.write_str("AcquireArc { .. }") 320 | } 321 | } 322 | 323 | impl EventListenerFuture for AcquireArcInner { 324 | type Output = SemaphoreGuardArc; 325 | 326 | fn poll_with_strategy<'x, S: Strategy<'x>>( 327 | self: Pin<&mut Self>, 328 | strategy: &mut S, 329 | cx: &mut S::Context, 330 | ) -> Poll { 331 | let this = self.project(); 332 | 333 | loop { 334 | match this.semaphore.try_acquire_arc() { 335 | Some(guard) => return Poll::Ready(guard), 336 | None => { 337 | // Wait on the listener. 338 | if this.listener.is_none() { 339 | *this.listener = Some(this.semaphore.event.listen()); 340 | } else { 341 | ready!(strategy.poll(this.listener, cx)); 342 | } 343 | } 344 | } 345 | } 346 | } 347 | } 348 | 349 | /// A guard that releases the acquired permit. 350 | #[clippy::has_significant_drop] 351 | #[derive(Debug)] 352 | pub struct SemaphoreGuard<'a>(&'a Semaphore); 353 | 354 | impl SemaphoreGuard<'_> { 355 | /// Drops the guard _without_ releasing the acquired permit. 356 | #[inline] 357 | pub fn forget(self) { 358 | mem::forget(self); 359 | } 360 | } 361 | 362 | impl Drop for SemaphoreGuard<'_> { 363 | fn drop(&mut self) { 364 | self.0.count.fetch_add(1, Ordering::AcqRel); 365 | self.0.event.notify(1); 366 | } 367 | } 368 | 369 | /// An owned guard that releases the acquired permit. 370 | #[clippy::has_significant_drop] 371 | #[derive(Debug)] 372 | pub struct SemaphoreGuardArc(Option>); 373 | 374 | impl SemaphoreGuardArc { 375 | /// Drops the guard _without_ releasing the acquired permit. 376 | /// (Will still decrement the `Arc` reference count.) 377 | #[inline] 378 | pub fn forget(mut self) { 379 | // Drop the inner `Arc` in order to decrement the reference count. 380 | // FIXME: get rid of the `Option` once RFC 3466 or equivalent becomes available. 381 | drop(self.0.take()); 382 | mem::forget(self); 383 | } 384 | } 385 | 386 | impl Drop for SemaphoreGuardArc { 387 | fn drop(&mut self) { 388 | let opt = self.0.take().unwrap(); 389 | opt.count.fetch_add(1, Ordering::AcqRel); 390 | opt.event.notify(1); 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /tests/barrier.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::thread; 3 | 4 | use async_lock::Barrier; 5 | use futures_lite::future; 6 | 7 | #[test] 8 | #[cfg_attr(miri, ignore)] 9 | fn smoke() { 10 | future::block_on(async move { 11 | const N: usize = 10; 12 | 13 | let barrier = Arc::new(Barrier::new(N)); 14 | 15 | for _ in 0..10 { 16 | let (tx, rx) = flume::unbounded(); 17 | 18 | for _ in 0..N - 1 { 19 | let c = barrier.clone(); 20 | let tx = tx.clone(); 21 | 22 | thread::spawn(move || { 23 | future::block_on(async move { 24 | let res = c.wait().await; 25 | tx.send_async(res.is_leader()).await.unwrap(); 26 | }) 27 | }); 28 | } 29 | 30 | // At this point, all spawned threads should be blocked, 31 | // so we shouldn't get anything from the channel. 32 | let res = rx.try_recv(); 33 | assert!(res.is_err()); 34 | 35 | let mut leader_found = barrier.wait().await.is_leader(); 36 | 37 | // Now, the barrier is cleared and we should get data. 38 | for _ in 0..N - 1 { 39 | if rx.recv_async().await.unwrap() { 40 | assert!(!leader_found); 41 | leader_found = true; 42 | } 43 | } 44 | assert!(leader_found); 45 | } 46 | }); 47 | } 48 | 49 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 50 | #[test] 51 | #[cfg_attr(miri, ignore)] 52 | fn smoke_blocking() { 53 | future::block_on(async move { 54 | const N: usize = 10; 55 | 56 | let barrier = Arc::new(Barrier::new(N)); 57 | 58 | for _ in 0..10 { 59 | let (tx, rx) = flume::unbounded(); 60 | 61 | for _ in 0..N - 1 { 62 | let c = barrier.clone(); 63 | let tx = tx.clone(); 64 | 65 | thread::spawn(move || { 66 | let res = c.wait_blocking(); 67 | tx.send(res.is_leader()).unwrap(); 68 | }); 69 | } 70 | 71 | // At this point, all spawned threads should be blocked, 72 | // so we shouldn't get anything from the channel. 73 | let res = rx.try_recv(); 74 | assert!(res.is_err()); 75 | 76 | let mut leader_found = barrier.wait_blocking().is_leader(); 77 | 78 | // Now, the barrier is cleared and we should get data. 79 | for _ in 0..N - 1 { 80 | if rx.recv_async().await.unwrap() { 81 | assert!(!leader_found); 82 | leader_found = true; 83 | } 84 | } 85 | assert!(leader_found); 86 | } 87 | }); 88 | } 89 | -------------------------------------------------------------------------------- /tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::{AtomicBool, Ordering}; 2 | use std::sync::Arc; 3 | use std::task::Context; 4 | 5 | use futures_lite::prelude::*; 6 | use waker_fn::waker_fn; 7 | 8 | pub fn check_yields_when_contended(contending_guard: G, acquire_future: impl Future) { 9 | let was_woken = Arc::new(AtomicBool::new(false)); 10 | let waker = { 11 | let was_woken = Arc::clone(&was_woken); 12 | waker_fn(move || was_woken.store(true, Ordering::SeqCst)) 13 | }; 14 | let mut cx = Context::from_waker(&waker); 15 | 16 | futures_lite::pin!(acquire_future); 17 | assert!(acquire_future.as_mut().poll(&mut cx).is_pending()); 18 | drop(contending_guard); 19 | assert!(was_woken.load(Ordering::SeqCst)); 20 | assert!(acquire_future.poll(&mut cx).is_ready()); 21 | } 22 | -------------------------------------------------------------------------------- /tests/loom.rs: -------------------------------------------------------------------------------- 1 | #![cfg(loom)] 2 | 3 | use loom::sync::{mpsc, Arc}; 4 | use loom::thread; 5 | 6 | use async_lock::Barrier; 7 | 8 | #[ignore] 9 | #[test] 10 | fn barrier_smoke() { 11 | loom::model(|| { 12 | const N: usize = 10; 13 | 14 | let barrier = Arc::new(Barrier::new(N)); 15 | 16 | for _ in 0..10 { 17 | let (tx, rx) = mpsc::channel(); 18 | 19 | for _ in 0..loom::MAX_THREADS - 1 { 20 | let c = barrier.clone(); 21 | let tx = tx.clone(); 22 | 23 | thread::spawn(move || { 24 | let res = c.wait_blocking(); 25 | tx.send(res.is_leader()).unwrap(); 26 | }); 27 | } 28 | 29 | // At this point, all spawned threads should be blocked, 30 | // so we shouldn't get anything from the channel. 31 | let res = rx.try_recv(); 32 | assert!(res.is_err()); 33 | 34 | let mut leader_found = barrier.wait_blocking().is_leader(); 35 | 36 | // Now, the barrier is cleared and we should get data. 37 | for _ in 0..N - 1 { 38 | if rx.recv().unwrap() { 39 | assert!(!leader_found); 40 | leader_found = true; 41 | } 42 | } 43 | assert!(leader_found); 44 | } 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /tests/mutex.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use std::sync::Arc; 4 | #[cfg(not(target_family = "wasm"))] 5 | use std::thread; 6 | 7 | use async_lock::Mutex; 8 | use futures_lite::future; 9 | 10 | use common::check_yields_when_contended; 11 | 12 | #[cfg(target_family = "wasm")] 13 | use wasm_bindgen_test::wasm_bindgen_test as test; 14 | 15 | #[cfg(target_family = "wasm")] 16 | wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); 17 | 18 | #[test] 19 | fn smoke() { 20 | future::block_on(async { 21 | let m = Mutex::new(()); 22 | drop(m.lock().await); 23 | drop(m.lock().await); 24 | }) 25 | } 26 | 27 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 28 | #[test] 29 | fn smoke_blocking() { 30 | let m = Mutex::new(()); 31 | drop(m.lock_blocking()); 32 | drop(m.lock_blocking()); 33 | } 34 | 35 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 36 | #[test] 37 | fn smoke_arc_blocking() { 38 | let m = Arc::new(Mutex::new(())); 39 | drop(m.lock_arc_blocking()); 40 | drop(m.lock_arc_blocking()); 41 | } 42 | 43 | #[test] 44 | fn try_lock() { 45 | let m = Mutex::new(()); 46 | *m.try_lock().unwrap() = (); 47 | } 48 | 49 | #[test] 50 | fn into_inner() { 51 | let m = Mutex::new(10i32); 52 | assert_eq!(m.into_inner(), 10); 53 | } 54 | 55 | #[test] 56 | fn get_mut() { 57 | let mut m = Mutex::new(10i32); 58 | *m.get_mut() = 20; 59 | assert_eq!(m.into_inner(), 20); 60 | } 61 | 62 | #[cfg(not(target_family = "wasm"))] 63 | #[test] 64 | fn contention() { 65 | future::block_on(async { 66 | let (tx, rx) = flume::unbounded(); 67 | 68 | let tx = Arc::new(tx); 69 | let mutex = Arc::new(Mutex::new(0i32)); 70 | let num_tasks = 100; 71 | 72 | for _ in 0..num_tasks { 73 | let tx = tx.clone(); 74 | let mutex = mutex.clone(); 75 | 76 | thread::spawn(|| { 77 | future::block_on(async move { 78 | let mut lock = mutex.lock().await; 79 | *lock += 1; 80 | tx.send_async(()).await.unwrap(); 81 | drop(lock); 82 | }) 83 | }); 84 | } 85 | 86 | for _ in 0..num_tasks { 87 | rx.recv_async().await.unwrap(); 88 | } 89 | 90 | let lock = mutex.lock().await; 91 | assert_eq!(num_tasks, *lock); 92 | }); 93 | } 94 | 95 | #[test] 96 | fn lifetime() { 97 | // Show that the future keeps the mutex alive. 98 | let _fut = { 99 | let mutex = Arc::new(Mutex::new(0i32)); 100 | mutex.lock_arc() 101 | }; 102 | } 103 | 104 | #[test] 105 | fn yields_when_contended() { 106 | let m = Mutex::new(()); 107 | check_yields_when_contended(m.try_lock().unwrap(), m.lock()); 108 | 109 | let m = Arc::new(m); 110 | check_yields_when_contended(m.try_lock_arc().unwrap(), m.lock_arc()); 111 | } 112 | -------------------------------------------------------------------------------- /tests/rwlock.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use std::sync::atomic::{AtomicUsize, Ordering}; 4 | use std::sync::Arc; 5 | 6 | use common::check_yields_when_contended; 7 | 8 | #[cfg(not(target_family = "wasm"))] 9 | use futures_lite::prelude::*; 10 | #[cfg(not(target_family = "wasm"))] 11 | use std::thread; 12 | 13 | use futures_lite::future; 14 | 15 | use async_lock::{ 16 | RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard, 17 | RwLockUpgradableReadGuardArc, 18 | }; 19 | 20 | #[cfg(target_family = "wasm")] 21 | use wasm_bindgen_test::wasm_bindgen_test as test; 22 | 23 | #[cfg(target_family = "wasm")] 24 | wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); 25 | 26 | #[cfg(not(target_family = "wasm"))] 27 | fn spawn(f: impl Future + Send + 'static) -> future::Boxed { 28 | let (s, r) = flume::bounded(1); 29 | thread::spawn(move || { 30 | future::block_on(async { 31 | let _ = s.send_async(f.await).await; 32 | }) 33 | }); 34 | async move { r.recv_async().await.unwrap() }.boxed() 35 | } 36 | 37 | #[test] 38 | fn smoke() { 39 | future::block_on(async { 40 | let lock = RwLock::new(()); 41 | drop(lock.read().await); 42 | drop(lock.write().await); 43 | drop((lock.read().await, lock.read().await)); 44 | drop(lock.write().await); 45 | }); 46 | } 47 | 48 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 49 | #[test] 50 | fn smoke_blocking() { 51 | let lock = RwLock::new(()); 52 | drop(lock.read_blocking()); 53 | drop(lock.write_blocking()); 54 | drop((lock.read_blocking(), lock.read_blocking())); 55 | let read = lock.read_blocking(); 56 | let upgradabe = lock.upgradable_read_blocking(); 57 | drop(read); 58 | drop(RwLockUpgradableReadGuard::upgrade_blocking(upgradabe)); 59 | drop(lock.write_blocking()); 60 | } 61 | 62 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 63 | #[test] 64 | fn smoke_arc_blocking() { 65 | let lock = Arc::new(RwLock::new(())); 66 | drop(lock.read_arc_blocking()); 67 | drop(lock.write_arc_blocking()); 68 | drop((lock.read_arc_blocking(), lock.read_arc_blocking())); 69 | let read = lock.read_arc_blocking(); 70 | let upgradabe = lock.upgradable_read_arc_blocking(); 71 | drop(read); 72 | drop(RwLockUpgradableReadGuardArc::upgrade_blocking(upgradabe)); 73 | drop(lock.write_arc_blocking()); 74 | } 75 | 76 | #[test] 77 | fn try_write() { 78 | future::block_on(async { 79 | let lock = RwLock::new(0isize); 80 | let read_guard = lock.read().await; 81 | assert!(lock.try_write().is_none()); 82 | drop(read_guard); 83 | }); 84 | } 85 | 86 | #[test] 87 | fn into_inner() { 88 | let lock = RwLock::new(10); 89 | assert_eq!(lock.into_inner(), 10); 90 | } 91 | 92 | #[test] 93 | fn into_inner_and_drop() { 94 | struct Counter(Arc); 95 | 96 | impl Drop for Counter { 97 | fn drop(&mut self) { 98 | self.0.fetch_add(1, Ordering::SeqCst); 99 | } 100 | } 101 | 102 | let cnt = Arc::new(AtomicUsize::new(0)); 103 | let lock = RwLock::new(Counter(cnt.clone())); 104 | assert_eq!(cnt.load(Ordering::SeqCst), 0); 105 | 106 | { 107 | let _inner = lock.into_inner(); 108 | assert_eq!(cnt.load(Ordering::SeqCst), 0); 109 | } 110 | 111 | assert_eq!(cnt.load(Ordering::SeqCst), 1); 112 | } 113 | 114 | #[test] 115 | fn get_mut() { 116 | let mut lock = RwLock::new(10); 117 | *lock.get_mut() = 20; 118 | assert_eq!(lock.into_inner(), 20); 119 | } 120 | 121 | // Miri bug; this works when async is replaced with blocking 122 | #[cfg(not(target_family = "wasm"))] 123 | #[test] 124 | #[cfg_attr(miri, ignore)] 125 | fn contention() { 126 | const N: u32 = 10; 127 | const M: usize = if cfg!(miri) { 100 } else { 1000 }; 128 | 129 | let (tx, rx) = flume::unbounded(); 130 | let tx = Arc::new(tx); 131 | let rw = Arc::new(RwLock::new(())); 132 | 133 | // Spawn N tasks that randomly acquire the lock M times. 134 | for _ in 0..N { 135 | let tx = tx.clone(); 136 | let rw = rw.clone(); 137 | 138 | let _spawned = spawn(async move { 139 | for _ in 0..M { 140 | if fastrand::u32(..N) == 0 { 141 | drop(rw.write().await); 142 | } else { 143 | drop(rw.read().await); 144 | } 145 | } 146 | tx.send_async(()).await.unwrap(); 147 | }); 148 | } 149 | 150 | future::block_on(async move { 151 | for _ in 0..N { 152 | rx.recv_async().await.unwrap(); 153 | } 154 | }); 155 | } 156 | 157 | #[cfg(not(target_family = "wasm"))] 158 | #[test] 159 | #[cfg_attr(miri, ignore)] 160 | fn contention_arc() { 161 | const N: u32 = 10; 162 | const M: usize = if cfg!(miri) { 100 } else { 1000 }; 163 | 164 | let (tx, rx) = flume::unbounded(); 165 | let tx = Arc::new(tx); 166 | let rw = Arc::new(RwLock::new(())); 167 | 168 | // Spawn N tasks that randomly acquire the lock M times. 169 | for _ in 0..N { 170 | let tx = tx.clone(); 171 | let rw = rw.clone(); 172 | 173 | let _spawned = spawn(async move { 174 | for _ in 0..M { 175 | if fastrand::u32(..N) == 0 { 176 | drop(rw.write_arc().await); 177 | } else { 178 | drop(rw.read_arc().await); 179 | } 180 | } 181 | tx.send_async(()).await.unwrap(); 182 | }); 183 | } 184 | 185 | future::block_on(async move { 186 | for _ in 0..N { 187 | rx.recv_async().await.unwrap(); 188 | } 189 | }); 190 | } 191 | 192 | #[cfg(not(target_family = "wasm"))] 193 | #[test] 194 | fn writer_and_readers() { 195 | let lock = Arc::new(RwLock::new(0i32)); 196 | let (tx, rx) = flume::unbounded(); 197 | 198 | // Spawn a writer task. 199 | let _spawned = spawn({ 200 | let lock = lock.clone(); 201 | async move { 202 | let mut lock = lock.write().await; 203 | for _ in 0..1000 { 204 | let tmp = *lock; 205 | *lock = -1; 206 | future::yield_now().await; 207 | *lock = tmp + 1; 208 | } 209 | tx.send_async(()).await.unwrap(); 210 | } 211 | }); 212 | 213 | // Readers try to catch the writer in the act. 214 | let mut readers = Vec::new(); 215 | for _ in 0..5 { 216 | let lock = lock.clone(); 217 | readers.push(spawn(async move { 218 | for _ in 0..1000 { 219 | let lock = lock.read().await; 220 | assert!(*lock >= 0); 221 | } 222 | })); 223 | } 224 | 225 | future::block_on(async move { 226 | // Wait for readers to pass their asserts. 227 | for r in readers { 228 | r.await; 229 | } 230 | 231 | // Wait for writer to finish. 232 | rx.recv_async().await.unwrap(); 233 | let lock = lock.read().await; 234 | assert_eq!(*lock, 1000); 235 | }); 236 | } 237 | 238 | #[cfg(not(target_family = "wasm"))] 239 | #[test] 240 | fn writer_and_readers_arc() { 241 | let lock = Arc::new(RwLock::new(0i32)); 242 | let (tx, rx) = flume::unbounded(); 243 | 244 | // Spawn a writer task. 245 | let _spawned = spawn({ 246 | let lock = lock.clone(); 247 | async move { 248 | let mut lock = lock.write_arc().await; 249 | for _ in 0..1000 { 250 | let tmp = *lock; 251 | *lock = -1; 252 | future::yield_now().await; 253 | *lock = tmp + 1; 254 | } 255 | tx.send_async(()).await.unwrap(); 256 | } 257 | }); 258 | 259 | // Readers try to catch the writer in the act. 260 | let mut readers = Vec::new(); 261 | for _ in 0..5 { 262 | let lock = lock.clone(); 263 | readers.push(spawn(async move { 264 | for _ in 0..1000 { 265 | let lock = lock.read_arc().await; 266 | assert!(*lock >= 0); 267 | } 268 | })); 269 | } 270 | 271 | future::block_on(async move { 272 | // Wait for readers to pass their asserts. 273 | for r in readers { 274 | r.await; 275 | } 276 | 277 | // Wait for writer to finish. 278 | rx.recv_async().await.unwrap(); 279 | let lock = lock.read_arc().await; 280 | assert_eq!(*lock, 1000); 281 | }); 282 | } 283 | 284 | #[test] 285 | fn upgrade() { 286 | future::block_on(async { 287 | let lock: RwLock = RwLock::new(0); 288 | 289 | let read_guard = lock.read().await; 290 | let read_guard2 = lock.read().await; 291 | // Should be able to obtain an upgradable lock. 292 | let upgradable_guard = lock.upgradable_read().await; 293 | // Should be able to obtain a read lock when an upgradable lock is active. 294 | let read_guard3 = lock.read().await; 295 | assert_eq!(0, *read_guard3); 296 | drop(read_guard); 297 | drop(read_guard2); 298 | drop(read_guard3); 299 | 300 | // Writers should not pass. 301 | assert!(lock.try_write().is_none()); 302 | 303 | let mut write_guard = RwLockUpgradableReadGuard::try_upgrade(upgradable_guard).expect( 304 | "should be able to upgrade an upgradable lock because there are no more readers", 305 | ); 306 | *write_guard += 1; 307 | drop(write_guard); 308 | 309 | let read_guard = lock.read().await; 310 | assert_eq!(1, *read_guard) 311 | }); 312 | } 313 | 314 | #[test] 315 | fn upgrade_arc() { 316 | future::block_on(async { 317 | let lock: Arc> = Arc::new(RwLock::new(0)); 318 | 319 | let read_guard = lock.read_arc().await; 320 | let read_guard2 = lock.read_arc().await; 321 | // Should be able to obtain an upgradable lock. 322 | let upgradable_guard = lock.upgradable_read_arc().await; 323 | // Should be able to obtain a read lock when an upgradable lock is active. 324 | let read_guard3 = lock.read_arc().await; 325 | assert_eq!(0, *read_guard3); 326 | drop(read_guard); 327 | drop(read_guard2); 328 | drop(read_guard3); 329 | 330 | // Writers should not pass. 331 | assert!(lock.try_write().is_none()); 332 | 333 | let mut write_guard = RwLockUpgradableReadGuardArc::try_upgrade(upgradable_guard).expect( 334 | "should be able to upgrade an upgradable lock because there are no more readers", 335 | ); 336 | *write_guard += 1; 337 | drop(write_guard); 338 | 339 | let read_guard = lock.read_arc().await; 340 | assert_eq!(1, *read_guard) 341 | }); 342 | } 343 | 344 | #[test] 345 | fn not_upgrade() { 346 | future::block_on(async { 347 | let mutex: RwLock = RwLock::new(0); 348 | 349 | let read_guard = mutex.read().await; 350 | let read_guard2 = mutex.read().await; 351 | // Should be able to obtain an upgradable lock. 352 | let upgradable_guard = mutex.upgradable_read().await; 353 | // Should be able to obtain a shared lock when an upgradable lock is active. 354 | let read_guard3 = mutex.read().await; 355 | assert_eq!(0, *read_guard3); 356 | drop(read_guard); 357 | drop(read_guard2); 358 | drop(read_guard3); 359 | 360 | // Drop the upgradable lock. 361 | drop(upgradable_guard); 362 | 363 | assert_eq!(0, *(mutex.read().await)); 364 | 365 | // Should be able to acquire a write lock because there are no more readers. 366 | let mut write_guard = mutex.write().await; 367 | *write_guard += 1; 368 | drop(write_guard); 369 | 370 | let read_guard = mutex.read().await; 371 | assert_eq!(1, *read_guard) 372 | }); 373 | } 374 | 375 | #[test] 376 | fn not_upgrade_arc() { 377 | future::block_on(async { 378 | let mutex: Arc> = Arc::new(RwLock::new(0)); 379 | 380 | let read_guard = mutex.read_arc().await; 381 | let read_guard2 = mutex.read_arc().await; 382 | // Should be able to obtain an upgradable lock. 383 | let upgradable_guard = mutex.upgradable_read_arc().await; 384 | // Should be able to obtain a shared lock when an upgradable lock is active. 385 | let read_guard3 = mutex.read_arc().await; 386 | assert_eq!(0, *read_guard3); 387 | drop(read_guard); 388 | drop(read_guard2); 389 | drop(read_guard3); 390 | 391 | // Drop the upgradable lock. 392 | drop(upgradable_guard); 393 | 394 | assert_eq!(0, *(mutex.read_arc().await)); 395 | 396 | // Should be able to acquire a write lock because there are no more readers. 397 | let mut write_guard = mutex.write_arc().await; 398 | *write_guard += 1; 399 | drop(write_guard); 400 | 401 | let read_guard = mutex.read_arc().await; 402 | assert_eq!(1, *read_guard) 403 | }); 404 | } 405 | 406 | #[test] 407 | fn upgradable_with_concurrent_writer() { 408 | future::block_on(async { 409 | let lock: Arc> = Arc::new(RwLock::new(0)); 410 | let lock2 = lock.clone(); 411 | 412 | let upgradable_guard = lock.upgradable_read().await; 413 | 414 | future::or( 415 | async move { 416 | let mut write_guard = lock2.write().await; 417 | *write_guard = 1; 418 | }, 419 | async move { 420 | let mut write_guard = RwLockUpgradableReadGuard::upgrade(upgradable_guard).await; 421 | assert_eq!(*write_guard, 0); 422 | *write_guard = 2; 423 | }, 424 | ) 425 | .await; 426 | 427 | assert_eq!(2, *(lock.write().await)); 428 | 429 | let read_guard = lock.read().await; 430 | assert_eq!(2, *read_guard); 431 | }); 432 | } 433 | 434 | #[test] 435 | fn upgradable_with_concurrent_writer_arc() { 436 | future::block_on(async { 437 | let lock: Arc> = Arc::new(RwLock::new(0)); 438 | let lock2 = lock.clone(); 439 | 440 | let upgradable_guard = lock.upgradable_read_arc().await; 441 | 442 | future::or( 443 | async move { 444 | let mut write_guard = lock2.write_arc().await; 445 | *write_guard = 1; 446 | }, 447 | async move { 448 | let mut write_guard = RwLockUpgradableReadGuardArc::upgrade(upgradable_guard).await; 449 | assert_eq!(*write_guard, 0); 450 | *write_guard = 2; 451 | }, 452 | ) 453 | .await; 454 | 455 | assert_eq!(2, *(lock.write_arc().await)); 456 | 457 | let read_guard = lock.read_arc().await; 458 | assert_eq!(2, *read_guard); 459 | }); 460 | } 461 | 462 | #[test] 463 | fn yields_when_contended() { 464 | let rw = RwLock::new(()); 465 | 466 | check_yields_when_contended(rw.try_write().unwrap(), rw.read()); 467 | check_yields_when_contended(rw.try_write().unwrap(), rw.upgradable_read()); 468 | check_yields_when_contended(rw.try_write().unwrap(), rw.write()); 469 | 470 | check_yields_when_contended(rw.try_read().unwrap(), rw.write()); 471 | 472 | check_yields_when_contended(rw.try_upgradable_read().unwrap(), rw.write()); 473 | check_yields_when_contended(rw.try_upgradable_read().unwrap(), rw.upgradable_read()); 474 | 475 | let upgradable = rw.try_upgradable_read().unwrap(); 476 | check_yields_when_contended( 477 | rw.try_read().unwrap(), 478 | RwLockUpgradableReadGuard::upgrade(upgradable), 479 | ); 480 | } 481 | 482 | #[test] 483 | fn yields_when_contended_arc() { 484 | let rw = Arc::new(RwLock::new(())); 485 | 486 | check_yields_when_contended(rw.try_write_arc().unwrap(), rw.read_arc()); 487 | check_yields_when_contended(rw.try_write_arc().unwrap(), rw.upgradable_read_arc()); 488 | check_yields_when_contended(rw.try_write_arc().unwrap(), rw.write_arc()); 489 | 490 | check_yields_when_contended(rw.try_read_arc().unwrap(), rw.write_arc()); 491 | 492 | check_yields_when_contended(rw.try_upgradable_read_arc().unwrap(), rw.write_arc()); 493 | check_yields_when_contended( 494 | rw.try_upgradable_read_arc().unwrap(), 495 | rw.upgradable_read_arc(), 496 | ); 497 | 498 | let upgradable = rw.try_upgradable_read_arc().unwrap(); 499 | check_yields_when_contended( 500 | rw.try_read_arc().unwrap(), 501 | RwLockUpgradableReadGuardArc::upgrade(upgradable), 502 | ); 503 | } 504 | 505 | #[test] 506 | fn cancellation() { 507 | future::block_on(async { 508 | let rw = RwLock::new(()); 509 | 510 | drop(rw.read()); 511 | 512 | drop(rw.upgradable_read()); 513 | 514 | drop(rw.write()); 515 | 516 | let read = rw.read().await; 517 | drop(read); 518 | 519 | let upgradable_read = rw.upgradable_read().await; 520 | drop(upgradable_read); 521 | 522 | let write = rw.write().await; 523 | drop(write); 524 | 525 | let upgradable_read = rw.upgradable_read().await; 526 | drop(RwLockUpgradableReadGuard::upgrade(upgradable_read)); 527 | 528 | let upgradable_read = rw.upgradable_read().await; 529 | let write = RwLockUpgradableReadGuard::upgrade(upgradable_read).await; 530 | drop(write); 531 | }); 532 | } 533 | 534 | #[test] 535 | fn arc_rwlock_refcounts() { 536 | future::block_on(async { 537 | let rw = Arc::new(RwLock::new(())); 538 | assert_eq!(Arc::strong_count(&rw), 1); 539 | 540 | drop(rw.read_arc()); 541 | assert_eq!(Arc::strong_count(&rw), 1); 542 | 543 | drop(rw.upgradable_read_arc()); 544 | assert_eq!(Arc::strong_count(&rw), 1); 545 | 546 | drop(rw.write()); 547 | assert_eq!(Arc::strong_count(&rw), 1); 548 | 549 | let read = rw.read_arc().await; 550 | assert_eq!(Arc::strong_count(&rw), 2); 551 | drop(read); 552 | assert_eq!(Arc::strong_count(&rw), 1); 553 | 554 | let upgradable_read = rw.upgradable_read_arc().await; 555 | assert_eq!(Arc::strong_count(&rw), 2); 556 | drop(upgradable_read); 557 | assert_eq!(Arc::strong_count(&rw), 1); 558 | 559 | let write = rw.write_arc().await; 560 | assert_eq!(Arc::strong_count(&rw), 2); 561 | drop(write); 562 | assert_eq!(Arc::strong_count(&rw), 1); 563 | 564 | let upgradable_read = rw.upgradable_read_arc().await; 565 | assert_eq!(Arc::strong_count(&rw), 2); 566 | drop(RwLockUpgradableReadGuardArc::upgrade(upgradable_read)); 567 | assert_eq!(Arc::strong_count(&rw), 1); 568 | 569 | let upgradable_read = rw.upgradable_read_arc().await; 570 | assert_eq!(Arc::strong_count(&rw), 2); 571 | let write = RwLockUpgradableReadGuardArc::upgrade(upgradable_read).await; 572 | assert_eq!(Arc::strong_count(&rw), 2); 573 | drop(write); 574 | assert_eq!(Arc::strong_count(&rw), 1); 575 | }); 576 | } 577 | 578 | // We are testing that this compiles. 579 | fn _covariance_test<'g>(guard: RwLockReadGuard<'g, &'static ()>) { 580 | let _: RwLockReadGuard<'g, &'g ()> = guard; 581 | } 582 | 583 | // We are testing that this compiles. 584 | fn _covariance_test_arc( 585 | guard: RwLockReadGuardArc<&'static ()>, 586 | mut _guard_2: RwLockReadGuardArc<&()>, 587 | ) { 588 | _guard_2 = guard; 589 | } 590 | -------------------------------------------------------------------------------- /tests/semaphore.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use std::future::Future; 4 | use std::mem::forget; 5 | use std::pin::Pin; 6 | use std::sync::{ 7 | atomic::{AtomicUsize, Ordering}, 8 | mpsc, Arc, 9 | }; 10 | use std::task::Context; 11 | use std::task::Poll; 12 | use std::thread; 13 | 14 | use common::check_yields_when_contended; 15 | 16 | use async_lock::Semaphore; 17 | use futures_lite::{future, pin}; 18 | 19 | #[test] 20 | fn try_acquire() { 21 | let s = Semaphore::new(2); 22 | let g1 = s.try_acquire().unwrap(); 23 | let _g2 = s.try_acquire().unwrap(); 24 | 25 | assert!(s.try_acquire().is_none()); 26 | drop(g1); 27 | assert!(s.try_acquire().is_some()); 28 | } 29 | 30 | #[test] 31 | fn stress() { 32 | const COUNT: usize = if cfg!(miri) { 500 } else { 10_000 }; 33 | 34 | let s = Arc::new(Semaphore::new(5)); 35 | let (tx, rx) = mpsc::channel::<()>(); 36 | 37 | for _ in 0..50 { 38 | let s = s.clone(); 39 | let tx = tx.clone(); 40 | 41 | thread::spawn(move || { 42 | future::block_on(async { 43 | for _ in 0..COUNT { 44 | s.acquire().await; 45 | } 46 | drop(tx); 47 | }) 48 | }); 49 | } 50 | 51 | drop(tx); 52 | let _ = rx.recv(); 53 | 54 | let _g1 = s.try_acquire().unwrap(); 55 | let g2 = s.try_acquire().unwrap(); 56 | let _g3 = s.try_acquire().unwrap(); 57 | let _g4 = s.try_acquire().unwrap(); 58 | let _g5 = s.try_acquire().unwrap(); 59 | 60 | assert!(s.try_acquire().is_none()); 61 | drop(g2); 62 | assert!(s.try_acquire().is_some()); 63 | } 64 | 65 | #[test] 66 | fn as_mutex() { 67 | let s = Arc::new(Semaphore::new(1)); 68 | let s2 = s.clone(); 69 | let _t = thread::spawn(move || { 70 | future::block_on(async { 71 | let _g = s2.acquire().await; 72 | }); 73 | }); 74 | future::block_on(async { 75 | let _g = s.acquire().await; 76 | }); 77 | } 78 | 79 | #[test] 80 | fn multi_resource() { 81 | let s = Arc::new(Semaphore::new(2)); 82 | let s2 = s.clone(); 83 | let (tx1, rx1) = mpsc::channel(); 84 | let (tx2, rx2) = mpsc::channel(); 85 | let _t = thread::spawn(move || { 86 | future::block_on(async { 87 | let _g = s2.acquire().await; 88 | let _ = rx2.recv(); 89 | tx1.send(()).unwrap(); 90 | }); 91 | }); 92 | future::block_on(async { 93 | let _g = s.acquire().await; 94 | tx2.send(()).unwrap(); 95 | rx1.recv().unwrap(); 96 | }); 97 | } 98 | 99 | #[test] 100 | fn lifetime() { 101 | // Show that the future keeps the semaphore alive. 102 | let _fut = { 103 | let mutex = Arc::new(Semaphore::new(2)); 104 | mutex.acquire_arc() 105 | }; 106 | } 107 | 108 | #[test] 109 | fn yields_when_contended() { 110 | let s = Semaphore::new(1); 111 | check_yields_when_contended(s.try_acquire().unwrap(), s.acquire()); 112 | 113 | let s = Arc::new(s); 114 | check_yields_when_contended(s.try_acquire_arc().unwrap(), s.acquire_arc()); 115 | } 116 | 117 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 118 | #[test] 119 | fn smoke_blocking() { 120 | let s = Semaphore::new(2); 121 | let g1 = s.acquire_blocking(); 122 | let _g2 = s.acquire_blocking(); 123 | assert!(s.try_acquire().is_none()); 124 | drop(g1); 125 | assert!(s.try_acquire().is_some()); 126 | } 127 | 128 | #[cfg(all(feature = "std", not(target_family = "wasm")))] 129 | #[test] 130 | fn smoke_arc_blocking() { 131 | let s = Arc::new(Semaphore::new(2)); 132 | let g1 = s.acquire_arc_blocking(); 133 | let _g2 = s.acquire_arc_blocking(); 134 | assert!(s.try_acquire().is_none()); 135 | drop(g1); 136 | assert!(s.try_acquire().is_some()); 137 | } 138 | 139 | #[test] 140 | fn add_permits() { 141 | static COUNTER: AtomicUsize = AtomicUsize::new(0); 142 | 143 | let s = Arc::new(Semaphore::new(0)); 144 | let (tx, rx) = mpsc::channel::<()>(); 145 | 146 | for _ in 0..50 { 147 | let s = s.clone(); 148 | let tx = tx.clone(); 149 | 150 | thread::spawn(move || { 151 | future::block_on(async { 152 | let perm = s.acquire().await; 153 | forget(perm); 154 | COUNTER.fetch_add(1, Ordering::Relaxed); 155 | drop(tx); 156 | }) 157 | }); 158 | } 159 | 160 | assert_eq!(COUNTER.load(Ordering::Relaxed), 0); 161 | 162 | s.add_permits(50); 163 | 164 | drop(tx); 165 | let _ = rx.recv(); 166 | 167 | assert_eq!(COUNTER.load(Ordering::Relaxed), 50); 168 | } 169 | 170 | #[test] 171 | fn add_permits_2() { 172 | future::block_on(AddPermitsTest); 173 | } 174 | 175 | struct AddPermitsTest; 176 | 177 | impl Future for AddPermitsTest { 178 | type Output = (); 179 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { 180 | let s = Semaphore::new(0); 181 | let acq = s.acquire(); 182 | pin!(acq); 183 | let acq_2 = s.acquire(); 184 | pin!(acq_2); 185 | assert!(acq.as_mut().poll(cx).is_pending()); 186 | assert!(acq_2.as_mut().poll(cx).is_pending()); 187 | s.add_permits(1); 188 | let g = acq.poll(cx); 189 | assert!(g.is_ready()); 190 | assert!(acq_2.poll(cx).is_pending()); 191 | 192 | Poll::Ready(()) 193 | } 194 | } 195 | --------------------------------------------------------------------------------