diff options
Diffstat (limited to 'vendor/crossbeam-utils')
30 files changed, 0 insertions, 5980 deletions
diff --git a/vendor/crossbeam-utils/.cargo-checksum.json b/vendor/crossbeam-utils/.cargo-checksum.json deleted file mode 100644 index 6614d3c..0000000 --- a/vendor/crossbeam-utils/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"3ae71b814876464d7d5a142d7b8b43a8a1564bf9e27fec1c6515001148ab6d48","Cargo.toml":"732d648b48238c27467bc79908c3ee7a0cd76330be5874ee9708c98b84472356","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"3c82bbb994f54ab76a9ed30a42dfd095c6e636258d379b9be3fbf66324310e71","benches/atomic_cell.rs":"c927eb3cd1e5ecc4b91adbc3bde98af15ffab4086190792ba64d5cde0e24df3d","build-common.rs":"502cb7494549bed6fa10ac7bea36e880eeb60290dc69b679ac5c92b376469562","build.rs":"34da4dc8f582959d727db84557cce37e1d2d54e8db78d355135774e70e0a7864","no_atomic.rs":"31a8276afd38e39987a169eeb02e9bed32670de5ca36d7eb74aab7e506cf9dc4","src/atomic/atomic_cell.rs":"cc7078265c6df82f544eb1adf0962ee9fffbb650b8f793d57047afbf205022ac","src/atomic/consume.rs":"381c2a8b13312ca0525d53ca1b7d0d4f525ddb154951fa3e216b061ad22012ff","src/atomic/mod.rs":"8157f0652fc4ac35c0a26ac6f4e9e2600fb7198c9560ff5e8297778722ca35dc","src/atomic/seq_lock.rs":"27182e6b87a9db73c5f6831759f8625f9fcdec3c2828204c444aef04f427735a","src/atomic/seq_lock_wide.rs":"9888dd03116bb89ca36d4ab8d5a0b5032107a2983a7eb8024454263b09080088","src/backoff.rs":"8715f0303ec91d1847c8ac3fc24bcc002a22a7284ade610e5eff4181f85827c7","src/cache_padded.rs":"e5a4cb14c343f161a01692dddc91efa441724dff980e0a74690faf32ef21e076","src/lib.rs":"bf2858bdbf5fb86588dba6566475d6c3c4567f892c0c885d27543a4622b34b16","src/sync/mod.rs":"eca73c04f821859b8434d2b93db87d160dc6a3f65498ca201cd40d732ca4c134","src/sync/once_lock.rs":"aa8f957604d1119c4fc7038a18c14a6281230e81005f31201c099acff284ad4b","src/sync/parker.rs":"698996e7530da1f3815df11c89df7d916155229cbfd022cccbd555f1d1d31985","src/sync/sharded_lock.rs":"f27cff33fd00cb6cee51cdb2d429df99ae4b81a1fefb99655ae7e3506f534fd1","src/sync/wait_group.rs":"3e339aab014f50e214fea535c841755113ea058153378ed54e50a4acb403c937","src/thread.rs":"b74bf00f0ea00fa1e60277af417fbd79bc0a8833d6d9633d7a85c86b59eba04c","tests/atomic_cell.rs":"da40f3badd2600ae0f03649ad433eac7b5cc769acf861dfc17f1e048d2786af7","tests/cache_padded.rs":"1bfaff8354c8184e1ee1f902881ca9400b60effb273b0d3f752801a483d2b66d","tests/parker.rs":"6def4721287d9d70b1cfd63ebb34e1c83fbb3376edbad2bc8aac6ef69dd99d20","tests/sharded_lock.rs":"314adeb8a651a28935f7a49c9a261b8fa1fd82bf6a16c865a5aced6216d7e40b","tests/thread.rs":"9a7d7d3028c552fd834c68598b04a1cc252a816bc20ab62cec060d6cd09cab10","tests/wait_group.rs":"2a41533a5f7f113d19cd2bdafcc2abf86509109652274156efdd74abd00896b6"},"package":"c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"}
\ No newline at end of file diff --git a/vendor/crossbeam-utils/CHANGELOG.md b/vendor/crossbeam-utils/CHANGELOG.md deleted file mode 100644 index 34c6bbd..0000000 --- a/vendor/crossbeam-utils/CHANGELOG.md +++ /dev/null @@ -1,231 +0,0 @@ -# Version 0.8.18 - -- Relax the minimum supported Rust version to 1.60. (#1056) -- Improve scalability of `AtomicCell` fallback. (#1055) - -# Version 0.8.17 - -- Bump the minimum supported Rust version to 1.61. (#1037) -- Improve support for targets without atomic CAS or 64-bit atomic. (#1037) -- Always implement `UnwindSafe` and `RefUnwindSafe` for `AtomicCell`. (#1045) -- Improve compatibility with Miri, TSan, and loom. (#995, #1003) -- Improve compatibility with unstable `oom=panic`. (#1045) -- Improve implementation of `CachePadded`. (#1014, #1025) -- Update `loom` dependency to 0.7. - -# Version 0.8.16 - -- Improve implementation of `CachePadded`. (#967) - -# Version 0.8.15 - -- Add `#[clippy::has_significant_drop]` to `ShardedLock{Read,Write}Guard`. (#958) -- Improve handling of very large timeout. (#953) -- Soft-deprecate `thread::scope()` in favor of the more efficient `std::thread::scope` that stabilized on Rust 1.63. (#954) - -# Version 0.8.14 - -- Fix build script bug introduced in 0.8.13. (#932) - -# Version 0.8.13 - -**Note:** This release has been yanked due to regression fixed in 0.8.14. - -- Improve support for custom targets. (#922) - -# Version 0.8.12 - -- Removes the dependency on the `once_cell` crate to restore the MSRV. (#913) -- Work around [rust-lang#98302](https://github.com/rust-lang/rust/issues/98302), which causes compile error on windows-gnu when LTO is enabled. (#913) - -# Version 0.8.11 - -- Bump the minimum supported Rust version to 1.38. (#877) - -# Version 0.8.10 - -- Fix unsoundness of `AtomicCell` on types containing niches. (#834) - This fix contains breaking changes, but they are allowed because this is a soundness bug fix. See #834 for more. - -# Version 0.8.9 - -- Replace lazy_static with once_cell. (#817) - -# Version 0.8.8 - -- Fix a bug when unstable `loom` support is enabled. (#787) - -# Version 0.8.7 - -- Add `AtomicCell<{i*,u*}>::{fetch_max,fetch_min}`. (#785) -- Add `AtomicCell<{i*,u*,bool}>::fetch_nand`. (#785) -- Fix unsoundness of `AtomicCell<{i,u}64>` arithmetics on 32-bit targets that support `Atomic{I,U}64` (#781) - -# Version 0.8.6 - -**Note:** This release has been yanked. See [GHSA-qc84-gqf4-9926](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-qc84-gqf4-9926) for details. - -- Re-add `AtomicCell<{i,u}64>::{fetch_add,fetch_sub,fetch_and,fetch_or,fetch_xor}` that were accidentally removed in 0.8.0 on targets that do not support `Atomic{I,U}64`. (#767) -- Re-add `AtomicCell<{i,u}128>::{fetch_add,fetch_sub,fetch_and,fetch_or,fetch_xor}` that were accidentally removed in 0.8.0. (#767) - -# Version 0.8.5 - -**Note:** This release has been yanked. See [GHSA-qc84-gqf4-9926](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-qc84-gqf4-9926) for details. - -- Add `AtomicCell::fetch_update`. (#704) -- Support targets that do not have atomic CAS on stable Rust. (#698) - -# Version 0.8.4 - -**Note:** This release has been yanked. See [GHSA-qc84-gqf4-9926](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-qc84-gqf4-9926) for details. - -- Bump `loom` dependency to version 0.5. (#686) - -# Version 0.8.3 - -**Note:** This release has been yanked. See [GHSA-qc84-gqf4-9926](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-qc84-gqf4-9926) for details. - -- Make `loom` dependency optional. (#666) - -# Version 0.8.2 - -**Note:** This release has been yanked. See [GHSA-qc84-gqf4-9926](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-qc84-gqf4-9926) for details. - -- Deprecate `AtomicCell::compare_and_swap`. Use `AtomicCell::compare_exchange` instead. (#619) -- Add `Parker::park_deadline`. (#563) -- Improve implementation of `CachePadded`. (#636) -- Add unstable support for `loom`. (#487) - -# Version 0.8.1 - -**Note:** This release has been yanked. See [GHSA-qc84-gqf4-9926](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-qc84-gqf4-9926) for details. - -- Make `AtomicCell::is_lock_free` always const fn. (#600) -- Fix a bug in `seq_lock_wide`. (#596) -- Remove `const_fn` dependency. (#600) -- `crossbeam-utils` no longer fails to compile if unable to determine rustc version. Instead, it now displays a warning. (#604) - -# Version 0.8.0 - -**Note:** This release has been yanked. See [GHSA-qc84-gqf4-9926](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-qc84-gqf4-9926) for details. - -- Bump the minimum supported Rust version to 1.36. -- Remove deprecated `AtomicCell::get_mut()` and `Backoff::is_complete()` methods. -- Remove `alloc` feature. -- Make `CachePadded::new()` const function. -- Make `AtomicCell::is_lock_free()` const function at 1.46+. -- Implement `From<T>` for `AtomicCell<T>`. - -# Version 0.7.2 - -- Fix bug in release (yanking 0.7.1) - -# Version 0.7.1 - -- Bump `autocfg` dependency to version 1.0. (#460) -- Make `AtomicCell` lockfree for u8, u16, u32, u64 sized values at 1.34+. (#454) - -# Version 0.7.0 - -- Bump the minimum required version to 1.28. -- Fix breakage with nightly feature due to rust-lang/rust#65214. -- Apply `#[repr(transparent)]` to `AtomicCell`. -- Make `AtomicCell::new()` const function at 1.31+. - -# Version 0.6.6 - -- Add `UnwindSafe` and `RefUnwindSafe` impls for `AtomicCell`. -- Add `AtomicCell::as_ptr()`. -- Add `AtomicCell::take()`. -- Fix a bug in `AtomicCell::compare_exchange()` and `AtomicCell::compare_and_swap()`. -- Various documentation improvements. - -# Version 0.6.5 - -- Rename `Backoff::is_complete()` to `Backoff::is_completed()`. - -# Version 0.6.4 - -- Add `WaitGroup`, `ShardedLock`, and `Backoff`. -- Add `fetch_*` methods for `AtomicCell<i128>` and `AtomicCell<u128>`. -- Expand documentation. - -# Version 0.6.3 - -- Add `AtomicCell`. -- Improve documentation. - -# Version 0.6.2 - -- Add `Parker`. -- Improve documentation. - -# Version 0.6.1 - -- Fix a soundness bug in `Scope::spawn()`. -- Remove the `T: 'scope` bound on `ScopedJoinHandle`. - -# Version 0.6.0 - -- Move `AtomicConsume` to `atomic` module. -- `scope()` returns a `Result` of thread joins. -- Remove `spawn_unchecked`. -- Fix a soundness bug due to incorrect lifetimes. -- Improve documentation. -- Support nested scoped spawns. -- Implement `Copy`, `Hash`, `PartialEq`, and `Eq` for `CachePadded`. -- Add `CachePadded::into_inner()`. - -# Version 0.5.0 - -- Reorganize sub-modules and rename functions. - -# Version 0.4.1 - -- Fix a documentation link. - -# Version 0.4.0 - -- `CachePadded` supports types bigger than 64 bytes. -- Fix a bug in scoped threads where unitialized memory was being dropped. -- Minimum required Rust version is now 1.25. - -# Version 0.3.2 - -- Mark `load_consume` with `#[inline]`. - -# Version 0.3.1 - -- `load_consume` on ARM and AArch64. - -# Version 0.3.0 - -- Add `join` for scoped thread API. -- Add `load_consume` for atomic load-consume memory ordering. -- Remove `AtomicOption`. - -# Version 0.2.2 - -- Support Rust 1.12.1. -- Call `T::clone` when cloning a `CachePadded<T>`. - -# Version 0.2.1 - -- Add `use_std` feature. - -# Version 0.2.0 - -- Add `nightly` feature. -- Use `repr(align(64))` on `CachePadded` with the `nightly` feature. -- Implement `Drop` for `CachePadded<T>`. -- Implement `Clone` for `CachePadded<T>`. -- Implement `From<T>` for `CachePadded<T>`. -- Implement better `Debug` for `CachePadded<T>`. -- Write more tests. -- Add this changelog. -- Change cache line length to 64 bytes. -- Remove `ZerosValid`. - -# Version 0.1.0 - -- Old implementation of `CachePadded` from `crossbeam` version 0.3.0 diff --git a/vendor/crossbeam-utils/Cargo.toml b/vendor/crossbeam-utils/Cargo.toml deleted file mode 100644 index b429d0a..0000000 --- a/vendor/crossbeam-utils/Cargo.toml +++ /dev/null @@ -1,48 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.60" -name = "crossbeam-utils" -version = "0.8.18" -description = "Utilities for concurrent programming" -homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" -readme = "README.md" -keywords = [ - "scoped", - "thread", - "atomic", - "cache", -] -categories = [ - "algorithms", - "concurrency", - "data-structures", - "no-std", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/crossbeam-rs/crossbeam" - -[dependencies.cfg-if] -version = "1" - -[dev-dependencies.rand] -version = "0.8" - -[features] -default = ["std"] -nightly = [] -std = [] - -[target."cfg(crossbeam_loom)".dependencies.loom] -version = "0.7.1" -optional = true diff --git a/vendor/crossbeam-utils/LICENSE-APACHE b/vendor/crossbeam-utils/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/vendor/crossbeam-utils/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/crossbeam-utils/LICENSE-MIT b/vendor/crossbeam-utils/LICENSE-MIT deleted file mode 100644 index 068d491..0000000 --- a/vendor/crossbeam-utils/LICENSE-MIT +++ /dev/null @@ -1,27 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2019 The Crossbeam Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/crossbeam-utils/README.md b/vendor/crossbeam-utils/README.md deleted file mode 100644 index 7d6a679..0000000 --- a/vendor/crossbeam-utils/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Crossbeam Utils - -[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( -https://github.com/crossbeam-rs/crossbeam/actions) -[![License](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils#license) -[![Cargo](https://img.shields.io/crates/v/crossbeam-utils.svg)]( -https://crates.io/crates/crossbeam-utils) -[![Documentation](https://docs.rs/crossbeam-utils/badge.svg)]( -https://docs.rs/crossbeam-utils) -[![Rust 1.60+](https://img.shields.io/badge/rust-1.60+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) - -This crate provides miscellaneous tools for concurrent programming: - -#### Atomics - -* [`AtomicCell`], a thread-safe mutable memory location.<sup>(no_std)</sup> -* [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering.<sup>(no_std)</sup> - -#### Thread synchronization - -* [`Parker`], a thread parking primitive. -* [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. -* [`WaitGroup`], for synchronizing the beginning or end of some computation. - -#### Utilities - -* [`Backoff`], for exponential backoff in spin loops.<sup>(no_std)</sup> -* [`CachePadded`], for padding and aligning a value to the length of a cache line.<sup>(no_std)</sup> -* [`scope`], for spawning threads that borrow local variables from the stack. - -*Features marked with <sup>(no_std)</sup> can be used in `no_std` environments.*<br/> - -[`AtomicCell`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/atomic/struct.AtomicCell.html -[`AtomicConsume`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/atomic/trait.AtomicConsume.html -[`Parker`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/sync/struct.Parker.html -[`ShardedLock`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/sync/struct.ShardedLock.html -[`WaitGroup`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/sync/struct.WaitGroup.html -[`Backoff`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/struct.Backoff.html -[`CachePadded`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/struct.CachePadded.html -[`scope`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/thread/fn.scope.html - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -crossbeam-utils = "0.8" -``` - -## Compatibility - -Crossbeam Utils supports stable Rust releases going back at least six months, -and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.60. - -## License - -Licensed under either of - - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -#### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. diff --git a/vendor/crossbeam-utils/benches/atomic_cell.rs b/vendor/crossbeam-utils/benches/atomic_cell.rs deleted file mode 100644 index 844f7c0..0000000 --- a/vendor/crossbeam-utils/benches/atomic_cell.rs +++ /dev/null @@ -1,156 +0,0 @@ -#![feature(test)] - -extern crate test; - -use std::sync::Barrier; - -use crossbeam_utils::atomic::AtomicCell; -use crossbeam_utils::thread; - -#[bench] -fn load_u8(b: &mut test::Bencher) { - let a = AtomicCell::new(0u8); - let mut sum = 0; - b.iter(|| sum += a.load()); - test::black_box(sum); -} - -#[bench] -fn store_u8(b: &mut test::Bencher) { - let a = AtomicCell::new(0u8); - b.iter(|| a.store(1)); -} - -#[bench] -fn fetch_add_u8(b: &mut test::Bencher) { - let a = AtomicCell::new(0u8); - b.iter(|| a.fetch_add(1)); -} - -#[bench] -fn compare_exchange_u8(b: &mut test::Bencher) { - let a = AtomicCell::new(0u8); - let mut i = 0; - b.iter(|| { - let _ = a.compare_exchange(i, i.wrapping_add(1)); - i = i.wrapping_add(1); - }); -} - -#[bench] -fn concurrent_load_u8(b: &mut test::Bencher) { - const THREADS: usize = 2; - const STEPS: usize = 1_000_000; - - let start = Barrier::new(THREADS + 1); - let end = Barrier::new(THREADS + 1); - let exit = AtomicCell::new(false); - - let a = AtomicCell::new(0u8); - - thread::scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| loop { - start.wait(); - - let mut sum = 0; - for _ in 0..STEPS { - sum += a.load(); - } - test::black_box(sum); - - end.wait(); - if exit.load() { - break; - } - }); - } - - start.wait(); - end.wait(); - - b.iter(|| { - start.wait(); - end.wait(); - }); - - start.wait(); - exit.store(true); - end.wait(); - }) - .unwrap(); -} - -#[bench] -fn load_usize(b: &mut test::Bencher) { - let a = AtomicCell::new(0usize); - let mut sum = 0; - b.iter(|| sum += a.load()); - test::black_box(sum); -} - -#[bench] -fn store_usize(b: &mut test::Bencher) { - let a = AtomicCell::new(0usize); - b.iter(|| a.store(1)); -} - -#[bench] -fn fetch_add_usize(b: &mut test::Bencher) { - let a = AtomicCell::new(0usize); - b.iter(|| a.fetch_add(1)); -} - -#[bench] -fn compare_exchange_usize(b: &mut test::Bencher) { - let a = AtomicCell::new(0usize); - let mut i = 0; - b.iter(|| { - let _ = a.compare_exchange(i, i.wrapping_add(1)); - i = i.wrapping_add(1); - }); -} - -#[bench] -fn concurrent_load_usize(b: &mut test::Bencher) { - const THREADS: usize = 2; - const STEPS: usize = 1_000_000; - - let start = Barrier::new(THREADS + 1); - let end = Barrier::new(THREADS + 1); - let exit = AtomicCell::new(false); - - let a = AtomicCell::new(0usize); - - thread::scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| loop { - start.wait(); - - let mut sum = 0; - for _ in 0..STEPS { - sum += a.load(); - } - test::black_box(sum); - - end.wait(); - if exit.load() { - break; - } - }); - } - - start.wait(); - end.wait(); - - b.iter(|| { - start.wait(); - end.wait(); - }); - - start.wait(); - exit.store(true); - end.wait(); - }) - .unwrap(); -} diff --git a/vendor/crossbeam-utils/build-common.rs b/vendor/crossbeam-utils/build-common.rs deleted file mode 100644 index e91bb4d..0000000 --- a/vendor/crossbeam-utils/build-common.rs +++ /dev/null @@ -1,13 +0,0 @@ -// The target triplets have the form of 'arch-vendor-system'. -// -// When building for Linux (e.g. the 'system' part is -// 'linux-something'), replace the vendor with 'unknown' -// so that mapping to rust standard targets happens correctly. -fn convert_custom_linux_target(target: String) -> String { - let mut parts: Vec<&str> = target.split('-').collect(); - let system = parts.get(2); - if system == Some(&"linux") { - parts[1] = "unknown"; - }; - parts.join("-") -} diff --git a/vendor/crossbeam-utils/build.rs b/vendor/crossbeam-utils/build.rs deleted file mode 100644 index c71c231..0000000 --- a/vendor/crossbeam-utils/build.rs +++ /dev/null @@ -1,47 +0,0 @@ -// The rustc-cfg listed below are considered public API, but it is *unstable* -// and outside of the normal semver guarantees: -// -// - `crossbeam_no_atomic` -// Assume the target does *not* support any atomic operations. -// This is usually detected automatically by the build script, but you may -// need to enable it manually when building for custom targets or using -// non-cargo build systems that don't run the build script. -// -// With the exceptions mentioned above, the rustc-cfg emitted by the build -// script are *not* public API. - -#![warn(rust_2018_idioms)] - -use std::env; - -include!("no_atomic.rs"); -include!("build-common.rs"); - -fn main() { - println!("cargo:rerun-if-changed=no_atomic.rs"); - - let target = match env::var("TARGET") { - Ok(target) => convert_custom_linux_target(target), - Err(e) => { - println!( - "cargo:warning={}: unable to get TARGET environment variable: {}", - env!("CARGO_PKG_NAME"), - e - ); - return; - } - }; - - // Note that this is `no_`*, not `has_*`. This allows treating as the latest - // stable rustc is used when the build script doesn't run. This is useful - // for non-cargo build systems that don't run the build script. - if NO_ATOMIC.contains(&&*target) { - println!("cargo:rustc-cfg=crossbeam_no_atomic"); - } - - // `cfg(sanitize = "..")` is not stabilized. - let sanitize = env::var("CARGO_CFG_SANITIZE").unwrap_or_default(); - if sanitize.contains("thread") { - println!("cargo:rustc-cfg=crossbeam_sanitize_thread"); - } -} diff --git a/vendor/crossbeam-utils/no_atomic.rs b/vendor/crossbeam-utils/no_atomic.rs deleted file mode 100644 index b97f397..0000000 --- a/vendor/crossbeam-utils/no_atomic.rs +++ /dev/null @@ -1,12 +0,0 @@ -// This file is @generated by no_atomic.sh. -// It is not intended for manual editing. - -const NO_ATOMIC: &[&str] = &[ - "bpfeb-unknown-none", - "bpfel-unknown-none", - "mipsel-sony-psx", - "msp430-none-elf", - "riscv32i-unknown-none-elf", - "riscv32im-unknown-none-elf", - "riscv32imc-unknown-none-elf", -]; diff --git a/vendor/crossbeam-utils/src/atomic/atomic_cell.rs b/vendor/crossbeam-utils/src/atomic/atomic_cell.rs deleted file mode 100644 index 06ccf2e..0000000 --- a/vendor/crossbeam-utils/src/atomic/atomic_cell.rs +++ /dev/null @@ -1,1182 +0,0 @@ -// Necessary for implementing atomic methods for `AtomicUnit` -#![allow(clippy::unit_arg)] - -use crate::primitive::sync::atomic::{self, Ordering}; -use crate::CachePadded; -use core::cell::UnsafeCell; -use core::cmp; -use core::fmt; -use core::mem::{self, ManuallyDrop, MaybeUninit}; -use core::panic::{RefUnwindSafe, UnwindSafe}; -use core::ptr; - -use super::seq_lock::SeqLock; - -/// A thread-safe mutable memory location. -/// -/// This type is equivalent to [`Cell`], except it can also be shared among multiple threads. -/// -/// Operations on `AtomicCell`s use atomic instructions whenever possible, and synchronize using -/// global locks otherwise. You can call [`AtomicCell::<T>::is_lock_free()`] to check whether -/// atomic instructions or locks will be used. -/// -/// Atomic loads use the [`Acquire`] ordering and atomic stores use the [`Release`] ordering. -/// -/// [`Cell`]: std::cell::Cell -/// [`AtomicCell::<T>::is_lock_free()`]: AtomicCell::is_lock_free -/// [`Acquire`]: std::sync::atomic::Ordering::Acquire -/// [`Release`]: std::sync::atomic::Ordering::Release -#[repr(transparent)] -pub struct AtomicCell<T> { - /// The inner value. - /// - /// If this value can be transmuted into a primitive atomic type, it will be treated as such. - /// Otherwise, all potentially concurrent operations on this data will be protected by a global - /// lock. - /// - /// Using MaybeUninit to prevent code outside the cell from observing partially initialized state: - /// <https://github.com/crossbeam-rs/crossbeam/issues/833> - /// - /// Note: - /// - we'll never store uninitialized `T` due to our API only using initialized `T`. - /// - this `MaybeUninit` does *not* fix <https://github.com/crossbeam-rs/crossbeam/issues/315>. - value: UnsafeCell<MaybeUninit<T>>, -} - -unsafe impl<T: Send> Send for AtomicCell<T> {} -unsafe impl<T: Send> Sync for AtomicCell<T> {} - -impl<T> UnwindSafe for AtomicCell<T> {} -impl<T> RefUnwindSafe for AtomicCell<T> {} - -impl<T> AtomicCell<T> { - /// Creates a new atomic cell initialized with `val`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(7); - /// ``` - pub const fn new(val: T) -> AtomicCell<T> { - AtomicCell { - value: UnsafeCell::new(MaybeUninit::new(val)), - } - } - - /// Consumes the atomic and returns the contained value. - /// - /// This is safe because passing `self` by value guarantees that no other threads are - /// concurrently accessing the atomic data. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(7); - /// let v = a.into_inner(); - /// - /// assert_eq!(v, 7); - /// ``` - pub fn into_inner(self) -> T { - let this = ManuallyDrop::new(self); - // SAFETY: - // - passing `self` by value guarantees that no other threads are concurrently - // accessing the atomic data - // - the raw pointer passed in is valid because we got it from an owned value. - // - `ManuallyDrop` prevents double dropping `T` - unsafe { this.as_ptr().read() } - } - - /// Returns `true` if operations on values of this type are lock-free. - /// - /// If the compiler or the platform doesn't support the necessary atomic instructions, - /// `AtomicCell<T>` will use global locks for every potentially concurrent atomic operation. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// // This type is internally represented as `AtomicUsize` so we can just use atomic - /// // operations provided by it. - /// assert_eq!(AtomicCell::<usize>::is_lock_free(), true); - /// - /// // A wrapper struct around `isize`. - /// struct Foo { - /// bar: isize, - /// } - /// // `AtomicCell<Foo>` will be internally represented as `AtomicIsize`. - /// assert_eq!(AtomicCell::<Foo>::is_lock_free(), true); - /// - /// // Operations on zero-sized types are always lock-free. - /// assert_eq!(AtomicCell::<()>::is_lock_free(), true); - /// - /// // Very large types cannot be represented as any of the standard atomic types, so atomic - /// // operations on them will have to use global locks for synchronization. - /// assert_eq!(AtomicCell::<[u8; 1000]>::is_lock_free(), false); - /// ``` - pub const fn is_lock_free() -> bool { - atomic_is_lock_free::<T>() - } - - /// Stores `val` into the atomic cell. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(7); - /// - /// assert_eq!(a.load(), 7); - /// a.store(8); - /// assert_eq!(a.load(), 8); - /// ``` - pub fn store(&self, val: T) { - if mem::needs_drop::<T>() { - drop(self.swap(val)); - } else { - unsafe { - atomic_store(self.as_ptr(), val); - } - } - } - - /// Stores `val` into the atomic cell and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(7); - /// - /// assert_eq!(a.load(), 7); - /// assert_eq!(a.swap(8), 7); - /// assert_eq!(a.load(), 8); - /// ``` - pub fn swap(&self, val: T) -> T { - unsafe { atomic_swap(self.as_ptr(), val) } - } - - /// Returns a raw pointer to the underlying data in this atomic cell. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(5); - /// - /// let ptr = a.as_ptr(); - /// ``` - #[inline] - pub fn as_ptr(&self) -> *mut T { - self.value.get().cast::<T>() - } -} - -impl<T: Default> AtomicCell<T> { - /// Takes the value of the atomic cell, leaving `Default::default()` in its place. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(5); - /// let five = a.take(); - /// - /// assert_eq!(five, 5); - /// assert_eq!(a.into_inner(), 0); - /// ``` - pub fn take(&self) -> T { - self.swap(Default::default()) - } -} - -impl<T: Copy> AtomicCell<T> { - /// Loads a value from the atomic cell. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(7); - /// - /// assert_eq!(a.load(), 7); - /// ``` - pub fn load(&self) -> T { - unsafe { atomic_load(self.as_ptr()) } - } -} - -impl<T: Copy + Eq> AtomicCell<T> { - /// If the current value equals `current`, stores `new` into the atomic cell. - /// - /// The return value is always the previous value. If it is equal to `current`, then the value - /// was updated. - /// - /// # Examples - /// - /// ``` - /// # #![allow(deprecated)] - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(1); - /// - /// assert_eq!(a.compare_and_swap(2, 3), 1); - /// assert_eq!(a.load(), 1); - /// - /// assert_eq!(a.compare_and_swap(1, 2), 1); - /// assert_eq!(a.load(), 2); - /// ``` - // TODO: remove in the next major version. - #[deprecated(note = "Use `compare_exchange` instead")] - pub fn compare_and_swap(&self, current: T, new: T) -> T { - match self.compare_exchange(current, new) { - Ok(v) => v, - Err(v) => v, - } - } - - /// If the current value equals `current`, stores `new` into the atomic cell. - /// - /// The return value is a result indicating whether the new value was written and containing - /// the previous value. On success this value is guaranteed to be equal to `current`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(1); - /// - /// assert_eq!(a.compare_exchange(2, 3), Err(1)); - /// assert_eq!(a.load(), 1); - /// - /// assert_eq!(a.compare_exchange(1, 2), Ok(1)); - /// assert_eq!(a.load(), 2); - /// ``` - pub fn compare_exchange(&self, current: T, new: T) -> Result<T, T> { - unsafe { atomic_compare_exchange_weak(self.as_ptr(), current, new) } - } - - /// Fetches the value, and applies a function to it that returns an optional - /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else - /// `Err(previous_value)`. - /// - /// Note: This may call the function multiple times if the value has been changed from other threads in - /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied - /// only once to the stored value. - /// - /// # Examples - /// - /// ```rust - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(7); - /// assert_eq!(a.fetch_update(|_| None), Err(7)); - /// assert_eq!(a.fetch_update(|a| Some(a + 1)), Ok(7)); - /// assert_eq!(a.fetch_update(|a| Some(a + 1)), Ok(8)); - /// assert_eq!(a.load(), 9); - /// ``` - #[inline] - pub fn fetch_update<F>(&self, mut f: F) -> Result<T, T> - where - F: FnMut(T) -> Option<T>, - { - let mut prev = self.load(); - while let Some(next) = f(prev) { - match self.compare_exchange(prev, next) { - x @ Ok(_) => return x, - Err(next_prev) => prev = next_prev, - } - } - Err(prev) - } -} - -// `MaybeUninit` prevents `T` from being dropped, so we need to implement `Drop` -// for `AtomicCell` to avoid leaks of non-`Copy` types. -impl<T> Drop for AtomicCell<T> { - fn drop(&mut self) { - if mem::needs_drop::<T>() { - // SAFETY: - // - the mutable reference guarantees that no other threads are concurrently accessing the atomic data - // - the raw pointer passed in is valid because we got it from a reference - // - `MaybeUninit` prevents double dropping `T` - unsafe { - self.as_ptr().drop_in_place(); - } - } - } -} - -macro_rules! atomic { - // If values of type `$t` can be transmuted into values of the primitive atomic type `$atomic`, - // declares variable `$a` of type `$atomic` and executes `$atomic_op`, breaking out of the loop. - (@check, $t:ty, $atomic:ty, $a:ident, $atomic_op:expr) => { - if can_transmute::<$t, $atomic>() { - let $a: &$atomic; - break $atomic_op; - } - }; - - // If values of type `$t` can be transmuted into values of a primitive atomic type, declares - // variable `$a` of that type and executes `$atomic_op`. Otherwise, just executes - // `$fallback_op`. - ($t:ty, $a:ident, $atomic_op:expr, $fallback_op:expr) => { - loop { - atomic!(@check, $t, AtomicUnit, $a, $atomic_op); - - atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op); - atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op); - atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op); - #[cfg(target_has_atomic = "64")] - atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op); - // TODO: AtomicU128 is unstable - // atomic!(@check, $t, atomic::AtomicU128, $a, $atomic_op); - - break $fallback_op; - } - }; -} - -macro_rules! impl_arithmetic { - ($t:ty, fallback, $example:tt) => { - impl AtomicCell<$t> { - /// Increments the current value by `val` and returns the previous value. - /// - /// The addition wraps on overflow. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_add(3), 7); - /// assert_eq!(a.load(), 10); - /// ``` - #[inline] - pub fn fetch_add(&self, val: $t) -> $t { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = value.wrapping_add(val); - old - } - - /// Decrements the current value by `val` and returns the previous value. - /// - /// The subtraction wraps on overflow. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_sub(3), 7); - /// assert_eq!(a.load(), 4); - /// ``` - #[inline] - pub fn fetch_sub(&self, val: $t) -> $t { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = value.wrapping_sub(val); - old - } - - /// Applies bitwise "and" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_and(3), 7); - /// assert_eq!(a.load(), 3); - /// ``` - #[inline] - pub fn fetch_and(&self, val: $t) -> $t { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value &= val; - old - } - - /// Applies bitwise "nand" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_nand(3), 7); - /// assert_eq!(a.load(), !(7 & 3)); - /// ``` - #[inline] - pub fn fetch_nand(&self, val: $t) -> $t { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = !(old & val); - old - } - - /// Applies bitwise "or" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_or(16), 7); - /// assert_eq!(a.load(), 23); - /// ``` - #[inline] - pub fn fetch_or(&self, val: $t) -> $t { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value |= val; - old - } - - /// Applies bitwise "xor" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_xor(2), 7); - /// assert_eq!(a.load(), 5); - /// ``` - #[inline] - pub fn fetch_xor(&self, val: $t) -> $t { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value ^= val; - old - } - - /// Compares and sets the maximum of the current value and `val`, - /// and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_max(2), 7); - /// assert_eq!(a.load(), 7); - /// ``` - #[inline] - pub fn fetch_max(&self, val: $t) -> $t { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = cmp::max(old, val); - old - } - - /// Compares and sets the minimum of the current value and `val`, - /// and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_min(2), 7); - /// assert_eq!(a.load(), 2); - /// ``` - #[inline] - pub fn fetch_min(&self, val: $t) -> $t { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = cmp::min(old, val); - old - } - } - }; - ($t:ty, $atomic:ident, $example:tt) => { - impl AtomicCell<$t> { - /// Increments the current value by `val` and returns the previous value. - /// - /// The addition wraps on overflow. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_add(3), 7); - /// assert_eq!(a.load(), 10); - /// ``` - #[inline] - pub fn fetch_add(&self, val: $t) -> $t { - atomic! { - $t, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; - a.fetch_add(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = value.wrapping_add(val); - old - } - } - } - - /// Decrements the current value by `val` and returns the previous value. - /// - /// The subtraction wraps on overflow. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_sub(3), 7); - /// assert_eq!(a.load(), 4); - /// ``` - #[inline] - pub fn fetch_sub(&self, val: $t) -> $t { - atomic! { - $t, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; - a.fetch_sub(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = value.wrapping_sub(val); - old - } - } - } - - /// Applies bitwise "and" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_and(3), 7); - /// assert_eq!(a.load(), 3); - /// ``` - #[inline] - pub fn fetch_and(&self, val: $t) -> $t { - atomic! { - $t, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; - a.fetch_and(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value &= val; - old - } - } - } - - /// Applies bitwise "nand" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_nand(3), 7); - /// assert_eq!(a.load(), !(7 & 3)); - /// ``` - #[inline] - pub fn fetch_nand(&self, val: $t) -> $t { - atomic! { - $t, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; - a.fetch_nand(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = !(old & val); - old - } - } - } - - /// Applies bitwise "or" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_or(16), 7); - /// assert_eq!(a.load(), 23); - /// ``` - #[inline] - pub fn fetch_or(&self, val: $t) -> $t { - atomic! { - $t, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; - a.fetch_or(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value |= val; - old - } - } - } - - /// Applies bitwise "xor" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_xor(2), 7); - /// assert_eq!(a.load(), 5); - /// ``` - #[inline] - pub fn fetch_xor(&self, val: $t) -> $t { - atomic! { - $t, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; - a.fetch_xor(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value ^= val; - old - } - } - } - - /// Compares and sets the maximum of the current value and `val`, - /// and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_max(9), 7); - /// assert_eq!(a.load(), 9); - /// ``` - #[inline] - pub fn fetch_max(&self, val: $t) -> $t { - atomic! { - $t, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; - a.fetch_max(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = cmp::max(old, val); - old - } - } - } - - /// Compares and sets the minimum of the current value and `val`, - /// and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - #[doc = $example] - /// - /// assert_eq!(a.fetch_min(2), 7); - /// assert_eq!(a.load(), 2); - /// ``` - #[inline] - pub fn fetch_min(&self, val: $t) -> $t { - atomic! { - $t, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::$atomic) }; - a.fetch_min(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = cmp::min(old, val); - old - } - } - } - } - }; -} - -impl_arithmetic!(u8, AtomicU8, "let a = AtomicCell::new(7u8);"); -impl_arithmetic!(i8, AtomicI8, "let a = AtomicCell::new(7i8);"); -impl_arithmetic!(u16, AtomicU16, "let a = AtomicCell::new(7u16);"); -impl_arithmetic!(i16, AtomicI16, "let a = AtomicCell::new(7i16);"); - -impl_arithmetic!(u32, AtomicU32, "let a = AtomicCell::new(7u32);"); -impl_arithmetic!(i32, AtomicI32, "let a = AtomicCell::new(7i32);"); - -#[cfg(target_has_atomic = "64")] -impl_arithmetic!(u64, AtomicU64, "let a = AtomicCell::new(7u64);"); -#[cfg(target_has_atomic = "64")] -impl_arithmetic!(i64, AtomicI64, "let a = AtomicCell::new(7i64);"); -#[cfg(not(target_has_atomic = "64"))] -impl_arithmetic!(u64, fallback, "let a = AtomicCell::new(7u64);"); -#[cfg(not(target_has_atomic = "64"))] -impl_arithmetic!(i64, fallback, "let a = AtomicCell::new(7i64);"); - -// TODO: AtomicU128 is unstable -// impl_arithmetic!(u128, AtomicU128, "let a = AtomicCell::new(7u128);"); -// impl_arithmetic!(i128, AtomicI128, "let a = AtomicCell::new(7i128);"); -impl_arithmetic!(u128, fallback, "let a = AtomicCell::new(7u128);"); -impl_arithmetic!(i128, fallback, "let a = AtomicCell::new(7i128);"); - -impl_arithmetic!(usize, AtomicUsize, "let a = AtomicCell::new(7usize);"); -impl_arithmetic!(isize, AtomicIsize, "let a = AtomicCell::new(7isize);"); - -impl AtomicCell<bool> { - /// Applies logical "and" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(true); - /// - /// assert_eq!(a.fetch_and(true), true); - /// assert_eq!(a.load(), true); - /// - /// assert_eq!(a.fetch_and(false), true); - /// assert_eq!(a.load(), false); - /// ``` - #[inline] - pub fn fetch_and(&self, val: bool) -> bool { - atomic! { - bool, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) }; - a.fetch_and(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value &= val; - old - } - } - } - - /// Applies logical "nand" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(true); - /// - /// assert_eq!(a.fetch_nand(false), true); - /// assert_eq!(a.load(), true); - /// - /// assert_eq!(a.fetch_nand(true), true); - /// assert_eq!(a.load(), false); - /// - /// assert_eq!(a.fetch_nand(false), false); - /// assert_eq!(a.load(), true); - /// ``` - #[inline] - pub fn fetch_nand(&self, val: bool) -> bool { - atomic! { - bool, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) }; - a.fetch_nand(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value = !(old & val); - old - } - } - } - - /// Applies logical "or" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(false); - /// - /// assert_eq!(a.fetch_or(false), false); - /// assert_eq!(a.load(), false); - /// - /// assert_eq!(a.fetch_or(true), false); - /// assert_eq!(a.load(), true); - /// ``` - #[inline] - pub fn fetch_or(&self, val: bool) -> bool { - atomic! { - bool, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) }; - a.fetch_or(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value |= val; - old - } - } - } - - /// Applies logical "xor" to the current value and returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::atomic::AtomicCell; - /// - /// let a = AtomicCell::new(true); - /// - /// assert_eq!(a.fetch_xor(false), true); - /// assert_eq!(a.load(), true); - /// - /// assert_eq!(a.fetch_xor(true), true); - /// assert_eq!(a.load(), false); - /// ``` - #[inline] - pub fn fetch_xor(&self, val: bool) -> bool { - atomic! { - bool, _a, - { - let a = unsafe { &*(self.as_ptr() as *const atomic::AtomicBool) }; - a.fetch_xor(val, Ordering::AcqRel) - }, - { - let _guard = lock(self.as_ptr() as usize).write(); - let value = unsafe { &mut *(self.as_ptr()) }; - let old = *value; - *value ^= val; - old - } - } - } -} - -impl<T: Default> Default for AtomicCell<T> { - fn default() -> AtomicCell<T> { - AtomicCell::new(T::default()) - } -} - -impl<T> From<T> for AtomicCell<T> { - #[inline] - fn from(val: T) -> AtomicCell<T> { - AtomicCell::new(val) - } -} - -impl<T: Copy + fmt::Debug> fmt::Debug for AtomicCell<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("AtomicCell") - .field("value", &self.load()) - .finish() - } -} - -/// Returns `true` if values of type `A` can be transmuted into values of type `B`. -const fn can_transmute<A, B>() -> bool { - // Sizes must be equal, but alignment of `A` must be greater or equal than that of `B`. - (mem::size_of::<A>() == mem::size_of::<B>()) & (mem::align_of::<A>() >= mem::align_of::<B>()) -} - -/// Returns a reference to the global lock associated with the `AtomicCell` at address `addr`. -/// -/// This function is used to protect atomic data which doesn't fit into any of the primitive atomic -/// types in `std::sync::atomic`. Operations on such atomics must therefore use a global lock. -/// -/// However, there is not only one global lock but an array of many locks, and one of them is -/// picked based on the given address. Having many locks reduces contention and improves -/// scalability. -#[inline] -#[must_use] -fn lock(addr: usize) -> &'static SeqLock { - // The number of locks is a prime number because we want to make sure `addr % LEN` gets - // dispersed across all locks. - // - // Note that addresses are always aligned to some power of 2, depending on type `T` in - // `AtomicCell<T>`. If `LEN` was an even number, then `addr % LEN` would be an even number, - // too, which means only half of the locks would get utilized! - // - // It is also possible for addresses to accidentally get aligned to a number that is not a - // power of 2. Consider this example: - // - // ``` - // #[repr(C)] - // struct Foo { - // a: AtomicCell<u8>, - // b: u8, - // c: u8, - // } - // ``` - // - // Now, if we have a slice of type `&[Foo]`, it is possible that field `a` in all items gets - // stored at addresses that are multiples of 3. It'd be too bad if `LEN` was divisible by 3. - // In order to protect from such cases, we simply choose a large prime number for `LEN`. - const LEN: usize = 67; - #[allow(clippy::declare_interior_mutable_const)] - const L: CachePadded<SeqLock> = CachePadded::new(SeqLock::new()); - static LOCKS: [CachePadded<SeqLock>; LEN] = [L; LEN]; - - // If the modulus is a constant number, the compiler will use crazy math to transform this into - // a sequence of cheap arithmetic operations rather than using the slow modulo instruction. - &LOCKS[addr % LEN] -} - -/// An atomic `()`. -/// -/// All operations are noops. -struct AtomicUnit; - -impl AtomicUnit { - #[inline] - fn load(&self, _order: Ordering) {} - - #[inline] - fn store(&self, _val: (), _order: Ordering) {} - - #[inline] - fn swap(&self, _val: (), _order: Ordering) {} - - #[inline] - fn compare_exchange_weak( - &self, - _current: (), - _new: (), - _success: Ordering, - _failure: Ordering, - ) -> Result<(), ()> { - Ok(()) - } -} - -/// Returns `true` if operations on `AtomicCell<T>` are lock-free. -const fn atomic_is_lock_free<T>() -> bool { - atomic! { T, _a, true, false } -} - -/// Atomically reads data from `src`. -/// -/// This operation uses the `Acquire` ordering. If possible, an atomic instructions is used, and a -/// global lock otherwise. -unsafe fn atomic_load<T>(src: *mut T) -> T -where - T: Copy, -{ - atomic! { - T, a, - { - a = &*(src as *const _ as *const _); - mem::transmute_copy(&a.load(Ordering::Acquire)) - }, - { - let lock = lock(src as usize); - - // Try doing an optimistic read first. - if let Some(stamp) = lock.optimistic_read() { - // We need a volatile read here because other threads might concurrently modify the - // value. In theory, data races are *always* UB, even if we use volatile reads and - // discard the data when a data race is detected. The proper solution would be to - // do atomic reads and atomic writes, but we can't atomically read and write all - // kinds of data since `AtomicU8` is not available on stable Rust yet. - // Load as `MaybeUninit` because we may load a value that is not valid as `T`. - let val = ptr::read_volatile(src.cast::<MaybeUninit<T>>()); - - if lock.validate_read(stamp) { - return val.assume_init(); - } - } - - // Grab a regular write lock so that writers don't starve this load. - let guard = lock.write(); - let val = ptr::read(src); - // The value hasn't been changed. Drop the guard without incrementing the stamp. - guard.abort(); - val - } - } -} - -/// Atomically writes `val` to `dst`. -/// -/// This operation uses the `Release` ordering. If possible, an atomic instructions is used, and a -/// global lock otherwise. -unsafe fn atomic_store<T>(dst: *mut T, val: T) { - atomic! { - T, a, - { - a = &*(dst as *const _ as *const _); - a.store(mem::transmute_copy(&val), Ordering::Release); - mem::forget(val); - }, - { - let _guard = lock(dst as usize).write(); - ptr::write(dst, val); - } - } -} - -/// Atomically swaps data at `dst` with `val`. -/// -/// This operation uses the `AcqRel` ordering. If possible, an atomic instructions is used, and a -/// global lock otherwise. -unsafe fn atomic_swap<T>(dst: *mut T, val: T) -> T { - atomic! { - T, a, - { - a = &*(dst as *const _ as *const _); - let res = mem::transmute_copy(&a.swap(mem::transmute_copy(&val), Ordering::AcqRel)); - mem::forget(val); - res - }, - { - let _guard = lock(dst as usize).write(); - ptr::replace(dst, val) - } - } -} - -/// Atomically compares data at `dst` to `current` and, if equal byte-for-byte, exchanges data at -/// `dst` with `new`. -/// -/// Returns the old value on success, or the current value at `dst` on failure. -/// -/// This operation uses the `AcqRel` ordering. If possible, an atomic instructions is used, and a -/// global lock otherwise. -#[allow(clippy::let_unit_value)] -unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T, mut current: T, new: T) -> Result<T, T> -where - T: Copy + Eq, -{ - atomic! { - T, a, - { - a = &*(dst as *const _ as *const _); - let mut current_raw = mem::transmute_copy(¤t); - let new_raw = mem::transmute_copy(&new); - - loop { - match a.compare_exchange_weak( - current_raw, - new_raw, - Ordering::AcqRel, - Ordering::Acquire, - ) { - Ok(_) => break Ok(current), - Err(previous_raw) => { - let previous = mem::transmute_copy(&previous_raw); - - if !T::eq(&previous, ¤t) { - break Err(previous); - } - - // The compare-exchange operation has failed and didn't store `new`. The - // failure is either spurious, or `previous` was semantically equal to - // `current` but not byte-equal. Let's retry with `previous` as the new - // `current`. - current = previous; - current_raw = previous_raw; - } - } - } - }, - { - let guard = lock(dst as usize).write(); - - if T::eq(&*dst, ¤t) { - Ok(ptr::replace(dst, new)) - } else { - let val = ptr::read(dst); - // The value hasn't been changed. Drop the guard without incrementing the stamp. - guard.abort(); - Err(val) - } - } - } -} diff --git a/vendor/crossbeam-utils/src/atomic/consume.rs b/vendor/crossbeam-utils/src/atomic/consume.rs deleted file mode 100644 index ff8e316..0000000 --- a/vendor/crossbeam-utils/src/atomic/consume.rs +++ /dev/null @@ -1,111 +0,0 @@ -#[cfg(not(crossbeam_no_atomic))] -use core::sync::atomic::Ordering; - -/// Trait which allows reading from primitive atomic types with "consume" ordering. -pub trait AtomicConsume { - /// Type returned by `load_consume`. - type Val; - - /// Loads a value from the atomic using a "consume" memory ordering. - /// - /// This is similar to the "acquire" ordering, except that an ordering is - /// only guaranteed with operations that "depend on" the result of the load. - /// However consume loads are usually much faster than acquire loads on - /// architectures with a weak memory model since they don't require memory - /// fence instructions. - /// - /// The exact definition of "depend on" is a bit vague, but it works as you - /// would expect in practice since a lot of software, especially the Linux - /// kernel, rely on this behavior. - /// - /// This is currently only implemented on ARM and AArch64, where a fence - /// can be avoided. On other architectures this will fall back to a simple - /// `load(Ordering::Acquire)`. - fn load_consume(&self) -> Self::Val; -} - -#[cfg(not(crossbeam_no_atomic))] -// Miri and Loom don't support "consume" ordering and ThreadSanitizer doesn't treat -// load(Relaxed) + compiler_fence(Acquire) as "consume" load. -// LLVM generates machine code equivalent to fence(Acquire) in compiler_fence(Acquire) -// on PowerPC, MIPS, etc. (https://godbolt.org/z/hffvjvW7h), so for now the fence -// can be actually avoided here only on ARM and AArch64. See also -// https://github.com/rust-lang/rust/issues/62256. -#[cfg(all( - any(target_arch = "arm", target_arch = "aarch64"), - not(any(miri, crossbeam_loom, crossbeam_sanitize_thread)), -))] -macro_rules! impl_consume { - () => { - #[inline] - fn load_consume(&self) -> Self::Val { - use crate::primitive::sync::atomic::compiler_fence; - let result = self.load(Ordering::Relaxed); - compiler_fence(Ordering::Acquire); - result - } - }; -} - -#[cfg(not(crossbeam_no_atomic))] -#[cfg(not(all( - any(target_arch = "arm", target_arch = "aarch64"), - not(any(miri, crossbeam_loom, crossbeam_sanitize_thread)), -)))] -macro_rules! impl_consume { - () => { - #[inline] - fn load_consume(&self) -> Self::Val { - self.load(Ordering::Acquire) - } - }; -} - -macro_rules! impl_atomic { - ($atomic:ident, $val:ty) => { - #[cfg(not(crossbeam_no_atomic))] - impl AtomicConsume for core::sync::atomic::$atomic { - type Val = $val; - impl_consume!(); - } - #[cfg(crossbeam_loom)] - impl AtomicConsume for loom::sync::atomic::$atomic { - type Val = $val; - impl_consume!(); - } - }; -} - -impl_atomic!(AtomicBool, bool); -impl_atomic!(AtomicUsize, usize); -impl_atomic!(AtomicIsize, isize); -impl_atomic!(AtomicU8, u8); -impl_atomic!(AtomicI8, i8); -impl_atomic!(AtomicU16, u16); -impl_atomic!(AtomicI16, i16); -#[cfg(any(target_has_atomic = "32", not(target_pointer_width = "16")))] -impl_atomic!(AtomicU32, u32); -#[cfg(any(target_has_atomic = "32", not(target_pointer_width = "16")))] -impl_atomic!(AtomicI32, i32); -#[cfg(any( - target_has_atomic = "64", - not(any(target_pointer_width = "16", target_pointer_width = "32")), -))] -impl_atomic!(AtomicU64, u64); -#[cfg(any( - target_has_atomic = "64", - not(any(target_pointer_width = "16", target_pointer_width = "32")), -))] -impl_atomic!(AtomicI64, i64); - -#[cfg(not(crossbeam_no_atomic))] -impl<T> AtomicConsume for core::sync::atomic::AtomicPtr<T> { - type Val = *mut T; - impl_consume!(); -} - -#[cfg(crossbeam_loom)] -impl<T> AtomicConsume for loom::sync::atomic::AtomicPtr<T> { - type Val = *mut T; - impl_consume!(); -} diff --git a/vendor/crossbeam-utils/src/atomic/mod.rs b/vendor/crossbeam-utils/src/atomic/mod.rs deleted file mode 100644 index 4332cc3..0000000 --- a/vendor/crossbeam-utils/src/atomic/mod.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Atomic types. -//! -//! * [`AtomicCell`], a thread-safe mutable memory location. -//! * [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering. - -#[cfg(target_has_atomic = "ptr")] -#[cfg(not(crossbeam_loom))] -cfg_if::cfg_if! { - // Use "wide" sequence lock if the pointer width <= 32 for preventing its counter against wrap - // around. - // - // We are ignoring too wide architectures (pointer width >= 256), since such a system will not - // appear in a conceivable future. - // - // In narrow architectures (pointer width <= 16), the counter is still <= 32-bit and may be - // vulnerable to wrap around. But it's mostly okay, since in such a primitive hardware, the - // counter will not be increased that fast. - if #[cfg(any(target_pointer_width = "64", target_pointer_width = "128"))] { - mod seq_lock; - } else { - #[path = "seq_lock_wide.rs"] - mod seq_lock; - } -} - -#[cfg(target_has_atomic = "ptr")] -// We cannot provide AtomicCell under cfg(crossbeam_loom) because loom's atomic -// types have a different in-memory representation than the underlying type. -// TODO: The latest loom supports fences, so fallback using seqlock may be available. -#[cfg(not(crossbeam_loom))] -mod atomic_cell; -mod consume; - -#[cfg(target_has_atomic = "ptr")] -#[cfg(not(crossbeam_loom))] -pub use self::atomic_cell::AtomicCell; -pub use self::consume::AtomicConsume; diff --git a/vendor/crossbeam-utils/src/atomic/seq_lock.rs b/vendor/crossbeam-utils/src/atomic/seq_lock.rs deleted file mode 100644 index ff8defd..0000000 --- a/vendor/crossbeam-utils/src/atomic/seq_lock.rs +++ /dev/null @@ -1,112 +0,0 @@ -use core::mem; -use core::sync::atomic::{self, AtomicUsize, Ordering}; - -use crate::Backoff; - -/// A simple stamped lock. -pub(crate) struct SeqLock { - /// The current state of the lock. - /// - /// All bits except the least significant one hold the current stamp. When locked, the state - /// equals 1 and doesn't contain a valid stamp. - state: AtomicUsize, -} - -impl SeqLock { - pub(crate) const fn new() -> Self { - Self { - state: AtomicUsize::new(0), - } - } - - /// If not locked, returns the current stamp. - /// - /// This method should be called before optimistic reads. - #[inline] - pub(crate) fn optimistic_read(&self) -> Option<usize> { - let state = self.state.load(Ordering::Acquire); - if state == 1 { - None - } else { - Some(state) - } - } - - /// Returns `true` if the current stamp is equal to `stamp`. - /// - /// This method should be called after optimistic reads to check whether they are valid. The - /// argument `stamp` should correspond to the one returned by method `optimistic_read`. - #[inline] - pub(crate) fn validate_read(&self, stamp: usize) -> bool { - atomic::fence(Ordering::Acquire); - self.state.load(Ordering::Relaxed) == stamp - } - - /// Grabs the lock for writing. - #[inline] - pub(crate) fn write(&'static self) -> SeqLockWriteGuard { - let backoff = Backoff::new(); - loop { - let previous = self.state.swap(1, Ordering::Acquire); - - if previous != 1 { - atomic::fence(Ordering::Release); - - return SeqLockWriteGuard { - lock: self, - state: previous, - }; - } - - backoff.snooze(); - } - } -} - -/// An RAII guard that releases the lock and increments the stamp when dropped. -pub(crate) struct SeqLockWriteGuard { - /// The parent lock. - lock: &'static SeqLock, - - /// The stamp before locking. - state: usize, -} - -impl SeqLockWriteGuard { - /// Releases the lock without incrementing the stamp. - #[inline] - pub(crate) fn abort(self) { - self.lock.state.store(self.state, Ordering::Release); - - // We specifically don't want to call drop(), since that's - // what increments the stamp. - mem::forget(self); - } -} - -impl Drop for SeqLockWriteGuard { - #[inline] - fn drop(&mut self) { - // Release the lock and increment the stamp. - self.lock - .state - .store(self.state.wrapping_add(2), Ordering::Release); - } -} - -#[cfg(test)] -mod tests { - use super::SeqLock; - - #[test] - fn test_abort() { - static LK: SeqLock = SeqLock::new(); - let before = LK.optimistic_read().unwrap(); - { - let guard = LK.write(); - guard.abort(); - } - let after = LK.optimistic_read().unwrap(); - assert_eq!(before, after, "aborted write does not update the stamp"); - } -} diff --git a/vendor/crossbeam-utils/src/atomic/seq_lock_wide.rs b/vendor/crossbeam-utils/src/atomic/seq_lock_wide.rs deleted file mode 100644 index ef5d94a..0000000 --- a/vendor/crossbeam-utils/src/atomic/seq_lock_wide.rs +++ /dev/null @@ -1,155 +0,0 @@ -use core::mem; -use core::sync::atomic::{self, AtomicUsize, Ordering}; - -use crate::Backoff; - -/// A simple stamped lock. -/// -/// The state is represented as two `AtomicUsize`: `state_hi` for high bits and `state_lo` for low -/// bits. -pub(crate) struct SeqLock { - /// The high bits of the current state of the lock. - state_hi: AtomicUsize, - - /// The low bits of the current state of the lock. - /// - /// All bits except the least significant one hold the current stamp. When locked, the state_lo - /// equals 1 and doesn't contain a valid stamp. - state_lo: AtomicUsize, -} - -impl SeqLock { - pub(crate) const fn new() -> Self { - Self { - state_hi: AtomicUsize::new(0), - state_lo: AtomicUsize::new(0), - } - } - - /// If not locked, returns the current stamp. - /// - /// This method should be called before optimistic reads. - #[inline] - pub(crate) fn optimistic_read(&self) -> Option<(usize, usize)> { - // The acquire loads from `state_hi` and `state_lo` synchronize with the release stores in - // `SeqLockWriteGuard::drop`. - // - // As a consequence, we can make sure that (1) all writes within the era of `state_hi - 1` - // happens before now; and therefore, (2) if `state_lo` is even, all writes within the - // critical section of (`state_hi`, `state_lo`) happens before now. - let state_hi = self.state_hi.load(Ordering::Acquire); - let state_lo = self.state_lo.load(Ordering::Acquire); - if state_lo == 1 { - None - } else { - Some((state_hi, state_lo)) - } - } - - /// Returns `true` if the current stamp is equal to `stamp`. - /// - /// This method should be called after optimistic reads to check whether they are valid. The - /// argument `stamp` should correspond to the one returned by method `optimistic_read`. - #[inline] - pub(crate) fn validate_read(&self, stamp: (usize, usize)) -> bool { - // Thanks to the fence, if we're noticing any modification to the data at the critical - // section of `(a, b)`, then the critical section's write of 1 to state_lo should be - // visible. - atomic::fence(Ordering::Acquire); - - // So if `state_lo` coincides with `stamp.1`, then either (1) we're noticing no modification - // to the data after the critical section of `(stamp.0, stamp.1)`, or (2) `state_lo` wrapped - // around. - // - // If (2) is the case, the acquire ordering ensures we see the new value of `state_hi`. - let state_lo = self.state_lo.load(Ordering::Acquire); - - // If (2) is the case and `state_hi` coincides with `stamp.0`, then `state_hi` also wrapped - // around, which we give up to correctly validate the read. - let state_hi = self.state_hi.load(Ordering::Relaxed); - - // Except for the case that both `state_hi` and `state_lo` wrapped around, the following - // condition implies that we're noticing no modification to the data after the critical - // section of `(stamp.0, stamp.1)`. - (state_hi, state_lo) == stamp - } - - /// Grabs the lock for writing. - #[inline] - pub(crate) fn write(&'static self) -> SeqLockWriteGuard { - let backoff = Backoff::new(); - loop { - let previous = self.state_lo.swap(1, Ordering::Acquire); - - if previous != 1 { - // To synchronize with the acquire fence in `validate_read` via any modification to - // the data at the critical section of `(state_hi, previous)`. - atomic::fence(Ordering::Release); - - return SeqLockWriteGuard { - lock: self, - state_lo: previous, - }; - } - - backoff.snooze(); - } - } -} - -/// An RAII guard that releases the lock and increments the stamp when dropped. -pub(crate) struct SeqLockWriteGuard { - /// The parent lock. - lock: &'static SeqLock, - - /// The stamp before locking. - state_lo: usize, -} - -impl SeqLockWriteGuard { - /// Releases the lock without incrementing the stamp. - #[inline] - pub(crate) fn abort(self) { - self.lock.state_lo.store(self.state_lo, Ordering::Release); - mem::forget(self); - } -} - -impl Drop for SeqLockWriteGuard { - #[inline] - fn drop(&mut self) { - let state_lo = self.state_lo.wrapping_add(2); - - // Increase the high bits if the low bits wrap around. - // - // Release ordering for synchronizing with `optimistic_read`. - if state_lo == 0 { - let state_hi = self.lock.state_hi.load(Ordering::Relaxed); - self.lock - .state_hi - .store(state_hi.wrapping_add(1), Ordering::Release); - } - - // Release the lock and increment the stamp. - // - // Release ordering for synchronizing with `optimistic_read`. - self.lock.state_lo.store(state_lo, Ordering::Release); - } -} - -#[cfg(test)] -mod tests { - use super::SeqLock; - - #[test] - fn test_abort() { - static LK: SeqLock = SeqLock::new(); - let before = LK.optimistic_read().unwrap(); - { - let guard = LK.write(); - guard.abort(); - } - let after = LK.optimistic_read().unwrap(); - assert_eq!(before, after, "aborted write does not update the stamp"); - } -} diff --git a/vendor/crossbeam-utils/src/backoff.rs b/vendor/crossbeam-utils/src/backoff.rs deleted file mode 100644 index 7a505ed..0000000 --- a/vendor/crossbeam-utils/src/backoff.rs +++ /dev/null @@ -1,287 +0,0 @@ -use crate::primitive::hint; -use core::cell::Cell; -use core::fmt; - -const SPIN_LIMIT: u32 = 6; -const YIELD_LIMIT: u32 = 10; - -/// Performs exponential backoff in spin loops. -/// -/// Backing off in spin loops reduces contention and improves overall performance. -/// -/// This primitive can execute *YIELD* and *PAUSE* instructions, yield the current thread to the OS -/// scheduler, and tell when is a good time to block the thread using a different synchronization -/// mechanism. Each step of the back off procedure takes roughly twice as long as the previous -/// step. -/// -/// # Examples -/// -/// Backing off in a lock-free loop: -/// -/// ``` -/// use crossbeam_utils::Backoff; -/// use std::sync::atomic::AtomicUsize; -/// use std::sync::atomic::Ordering::SeqCst; -/// -/// fn fetch_mul(a: &AtomicUsize, b: usize) -> usize { -/// let backoff = Backoff::new(); -/// loop { -/// let val = a.load(SeqCst); -/// if a.compare_exchange(val, val.wrapping_mul(b), SeqCst, SeqCst).is_ok() { -/// return val; -/// } -/// backoff.spin(); -/// } -/// } -/// ``` -/// -/// Waiting for an [`AtomicBool`] to become `true`: -/// -/// ``` -/// use crossbeam_utils::Backoff; -/// use std::sync::atomic::AtomicBool; -/// use std::sync::atomic::Ordering::SeqCst; -/// -/// fn spin_wait(ready: &AtomicBool) { -/// let backoff = Backoff::new(); -/// while !ready.load(SeqCst) { -/// backoff.snooze(); -/// } -/// } -/// ``` -/// -/// Waiting for an [`AtomicBool`] to become `true` and parking the thread after a long wait. -/// Note that whoever sets the atomic variable to `true` must notify the parked thread by calling -/// [`unpark()`]: -/// -/// ``` -/// use crossbeam_utils::Backoff; -/// use std::sync::atomic::AtomicBool; -/// use std::sync::atomic::Ordering::SeqCst; -/// use std::thread; -/// -/// fn blocking_wait(ready: &AtomicBool) { -/// let backoff = Backoff::new(); -/// while !ready.load(SeqCst) { -/// if backoff.is_completed() { -/// thread::park(); -/// } else { -/// backoff.snooze(); -/// } -/// } -/// } -/// ``` -/// -/// [`is_completed`]: Backoff::is_completed -/// [`std::thread::park()`]: std::thread::park -/// [`Condvar`]: std::sync::Condvar -/// [`AtomicBool`]: std::sync::atomic::AtomicBool -/// [`unpark()`]: std::thread::Thread::unpark -pub struct Backoff { - step: Cell<u32>, -} - -impl Backoff { - /// Creates a new `Backoff`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::Backoff; - /// - /// let backoff = Backoff::new(); - /// ``` - #[inline] - pub fn new() -> Self { - Backoff { step: Cell::new(0) } - } - - /// Resets the `Backoff`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::Backoff; - /// - /// let backoff = Backoff::new(); - /// backoff.reset(); - /// ``` - #[inline] - pub fn reset(&self) { - self.step.set(0); - } - - /// Backs off in a lock-free loop. - /// - /// This method should be used when we need to retry an operation because another thread made - /// progress. - /// - /// The processor may yield using the *YIELD* or *PAUSE* instruction. - /// - /// # Examples - /// - /// Backing off in a lock-free loop: - /// - /// ``` - /// use crossbeam_utils::Backoff; - /// use std::sync::atomic::AtomicUsize; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// fn fetch_mul(a: &AtomicUsize, b: usize) -> usize { - /// let backoff = Backoff::new(); - /// loop { - /// let val = a.load(SeqCst); - /// if a.compare_exchange(val, val.wrapping_mul(b), SeqCst, SeqCst).is_ok() { - /// return val; - /// } - /// backoff.spin(); - /// } - /// } - /// - /// let a = AtomicUsize::new(7); - /// assert_eq!(fetch_mul(&a, 8), 7); - /// assert_eq!(a.load(SeqCst), 56); - /// ``` - #[inline] - pub fn spin(&self) { - for _ in 0..1 << self.step.get().min(SPIN_LIMIT) { - hint::spin_loop(); - } - - if self.step.get() <= SPIN_LIMIT { - self.step.set(self.step.get() + 1); - } - } - - /// Backs off in a blocking loop. - /// - /// This method should be used when we need to wait for another thread to make progress. - /// - /// The processor may yield using the *YIELD* or *PAUSE* instruction and the current thread - /// may yield by giving up a timeslice to the OS scheduler. - /// - /// In `#[no_std]` environments, this method is equivalent to [`spin`]. - /// - /// If possible, use [`is_completed`] to check when it is advised to stop using backoff and - /// block the current thread using a different synchronization mechanism instead. - /// - /// [`spin`]: Backoff::spin - /// [`is_completed`]: Backoff::is_completed - /// - /// # Examples - /// - /// Waiting for an [`AtomicBool`] to become `true`: - /// - /// ``` - /// use crossbeam_utils::Backoff; - /// use std::sync::Arc; - /// use std::sync::atomic::AtomicBool; - /// use std::sync::atomic::Ordering::SeqCst; - /// use std::thread; - /// use std::time::Duration; - /// - /// fn spin_wait(ready: &AtomicBool) { - /// let backoff = Backoff::new(); - /// while !ready.load(SeqCst) { - /// backoff.snooze(); - /// } - /// } - /// - /// let ready = Arc::new(AtomicBool::new(false)); - /// let ready2 = ready.clone(); - /// - /// thread::spawn(move || { - /// thread::sleep(Duration::from_millis(100)); - /// ready2.store(true, SeqCst); - /// }); - /// - /// assert_eq!(ready.load(SeqCst), false); - /// spin_wait(&ready); - /// assert_eq!(ready.load(SeqCst), true); - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 - /// ``` - /// - /// [`AtomicBool`]: std::sync::atomic::AtomicBool - #[inline] - pub fn snooze(&self) { - if self.step.get() <= SPIN_LIMIT { - for _ in 0..1 << self.step.get() { - hint::spin_loop(); - } - } else { - #[cfg(not(feature = "std"))] - for _ in 0..1 << self.step.get() { - hint::spin_loop(); - } - - #[cfg(feature = "std")] - ::std::thread::yield_now(); - } - - if self.step.get() <= YIELD_LIMIT { - self.step.set(self.step.get() + 1); - } - } - - /// Returns `true` if exponential backoff has completed and blocking the thread is advised. - /// - /// # Examples - /// - /// Waiting for an [`AtomicBool`] to become `true` and parking the thread after a long wait: - /// - /// ``` - /// use crossbeam_utils::Backoff; - /// use std::sync::Arc; - /// use std::sync::atomic::AtomicBool; - /// use std::sync::atomic::Ordering::SeqCst; - /// use std::thread; - /// use std::time::Duration; - /// - /// fn blocking_wait(ready: &AtomicBool) { - /// let backoff = Backoff::new(); - /// while !ready.load(SeqCst) { - /// if backoff.is_completed() { - /// thread::park(); - /// } else { - /// backoff.snooze(); - /// } - /// } - /// } - /// - /// let ready = Arc::new(AtomicBool::new(false)); - /// let ready2 = ready.clone(); - /// let waiter = thread::current(); - /// - /// thread::spawn(move || { - /// thread::sleep(Duration::from_millis(100)); - /// ready2.store(true, SeqCst); - /// waiter.unpark(); - /// }); - /// - /// assert_eq!(ready.load(SeqCst), false); - /// blocking_wait(&ready); - /// assert_eq!(ready.load(SeqCst), true); - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 - /// ``` - /// - /// [`AtomicBool`]: std::sync::atomic::AtomicBool - #[inline] - pub fn is_completed(&self) -> bool { - self.step.get() > YIELD_LIMIT - } -} - -impl fmt::Debug for Backoff { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Backoff") - .field("step", &self.step) - .field("is_completed", &self.is_completed()) - .finish() - } -} - -impl Default for Backoff { - fn default() -> Backoff { - Backoff::new() - } -} diff --git a/vendor/crossbeam-utils/src/cache_padded.rs b/vendor/crossbeam-utils/src/cache_padded.rs deleted file mode 100644 index f44f2d7..0000000 --- a/vendor/crossbeam-utils/src/cache_padded.rs +++ /dev/null @@ -1,209 +0,0 @@ -use core::fmt; -use core::ops::{Deref, DerefMut}; - -/// Pads and aligns a value to the length of a cache line. -/// -/// In concurrent programming, sometimes it is desirable to make sure commonly accessed pieces of -/// data are not placed into the same cache line. Updating an atomic value invalidates the whole -/// cache line it belongs to, which makes the next access to the same cache line slower for other -/// CPU cores. Use `CachePadded` to ensure updating one piece of data doesn't invalidate other -/// cached data. -/// -/// # Size and alignment -/// -/// Cache lines are assumed to be N bytes long, depending on the architecture: -/// -/// * On x86-64, aarch64, and powerpc64, N = 128. -/// * On arm, mips, mips64, sparc, and hexagon, N = 32. -/// * On m68k, N = 16. -/// * On s390x, N = 256. -/// * On all others, N = 64. -/// -/// Note that N is just a reasonable guess and is not guaranteed to match the actual cache line -/// length of the machine the program is running on. On modern Intel architectures, spatial -/// prefetcher is pulling pairs of 64-byte cache lines at a time, so we pessimistically assume that -/// cache lines are 128 bytes long. -/// -/// The size of `CachePadded<T>` is the smallest multiple of N bytes large enough to accommodate -/// a value of type `T`. -/// -/// The alignment of `CachePadded<T>` is the maximum of N bytes and the alignment of `T`. -/// -/// # Examples -/// -/// Alignment and padding: -/// -/// ``` -/// use crossbeam_utils::CachePadded; -/// -/// let array = [CachePadded::new(1i8), CachePadded::new(2i8)]; -/// let addr1 = &*array[0] as *const i8 as usize; -/// let addr2 = &*array[1] as *const i8 as usize; -/// -/// assert!(addr2 - addr1 >= 32); -/// assert_eq!(addr1 % 32, 0); -/// assert_eq!(addr2 % 32, 0); -/// ``` -/// -/// When building a concurrent queue with a head and a tail index, it is wise to place them in -/// different cache lines so that concurrent threads pushing and popping elements don't invalidate -/// each other's cache lines: -/// -/// ``` -/// use crossbeam_utils::CachePadded; -/// use std::sync::atomic::AtomicUsize; -/// -/// struct Queue<T> { -/// head: CachePadded<AtomicUsize>, -/// tail: CachePadded<AtomicUsize>, -/// buffer: *mut T, -/// } -/// ``` -#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)] -// Starting from Intel's Sandy Bridge, spatial prefetcher is now pulling pairs of 64-byte cache -// lines at a time, so we have to align to 128 bytes rather than 64. -// -// Sources: -// - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf -// - https://github.com/facebook/folly/blob/1b5288e6eea6df074758f877c849b6e73bbb9fbb/folly/lang/Align.h#L107 -// -// ARM's big.LITTLE architecture has asymmetric cores and "big" cores have 128-byte cache line size. -// -// Sources: -// - https://www.mono-project.com/news/2016/09/12/arm64-icache/ -// -// powerpc64 has 128-byte cache line size. -// -// Sources: -// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_ppc64x.go#L9 -// - https://github.com/torvalds/linux/blob/3516bd729358a2a9b090c1905bd2a3fa926e24c6/arch/powerpc/include/asm/cache.h#L26 -#[cfg_attr( - any( - target_arch = "x86_64", - target_arch = "aarch64", - target_arch = "powerpc64", - ), - repr(align(128)) -)] -// arm, mips, mips64, sparc, and hexagon have 32-byte cache line size. -// -// Sources: -// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_arm.go#L7 -// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips.go#L7 -// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mipsle.go#L7 -// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips64x.go#L9 -// - https://github.com/torvalds/linux/blob/3516bd729358a2a9b090c1905bd2a3fa926e24c6/arch/sparc/include/asm/cache.h#L17 -// - https://github.com/torvalds/linux/blob/3516bd729358a2a9b090c1905bd2a3fa926e24c6/arch/hexagon/include/asm/cache.h#L12 -#[cfg_attr( - any( - target_arch = "arm", - target_arch = "mips", - target_arch = "mips32r6", - target_arch = "mips64", - target_arch = "mips64r6", - target_arch = "sparc", - target_arch = "hexagon", - ), - repr(align(32)) -)] -// m68k has 16-byte cache line size. -// -// Sources: -// - https://github.com/torvalds/linux/blob/3516bd729358a2a9b090c1905bd2a3fa926e24c6/arch/m68k/include/asm/cache.h#L9 -#[cfg_attr(target_arch = "m68k", repr(align(16)))] -// s390x has 256-byte cache line size. -// -// Sources: -// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_s390x.go#L7 -// - https://github.com/torvalds/linux/blob/3516bd729358a2a9b090c1905bd2a3fa926e24c6/arch/s390/include/asm/cache.h#L13 -#[cfg_attr(target_arch = "s390x", repr(align(256)))] -// x86, wasm, riscv, and sparc64 have 64-byte cache line size. -// -// Sources: -// - https://github.com/golang/go/blob/dda2991c2ea0c5914714469c4defc2562a907230/src/internal/cpu/cpu_x86.go#L9 -// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_wasm.go#L7 -// - https://github.com/torvalds/linux/blob/3516bd729358a2a9b090c1905bd2a3fa926e24c6/arch/riscv/include/asm/cache.h#L10 -// - https://github.com/torvalds/linux/blob/3516bd729358a2a9b090c1905bd2a3fa926e24c6/arch/sparc/include/asm/cache.h#L19 -// -// All others are assumed to have 64-byte cache line size. -#[cfg_attr( - not(any( - target_arch = "x86_64", - target_arch = "aarch64", - target_arch = "powerpc64", - target_arch = "arm", - target_arch = "mips", - target_arch = "mips32r6", - target_arch = "mips64", - target_arch = "mips64r6", - target_arch = "sparc", - target_arch = "hexagon", - target_arch = "m68k", - target_arch = "s390x", - )), - repr(align(64)) -)] -pub struct CachePadded<T> { - value: T, -} - -unsafe impl<T: Send> Send for CachePadded<T> {} -unsafe impl<T: Sync> Sync for CachePadded<T> {} - -impl<T> CachePadded<T> { - /// Pads and aligns a value to the length of a cache line. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::CachePadded; - /// - /// let padded_value = CachePadded::new(1); - /// ``` - pub const fn new(t: T) -> CachePadded<T> { - CachePadded::<T> { value: t } - } - - /// Returns the inner value. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::CachePadded; - /// - /// let padded_value = CachePadded::new(7); - /// let value = padded_value.into_inner(); - /// assert_eq!(value, 7); - /// ``` - pub fn into_inner(self) -> T { - self.value - } -} - -impl<T> Deref for CachePadded<T> { - type Target = T; - - fn deref(&self) -> &T { - &self.value - } -} - -impl<T> DerefMut for CachePadded<T> { - fn deref_mut(&mut self) -> &mut T { - &mut self.value - } -} - -impl<T: fmt::Debug> fmt::Debug for CachePadded<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CachePadded") - .field("value", &self.value) - .finish() - } -} - -impl<T> From<T> for CachePadded<T> { - fn from(t: T) -> Self { - CachePadded::new(t) - } -} diff --git a/vendor/crossbeam-utils/src/lib.rs b/vendor/crossbeam-utils/src/lib.rs deleted file mode 100644 index 6ab748f..0000000 --- a/vendor/crossbeam-utils/src/lib.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Miscellaneous tools for concurrent programming. -//! -//! ## Atomics -//! -//! * [`AtomicCell`], a thread-safe mutable memory location. -//! * [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering. -//! -//! ## Thread synchronization -//! -//! * [`Parker`], a thread parking primitive. -//! * [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. -//! * [`WaitGroup`], for synchronizing the beginning or end of some computation. -//! -//! ## Utilities -//! -//! * [`Backoff`], for exponential backoff in spin loops. -//! * [`CachePadded`], for padding and aligning a value to the length of a cache line. -//! * [`scope`], for spawning threads that borrow local variables from the stack. -//! -//! [`AtomicCell`]: atomic::AtomicCell -//! [`AtomicConsume`]: atomic::AtomicConsume -//! [`Parker`]: sync::Parker -//! [`ShardedLock`]: sync::ShardedLock -//! [`WaitGroup`]: sync::WaitGroup -//! [`scope`]: thread::scope - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn( - missing_docs, - missing_debug_implementations, - rust_2018_idioms, - unreachable_pub -)] -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(crossbeam_loom)] -#[allow(unused_imports)] -mod primitive { - pub(crate) mod hint { - pub(crate) use loom::hint::spin_loop; - } - pub(crate) mod sync { - pub(crate) mod atomic { - pub(crate) use loom::sync::atomic::{ - AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, - AtomicU32, AtomicU64, AtomicU8, AtomicUsize, Ordering, - }; - - // FIXME: loom does not support compiler_fence at the moment. - // https://github.com/tokio-rs/loom/issues/117 - // we use fence as a stand-in for compiler_fence for the time being. - // this may miss some races since fence is stronger than compiler_fence, - // but it's the best we can do for the time being. - pub(crate) use loom::sync::atomic::fence as compiler_fence; - } - pub(crate) use loom::sync::{Arc, Condvar, Mutex}; - } -} -#[cfg(not(crossbeam_loom))] -#[allow(unused_imports)] -mod primitive { - pub(crate) mod hint { - pub(crate) use core::hint::spin_loop; - } - pub(crate) mod sync { - pub(crate) mod atomic { - pub(crate) use core::sync::atomic::{compiler_fence, Ordering}; - #[cfg(not(crossbeam_no_atomic))] - pub(crate) use core::sync::atomic::{ - AtomicBool, AtomicI16, AtomicI8, AtomicIsize, AtomicU16, AtomicU8, AtomicUsize, - }; - #[cfg(not(crossbeam_no_atomic))] - #[cfg(any(target_has_atomic = "32", not(target_pointer_width = "16")))] - pub(crate) use core::sync::atomic::{AtomicI32, AtomicU32}; - #[cfg(not(crossbeam_no_atomic))] - #[cfg(any( - target_has_atomic = "64", - not(any(target_pointer_width = "16", target_pointer_width = "32")), - ))] - pub(crate) use core::sync::atomic::{AtomicI64, AtomicU64}; - } - - #[cfg(feature = "std")] - pub(crate) use std::sync::{Arc, Condvar, Mutex}; - } -} - -pub mod atomic; - -mod cache_padded; -pub use crate::cache_padded::CachePadded; - -mod backoff; -pub use crate::backoff::Backoff; - -use cfg_if::cfg_if; - -cfg_if! { - if #[cfg(feature = "std")] { - pub mod sync; - - #[cfg(not(crossbeam_loom))] - pub mod thread; - } -} diff --git a/vendor/crossbeam-utils/src/sync/mod.rs b/vendor/crossbeam-utils/src/sync/mod.rs deleted file mode 100644 index f9eec71..0000000 --- a/vendor/crossbeam-utils/src/sync/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Thread synchronization primitives. -//! -//! * [`Parker`], a thread parking primitive. -//! * [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. -//! * [`WaitGroup`], for synchronizing the beginning or end of some computation. - -#[cfg(not(crossbeam_loom))] -mod once_lock; -mod parker; -#[cfg(not(crossbeam_loom))] -mod sharded_lock; -mod wait_group; - -pub use self::parker::{Parker, Unparker}; -#[cfg(not(crossbeam_loom))] -pub use self::sharded_lock::{ShardedLock, ShardedLockReadGuard, ShardedLockWriteGuard}; -pub use self::wait_group::WaitGroup; diff --git a/vendor/crossbeam-utils/src/sync/once_lock.rs b/vendor/crossbeam-utils/src/sync/once_lock.rs deleted file mode 100644 index e057aca..0000000 --- a/vendor/crossbeam-utils/src/sync/once_lock.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Based on unstable std::sync::OnceLock. -// -// Source: https://github.com/rust-lang/rust/blob/8e9c93df464b7ada3fc7a1c8ccddd9dcb24ee0a0/library/std/src/sync/once_lock.rs - -use core::cell::UnsafeCell; -use core::mem::MaybeUninit; -use std::sync::Once; - -pub(crate) struct OnceLock<T> { - once: Once, - value: UnsafeCell<MaybeUninit<T>>, - // Unlike std::sync::OnceLock, we don't need PhantomData here because - // we don't use #[may_dangle]. -} - -unsafe impl<T: Sync + Send> Sync for OnceLock<T> {} -unsafe impl<T: Send> Send for OnceLock<T> {} - -impl<T> OnceLock<T> { - /// Creates a new empty cell. - #[must_use] - pub(crate) const fn new() -> Self { - Self { - once: Once::new(), - value: UnsafeCell::new(MaybeUninit::uninit()), - } - } - - /// Gets the contents of the cell, initializing it with `f` if the cell - /// was empty. - /// - /// Many threads may call `get_or_init` concurrently with different - /// initializing functions, but it is guaranteed that only one function - /// will be executed. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and the cell - /// remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. The - /// exact outcome is unspecified. Current implementation deadlocks, but - /// this may be changed to a panic in the future. - pub(crate) fn get_or_init<F>(&self, f: F) -> &T - where - F: FnOnce() -> T, - { - // Fast path check - if self.once.is_completed() { - // SAFETY: The inner value has been initialized - return unsafe { self.get_unchecked() }; - } - self.initialize(f); - - // SAFETY: The inner value has been initialized - unsafe { self.get_unchecked() } - } - - #[cold] - fn initialize<F>(&self, f: F) - where - F: FnOnce() -> T, - { - let slot = self.value.get(); - - self.once.call_once(|| { - let value = f(); - unsafe { slot.write(MaybeUninit::new(value)) } - }); - } - - /// # Safety - /// - /// The value must be initialized - unsafe fn get_unchecked(&self) -> &T { - debug_assert!(self.once.is_completed()); - &*self.value.get().cast::<T>() - } -} - -impl<T> Drop for OnceLock<T> { - fn drop(&mut self) { - if self.once.is_completed() { - // SAFETY: The inner value has been initialized - unsafe { (*self.value.get()).assume_init_drop() }; - } - } -} diff --git a/vendor/crossbeam-utils/src/sync/parker.rs b/vendor/crossbeam-utils/src/sync/parker.rs deleted file mode 100644 index 971981d..0000000 --- a/vendor/crossbeam-utils/src/sync/parker.rs +++ /dev/null @@ -1,415 +0,0 @@ -use crate::primitive::sync::atomic::{AtomicUsize, Ordering::SeqCst}; -use crate::primitive::sync::{Arc, Condvar, Mutex}; -use std::fmt; -use std::marker::PhantomData; -use std::time::{Duration, Instant}; - -/// A thread parking primitive. -/// -/// Conceptually, each `Parker` has an associated token which is initially not present: -/// -/// * The [`park`] method blocks the current thread unless or until the token is available, at -/// which point it automatically consumes the token. -/// -/// * The [`park_timeout`] and [`park_deadline`] methods work the same as [`park`], but block for -/// a specified maximum time. -/// -/// * The [`unpark`] method atomically makes the token available if it wasn't already. Because the -/// token is initially absent, [`unpark`] followed by [`park`] will result in the second call -/// returning immediately. -/// -/// In other words, each `Parker` acts a bit like a spinlock that can be locked and unlocked using -/// [`park`] and [`unpark`]. -/// -/// # Examples -/// -/// ``` -/// use std::thread; -/// use std::time::Duration; -/// use crossbeam_utils::sync::Parker; -/// -/// let p = Parker::new(); -/// let u = p.unparker().clone(); -/// -/// // Make the token available. -/// u.unpark(); -/// // Wakes up immediately and consumes the token. -/// p.park(); -/// -/// thread::spawn(move || { -/// thread::sleep(Duration::from_millis(500)); -/// u.unpark(); -/// }); -/// -/// // Wakes up when `u.unpark()` provides the token. -/// p.park(); -/// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -/// ``` -/// -/// [`park`]: Parker::park -/// [`park_timeout`]: Parker::park_timeout -/// [`park_deadline`]: Parker::park_deadline -/// [`unpark`]: Unparker::unpark -pub struct Parker { - unparker: Unparker, - _marker: PhantomData<*const ()>, -} - -unsafe impl Send for Parker {} - -impl Default for Parker { - fn default() -> Self { - Self { - unparker: Unparker { - inner: Arc::new(Inner { - state: AtomicUsize::new(EMPTY), - lock: Mutex::new(()), - cvar: Condvar::new(), - }), - }, - _marker: PhantomData, - } - } -} - -impl Parker { - /// Creates a new `Parker`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::Parker; - /// - /// let p = Parker::new(); - /// ``` - /// - pub fn new() -> Parker { - Self::default() - } - - /// Blocks the current thread until the token is made available. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::Parker; - /// - /// let p = Parker::new(); - /// let u = p.unparker().clone(); - /// - /// // Make the token available. - /// u.unpark(); - /// - /// // Wakes up immediately and consumes the token. - /// p.park(); - /// ``` - pub fn park(&self) { - self.unparker.inner.park(None); - } - - /// Blocks the current thread until the token is made available, but only for a limited time. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// use crossbeam_utils::sync::Parker; - /// - /// let p = Parker::new(); - /// - /// // Waits for the token to become available, but will not wait longer than 500 ms. - /// p.park_timeout(Duration::from_millis(500)); - /// ``` - pub fn park_timeout(&self, timeout: Duration) { - match Instant::now().checked_add(timeout) { - Some(deadline) => self.park_deadline(deadline), - None => self.park(), - } - } - - /// Blocks the current thread until the token is made available, or until a certain deadline. - /// - /// # Examples - /// - /// ``` - /// use std::time::{Duration, Instant}; - /// use crossbeam_utils::sync::Parker; - /// - /// let p = Parker::new(); - /// let deadline = Instant::now() + Duration::from_millis(500); - /// - /// // Waits for the token to become available, but will not wait longer than 500 ms. - /// p.park_deadline(deadline); - /// ``` - pub fn park_deadline(&self, deadline: Instant) { - self.unparker.inner.park(Some(deadline)) - } - - /// Returns a reference to an associated [`Unparker`]. - /// - /// The returned [`Unparker`] doesn't have to be used by reference - it can also be cloned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::Parker; - /// - /// let p = Parker::new(); - /// let u = p.unparker().clone(); - /// - /// // Make the token available. - /// u.unpark(); - /// // Wakes up immediately and consumes the token. - /// p.park(); - /// ``` - /// - /// [`park`]: Parker::park - /// [`park_timeout`]: Parker::park_timeout - pub fn unparker(&self) -> &Unparker { - &self.unparker - } - - /// Converts a `Parker` into a raw pointer. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::Parker; - /// - /// let p = Parker::new(); - /// let raw = Parker::into_raw(p); - /// # let _ = unsafe { Parker::from_raw(raw) }; - /// ``` - pub fn into_raw(this: Parker) -> *const () { - Unparker::into_raw(this.unparker) - } - - /// Converts a raw pointer into a `Parker`. - /// - /// # Safety - /// - /// This method is safe to use only with pointers returned by [`Parker::into_raw`]. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::Parker; - /// - /// let p = Parker::new(); - /// let raw = Parker::into_raw(p); - /// let p = unsafe { Parker::from_raw(raw) }; - /// ``` - pub unsafe fn from_raw(ptr: *const ()) -> Parker { - Parker { - unparker: Unparker::from_raw(ptr), - _marker: PhantomData, - } - } -} - -impl fmt::Debug for Parker { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Parker { .. }") - } -} - -/// Unparks a thread parked by the associated [`Parker`]. -pub struct Unparker { - inner: Arc<Inner>, -} - -unsafe impl Send for Unparker {} -unsafe impl Sync for Unparker {} - -impl Unparker { - /// Atomically makes the token available if it is not already. - /// - /// This method will wake up the thread blocked on [`park`] or [`park_timeout`], if there is - /// any. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// use std::time::Duration; - /// use crossbeam_utils::sync::Parker; - /// - /// let p = Parker::new(); - /// let u = p.unparker().clone(); - /// - /// thread::spawn(move || { - /// thread::sleep(Duration::from_millis(500)); - /// u.unpark(); - /// }); - /// - /// // Wakes up when `u.unpark()` provides the token. - /// p.park(); - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 - /// ``` - /// - /// [`park`]: Parker::park - /// [`park_timeout`]: Parker::park_timeout - pub fn unpark(&self) { - self.inner.unpark() - } - - /// Converts an `Unparker` into a raw pointer. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::{Parker, Unparker}; - /// - /// let p = Parker::new(); - /// let u = p.unparker().clone(); - /// let raw = Unparker::into_raw(u); - /// # let _ = unsafe { Unparker::from_raw(raw) }; - /// ``` - pub fn into_raw(this: Unparker) -> *const () { - Arc::into_raw(this.inner).cast::<()>() - } - - /// Converts a raw pointer into an `Unparker`. - /// - /// # Safety - /// - /// This method is safe to use only with pointers returned by [`Unparker::into_raw`]. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::{Parker, Unparker}; - /// - /// let p = Parker::new(); - /// let u = p.unparker().clone(); - /// - /// let raw = Unparker::into_raw(u); - /// let u = unsafe { Unparker::from_raw(raw) }; - /// ``` - pub unsafe fn from_raw(ptr: *const ()) -> Unparker { - Unparker { - inner: Arc::from_raw(ptr.cast::<Inner>()), - } - } -} - -impl fmt::Debug for Unparker { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Unparker { .. }") - } -} - -impl Clone for Unparker { - fn clone(&self) -> Unparker { - Unparker { - inner: self.inner.clone(), - } - } -} - -const EMPTY: usize = 0; -const PARKED: usize = 1; -const NOTIFIED: usize = 2; - -struct Inner { - state: AtomicUsize, - lock: Mutex<()>, - cvar: Condvar, -} - -impl Inner { - fn park(&self, deadline: Option<Instant>) { - // If we were previously notified then we consume this notification and return quickly. - if self - .state - .compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) - .is_ok() - { - return; - } - - // If the timeout is zero, then there is no need to actually block. - if let Some(deadline) = deadline { - if deadline <= Instant::now() { - return; - } - } - - // Otherwise we need to coordinate going to sleep. - let mut m = self.lock.lock().unwrap(); - - match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { - Ok(_) => {} - // Consume this notification to avoid spurious wakeups in the next park. - Err(NOTIFIED) => { - // We must read `state` here, even though we know it will be `NOTIFIED`. This is - // because `unpark` may have been called again since we read `NOTIFIED` in the - // `compare_exchange` above. We must perform an acquire operation that synchronizes - // with that `unpark` to observe any writes it made before the call to `unpark`. To - // do that we must read from the write it made to `state`. - let old = self.state.swap(EMPTY, SeqCst); - assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); - return; - } - Err(n) => panic!("inconsistent park_timeout state: {}", n), - } - - loop { - // Block the current thread on the conditional variable. - m = match deadline { - None => self.cvar.wait(m).unwrap(), - Some(deadline) => { - let now = Instant::now(); - if now < deadline { - // We could check for a timeout here, in the return value of wait_timeout, - // but in the case that a timeout and an unpark arrive simultaneously, we - // prefer to report the former. - self.cvar.wait_timeout(m, deadline - now).unwrap().0 - } else { - // We've timed out; swap out the state back to empty on our way out - match self.state.swap(EMPTY, SeqCst) { - NOTIFIED | PARKED => return, - n => panic!("inconsistent park_timeout state: {}", n), - }; - } - } - }; - - if self - .state - .compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) - .is_ok() - { - // got a notification - return; - } - - // Spurious wakeup, go back to sleep. Alternatively, if we timed out, it will be caught - // in the branch above, when we discover the deadline is in the past - } - } - - pub(crate) fn unpark(&self) { - // To ensure the unparked thread will observe any writes we made before this call, we must - // perform a release operation that `park` can synchronize with. To do that we must write - // `NOTIFIED` even if `state` is already `NOTIFIED`. That is why this must be a swap rather - // than a compare-and-swap that returns if it reads `NOTIFIED` on failure. - match self.state.swap(NOTIFIED, SeqCst) { - EMPTY => return, // no one was waiting - NOTIFIED => return, // already unparked - PARKED => {} // gotta go wake someone up - _ => panic!("inconsistent state in unpark"), - } - - // There is a period between when the parked thread sets `state` to `PARKED` (or last - // checked `state` in the case of a spurious wakeup) and when it actually waits on `cvar`. - // If we were to notify during this period it would be ignored and then when the parked - // thread went to sleep it would never wake up. Fortunately, it has `lock` locked at this - // stage so we can acquire `lock` to wait until it is ready to receive the notification. - // - // Releasing `lock` before the call to `notify_one` means that when the parked thread wakes - // it doesn't get woken only to have to wait for us to release `lock`. - drop(self.lock.lock().unwrap()); - self.cvar.notify_one(); - } -} diff --git a/vendor/crossbeam-utils/src/sync/sharded_lock.rs b/vendor/crossbeam-utils/src/sync/sharded_lock.rs deleted file mode 100644 index 5aee56f..0000000 --- a/vendor/crossbeam-utils/src/sync/sharded_lock.rs +++ /dev/null @@ -1,636 +0,0 @@ -use std::cell::UnsafeCell; -use std::collections::HashMap; -use std::fmt; -use std::marker::PhantomData; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::panic::{RefUnwindSafe, UnwindSafe}; -use std::sync::{LockResult, PoisonError, TryLockError, TryLockResult}; -use std::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use std::thread::{self, ThreadId}; - -use crate::sync::once_lock::OnceLock; -use crate::CachePadded; - -/// The number of shards per sharded lock. Must be a power of two. -const NUM_SHARDS: usize = 8; - -/// A shard containing a single reader-writer lock. -struct Shard { - /// The inner reader-writer lock. - lock: RwLock<()>, - - /// The write-guard keeping this shard locked. - /// - /// Write operations will lock each shard and store the guard here. These guards get dropped at - /// the same time the big guard is dropped. - write_guard: UnsafeCell<Option<RwLockWriteGuard<'static, ()>>>, -} - -/// A sharded reader-writer lock. -/// -/// This lock is equivalent to [`RwLock`], except read operations are faster and write operations -/// are slower. -/// -/// A `ShardedLock` is internally made of a list of *shards*, each being a [`RwLock`] occupying a -/// single cache line. Read operations will pick one of the shards depending on the current thread -/// and lock it. Write operations need to lock all shards in succession. -/// -/// By splitting the lock into shards, concurrent read operations will in most cases choose -/// different shards and thus update different cache lines, which is good for scalability. However, -/// write operations need to do more work and are therefore slower than usual. -/// -/// The priority policy of the lock is dependent on the underlying operating system's -/// implementation, and this type does not guarantee that any particular policy will be used. -/// -/// # Poisoning -/// -/// A `ShardedLock`, like [`RwLock`], will become poisoned on a panic. Note that it may only be -/// poisoned if a panic occurs while a write operation is in progress. If a panic occurs in any -/// read operation, the lock will not be poisoned. -/// -/// # Examples -/// -/// ``` -/// use crossbeam_utils::sync::ShardedLock; -/// -/// let lock = ShardedLock::new(5); -/// -/// // Any number of read locks can be held at once. -/// { -/// let r1 = lock.read().unwrap(); -/// let r2 = lock.read().unwrap(); -/// assert_eq!(*r1, 5); -/// assert_eq!(*r2, 5); -/// } // Read locks are dropped at this point. -/// -/// // However, only one write lock may be held. -/// { -/// let mut w = lock.write().unwrap(); -/// *w += 1; -/// assert_eq!(*w, 6); -/// } // Write lock is dropped here. -/// ``` -/// -/// [`RwLock`]: std::sync::RwLock -pub struct ShardedLock<T: ?Sized> { - /// A list of locks protecting the internal data. - shards: Box<[CachePadded<Shard>]>, - - /// The internal data. - value: UnsafeCell<T>, -} - -unsafe impl<T: ?Sized + Send> Send for ShardedLock<T> {} -unsafe impl<T: ?Sized + Send + Sync> Sync for ShardedLock<T> {} - -impl<T: ?Sized> UnwindSafe for ShardedLock<T> {} -impl<T: ?Sized> RefUnwindSafe for ShardedLock<T> {} - -impl<T> ShardedLock<T> { - /// Creates a new sharded reader-writer lock. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::ShardedLock; - /// - /// let lock = ShardedLock::new(5); - /// ``` - pub fn new(value: T) -> ShardedLock<T> { - ShardedLock { - shards: (0..NUM_SHARDS) - .map(|_| { - CachePadded::new(Shard { - lock: RwLock::new(()), - write_guard: UnsafeCell::new(None), - }) - }) - .collect::<Box<[_]>>(), - value: UnsafeCell::new(value), - } - } - - /// Consumes this lock, returning the underlying data. - /// - /// # Errors - /// - /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write - /// operation panics. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::ShardedLock; - /// - /// let lock = ShardedLock::new(String::new()); - /// { - /// let mut s = lock.write().unwrap(); - /// *s = "modified".to_owned(); - /// } - /// assert_eq!(lock.into_inner().unwrap(), "modified"); - /// ``` - pub fn into_inner(self) -> LockResult<T> { - let is_poisoned = self.is_poisoned(); - let inner = self.value.into_inner(); - - if is_poisoned { - Err(PoisonError::new(inner)) - } else { - Ok(inner) - } - } -} - -impl<T: ?Sized> ShardedLock<T> { - /// Returns `true` if the lock is poisoned. - /// - /// If another thread can still access the lock, it may become poisoned at any time. A `false` - /// result should not be trusted without additional synchronization. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::ShardedLock; - /// use std::sync::Arc; - /// use std::thread; - /// - /// let lock = Arc::new(ShardedLock::new(0)); - /// let c_lock = lock.clone(); - /// - /// let _ = thread::spawn(move || { - /// let _lock = c_lock.write().unwrap(); - /// panic!(); // the lock gets poisoned - /// }).join(); - /// assert_eq!(lock.is_poisoned(), true); - /// ``` - pub fn is_poisoned(&self) -> bool { - self.shards[0].lock.is_poisoned() - } - - /// Returns a mutable reference to the underlying data. - /// - /// Since this call borrows the lock mutably, no actual locking needs to take place. - /// - /// # Errors - /// - /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write - /// operation panics. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::ShardedLock; - /// - /// let mut lock = ShardedLock::new(0); - /// *lock.get_mut().unwrap() = 10; - /// assert_eq!(*lock.read().unwrap(), 10); - /// ``` - pub fn get_mut(&mut self) -> LockResult<&mut T> { - let is_poisoned = self.is_poisoned(); - let inner = unsafe { &mut *self.value.get() }; - - if is_poisoned { - Err(PoisonError::new(inner)) - } else { - Ok(inner) - } - } - - /// Attempts to acquire this lock with shared read access. - /// - /// If the access could not be granted at this time, an error is returned. Otherwise, a guard - /// is returned which will release the shared access when it is dropped. This method does not - /// provide any guarantees with respect to the ordering of whether contentious readers or - /// writers will acquire the lock first. - /// - /// # Errors - /// - /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write - /// operation panics. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::ShardedLock; - /// - /// let lock = ShardedLock::new(1); - /// - /// match lock.try_read() { - /// Ok(n) => assert_eq!(*n, 1), - /// Err(_) => unreachable!(), - /// }; - /// ``` - pub fn try_read(&self) -> TryLockResult<ShardedLockReadGuard<'_, T>> { - // Take the current thread index and map it to a shard index. Thread indices will tend to - // distribute shards among threads equally, thus reducing contention due to read-locking. - let current_index = current_index().unwrap_or(0); - let shard_index = current_index & (self.shards.len() - 1); - - match self.shards[shard_index].lock.try_read() { - Ok(guard) => Ok(ShardedLockReadGuard { - lock: self, - _guard: guard, - _marker: PhantomData, - }), - Err(TryLockError::Poisoned(err)) => { - let guard = ShardedLockReadGuard { - lock: self, - _guard: err.into_inner(), - _marker: PhantomData, - }; - Err(TryLockError::Poisoned(PoisonError::new(guard))) - } - Err(TryLockError::WouldBlock) => Err(TryLockError::WouldBlock), - } - } - - /// Locks with shared read access, blocking the current thread until it can be acquired. - /// - /// The calling thread will be blocked until there are no more writers which hold the lock. - /// There may be other readers currently inside the lock when this method returns. This method - /// does not provide any guarantees with respect to the ordering of whether contentious readers - /// or writers will acquire the lock first. - /// - /// Returns a guard which will release the shared access when dropped. - /// - /// # Errors - /// - /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write - /// operation panics. - /// - /// # Panics - /// - /// This method might panic when called if the lock is already held by the current thread. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::ShardedLock; - /// use std::sync::Arc; - /// use std::thread; - /// - /// let lock = Arc::new(ShardedLock::new(1)); - /// let c_lock = lock.clone(); - /// - /// let n = lock.read().unwrap(); - /// assert_eq!(*n, 1); - /// - /// thread::spawn(move || { - /// let r = c_lock.read(); - /// assert!(r.is_ok()); - /// }).join().unwrap(); - /// ``` - pub fn read(&self) -> LockResult<ShardedLockReadGuard<'_, T>> { - // Take the current thread index and map it to a shard index. Thread indices will tend to - // distribute shards among threads equally, thus reducing contention due to read-locking. - let current_index = current_index().unwrap_or(0); - let shard_index = current_index & (self.shards.len() - 1); - - match self.shards[shard_index].lock.read() { - Ok(guard) => Ok(ShardedLockReadGuard { - lock: self, - _guard: guard, - _marker: PhantomData, - }), - Err(err) => Err(PoisonError::new(ShardedLockReadGuard { - lock: self, - _guard: err.into_inner(), - _marker: PhantomData, - })), - } - } - - /// Attempts to acquire this lock with exclusive write access. - /// - /// If the access could not be granted at this time, an error is returned. Otherwise, a guard - /// is returned which will release the exclusive access when it is dropped. This method does - /// not provide any guarantees with respect to the ordering of whether contentious readers or - /// writers will acquire the lock first. - /// - /// # Errors - /// - /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write - /// operation panics. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::ShardedLock; - /// - /// let lock = ShardedLock::new(1); - /// - /// let n = lock.read().unwrap(); - /// assert_eq!(*n, 1); - /// - /// assert!(lock.try_write().is_err()); - /// ``` - pub fn try_write(&self) -> TryLockResult<ShardedLockWriteGuard<'_, T>> { - let mut poisoned = false; - let mut blocked = None; - - // Write-lock each shard in succession. - for (i, shard) in self.shards.iter().enumerate() { - let guard = match shard.lock.try_write() { - Ok(guard) => guard, - Err(TryLockError::Poisoned(err)) => { - poisoned = true; - err.into_inner() - } - Err(TryLockError::WouldBlock) => { - blocked = Some(i); - break; - } - }; - - // Store the guard into the shard. - unsafe { - let guard: RwLockWriteGuard<'static, ()> = mem::transmute(guard); - let dest: *mut _ = shard.write_guard.get(); - *dest = Some(guard); - } - } - - if let Some(i) = blocked { - // Unlock the shards in reverse order of locking. - for shard in self.shards[0..i].iter().rev() { - unsafe { - let dest: *mut _ = shard.write_guard.get(); - let guard = (*dest).take(); - drop(guard); - } - } - Err(TryLockError::WouldBlock) - } else if poisoned { - let guard = ShardedLockWriteGuard { - lock: self, - _marker: PhantomData, - }; - Err(TryLockError::Poisoned(PoisonError::new(guard))) - } else { - Ok(ShardedLockWriteGuard { - lock: self, - _marker: PhantomData, - }) - } - } - - /// Locks with exclusive write access, blocking the current thread until it can be acquired. - /// - /// The calling thread will be blocked until there are no more writers which hold the lock. - /// There may be other readers currently inside the lock when this method returns. This method - /// does not provide any guarantees with respect to the ordering of whether contentious readers - /// or writers will acquire the lock first. - /// - /// Returns a guard which will release the exclusive access when dropped. - /// - /// # Errors - /// - /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write - /// operation panics. - /// - /// # Panics - /// - /// This method might panic when called if the lock is already held by the current thread. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::ShardedLock; - /// - /// let lock = ShardedLock::new(1); - /// - /// let mut n = lock.write().unwrap(); - /// *n = 2; - /// - /// assert!(lock.try_read().is_err()); - /// ``` - pub fn write(&self) -> LockResult<ShardedLockWriteGuard<'_, T>> { - let mut poisoned = false; - - // Write-lock each shard in succession. - for shard in self.shards.iter() { - let guard = match shard.lock.write() { - Ok(guard) => guard, - Err(err) => { - poisoned = true; - err.into_inner() - } - }; - - // Store the guard into the shard. - unsafe { - let guard: RwLockWriteGuard<'_, ()> = guard; - let guard: RwLockWriteGuard<'static, ()> = mem::transmute(guard); - let dest: *mut _ = shard.write_guard.get(); - *dest = Some(guard); - } - } - - if poisoned { - Err(PoisonError::new(ShardedLockWriteGuard { - lock: self, - _marker: PhantomData, - })) - } else { - Ok(ShardedLockWriteGuard { - lock: self, - _marker: PhantomData, - }) - } - } -} - -impl<T: ?Sized + fmt::Debug> fmt::Debug for ShardedLock<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.try_read() { - Ok(guard) => f - .debug_struct("ShardedLock") - .field("data", &&*guard) - .finish(), - Err(TryLockError::Poisoned(err)) => f - .debug_struct("ShardedLock") - .field("data", &&**err.get_ref()) - .finish(), - Err(TryLockError::WouldBlock) => { - struct LockedPlaceholder; - impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("<locked>") - } - } - f.debug_struct("ShardedLock") - .field("data", &LockedPlaceholder) - .finish() - } - } - } -} - -impl<T: Default> Default for ShardedLock<T> { - fn default() -> ShardedLock<T> { - ShardedLock::new(Default::default()) - } -} - -impl<T> From<T> for ShardedLock<T> { - fn from(t: T) -> Self { - ShardedLock::new(t) - } -} - -/// A guard used to release the shared read access of a [`ShardedLock`] when dropped. -#[clippy::has_significant_drop] -pub struct ShardedLockReadGuard<'a, T: ?Sized> { - lock: &'a ShardedLock<T>, - _guard: RwLockReadGuard<'a, ()>, - _marker: PhantomData<RwLockReadGuard<'a, T>>, -} - -unsafe impl<T: ?Sized + Sync> Sync for ShardedLockReadGuard<'_, T> {} - -impl<T: ?Sized> Deref for ShardedLockReadGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.lock.value.get() } - } -} - -impl<T: fmt::Debug> fmt::Debug for ShardedLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ShardedLockReadGuard") - .field("lock", &self.lock) - .finish() - } -} - -impl<T: ?Sized + fmt::Display> fmt::Display for ShardedLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -/// A guard used to release the exclusive write access of a [`ShardedLock`] when dropped. -#[clippy::has_significant_drop] -pub struct ShardedLockWriteGuard<'a, T: ?Sized> { - lock: &'a ShardedLock<T>, - _marker: PhantomData<RwLockWriteGuard<'a, T>>, -} - -unsafe impl<T: ?Sized + Sync> Sync for ShardedLockWriteGuard<'_, T> {} - -impl<T: ?Sized> Drop for ShardedLockWriteGuard<'_, T> { - fn drop(&mut self) { - // Unlock the shards in reverse order of locking. - for shard in self.lock.shards.iter().rev() { - unsafe { - let dest: *mut _ = shard.write_guard.get(); - let guard = (*dest).take(); - drop(guard); - } - } - } -} - -impl<T: fmt::Debug> fmt::Debug for ShardedLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ShardedLockWriteGuard") - .field("lock", &self.lock) - .finish() - } -} - -impl<T: ?Sized + fmt::Display> fmt::Display for ShardedLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -impl<T: ?Sized> Deref for ShardedLockWriteGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.lock.value.get() } - } -} - -impl<T: ?Sized> DerefMut for ShardedLockWriteGuard<'_, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.lock.value.get() } - } -} - -/// Returns a `usize` that identifies the current thread. -/// -/// Each thread is associated with an 'index'. While there are no particular guarantees, indices -/// usually tend to be consecutive numbers between 0 and the number of running threads. -/// -/// Since this function accesses TLS, `None` might be returned if the current thread's TLS is -/// tearing down. -#[inline] -fn current_index() -> Option<usize> { - REGISTRATION.try_with(|reg| reg.index).ok() -} - -/// The global registry keeping track of registered threads and indices. -struct ThreadIndices { - /// Mapping from `ThreadId` to thread index. - mapping: HashMap<ThreadId, usize>, - - /// A list of free indices. - free_list: Vec<usize>, - - /// The next index to allocate if the free list is empty. - next_index: usize, -} - -fn thread_indices() -> &'static Mutex<ThreadIndices> { - static THREAD_INDICES: OnceLock<Mutex<ThreadIndices>> = OnceLock::new(); - fn init() -> Mutex<ThreadIndices> { - Mutex::new(ThreadIndices { - mapping: HashMap::new(), - free_list: Vec::new(), - next_index: 0, - }) - } - THREAD_INDICES.get_or_init(init) -} - -/// A registration of a thread with an index. -/// -/// When dropped, unregisters the thread and frees the reserved index. -struct Registration { - index: usize, - thread_id: ThreadId, -} - -impl Drop for Registration { - fn drop(&mut self) { - let mut indices = thread_indices().lock().unwrap(); - indices.mapping.remove(&self.thread_id); - indices.free_list.push(self.index); - } -} - -thread_local! { - static REGISTRATION: Registration = { - let thread_id = thread::current().id(); - let mut indices = thread_indices().lock().unwrap(); - - let index = match indices.free_list.pop() { - Some(i) => i, - None => { - let i = indices.next_index; - indices.next_index += 1; - i - } - }; - indices.mapping.insert(thread_id, index); - - Registration { - index, - thread_id, - } - }; -} diff --git a/vendor/crossbeam-utils/src/sync/wait_group.rs b/vendor/crossbeam-utils/src/sync/wait_group.rs deleted file mode 100644 index 19d6074..0000000 --- a/vendor/crossbeam-utils/src/sync/wait_group.rs +++ /dev/null @@ -1,145 +0,0 @@ -use crate::primitive::sync::{Arc, Condvar, Mutex}; -use std::fmt; - -/// Enables threads to synchronize the beginning or end of some computation. -/// -/// # Wait groups vs barriers -/// -/// `WaitGroup` is very similar to [`Barrier`], but there are a few differences: -/// -/// * [`Barrier`] needs to know the number of threads at construction, while `WaitGroup` is cloned to -/// register more threads. -/// -/// * A [`Barrier`] can be reused even after all threads have synchronized, while a `WaitGroup` -/// synchronizes threads only once. -/// -/// * All threads wait for others to reach the [`Barrier`]. With `WaitGroup`, each thread can choose -/// to either wait for other threads or to continue without blocking. -/// -/// # Examples -/// -/// ``` -/// use crossbeam_utils::sync::WaitGroup; -/// use std::thread; -/// -/// // Create a new wait group. -/// let wg = WaitGroup::new(); -/// -/// for _ in 0..4 { -/// // Create another reference to the wait group. -/// let wg = wg.clone(); -/// -/// thread::spawn(move || { -/// // Do some work. -/// -/// // Drop the reference to the wait group. -/// drop(wg); -/// }); -/// } -/// -/// // Block until all threads have finished their work. -/// wg.wait(); -/// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 -/// ``` -/// -/// [`Barrier`]: std::sync::Barrier -pub struct WaitGroup { - inner: Arc<Inner>, -} - -/// Inner state of a `WaitGroup`. -struct Inner { - cvar: Condvar, - count: Mutex<usize>, -} - -impl Default for WaitGroup { - fn default() -> Self { - Self { - inner: Arc::new(Inner { - cvar: Condvar::new(), - count: Mutex::new(1), - }), - } - } -} - -impl WaitGroup { - /// Creates a new wait group and returns the single reference to it. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::WaitGroup; - /// - /// let wg = WaitGroup::new(); - /// ``` - pub fn new() -> Self { - Self::default() - } - - /// Drops this reference and waits until all other references are dropped. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::sync::WaitGroup; - /// use std::thread; - /// - /// let wg = WaitGroup::new(); - /// - /// thread::spawn({ - /// let wg = wg.clone(); - /// move || { - /// // Block until both threads have reached `wait()`. - /// wg.wait(); - /// } - /// }); - /// - /// // Block until both threads have reached `wait()`. - /// wg.wait(); - /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 - /// ``` - pub fn wait(self) { - if *self.inner.count.lock().unwrap() == 1 { - return; - } - - let inner = self.inner.clone(); - drop(self); - - let mut count = inner.count.lock().unwrap(); - while *count > 0 { - count = inner.cvar.wait(count).unwrap(); - } - } -} - -impl Drop for WaitGroup { - fn drop(&mut self) { - let mut count = self.inner.count.lock().unwrap(); - *count -= 1; - - if *count == 0 { - self.inner.cvar.notify_all(); - } - } -} - -impl Clone for WaitGroup { - fn clone(&self) -> WaitGroup { - let mut count = self.inner.count.lock().unwrap(); - *count += 1; - - WaitGroup { - inner: self.inner.clone(), - } - } -} - -impl fmt::Debug for WaitGroup { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let count: &usize = &*self.inner.count.lock().unwrap(); - f.debug_struct("WaitGroup").field("count", count).finish() - } -} diff --git a/vendor/crossbeam-utils/src/thread.rs b/vendor/crossbeam-utils/src/thread.rs deleted file mode 100644 index 2d4805e..0000000 --- a/vendor/crossbeam-utils/src/thread.rs +++ /dev/null @@ -1,604 +0,0 @@ -//! Threads that can borrow variables from the stack. -//! -//! Create a scope when spawned threads need to access variables on the stack: -//! -//! ``` -//! use crossbeam_utils::thread; -//! -//! let people = vec![ -//! "Alice".to_string(), -//! "Bob".to_string(), -//! "Carol".to_string(), -//! ]; -//! -//! thread::scope(|s| { -//! for person in &people { -//! s.spawn(move |_| { -//! println!("Hello, {}!", person); -//! }); -//! } -//! }).unwrap(); -//! ``` -//! -//! # Why scoped threads? -//! -//! Suppose we wanted to re-write the previous example using plain threads: -//! -//! ```compile_fail,E0597 -//! use std::thread; -//! -//! let people = vec![ -//! "Alice".to_string(), -//! "Bob".to_string(), -//! "Carol".to_string(), -//! ]; -//! -//! let mut threads = Vec::new(); -//! -//! for person in &people { -//! threads.push(thread::spawn(move || { -//! println!("Hello, {}!", person); -//! })); -//! } -//! -//! for thread in threads { -//! thread.join().unwrap(); -//! } -//! ``` -//! -//! This doesn't work because the borrow checker complains about `people` not living long enough: -//! -//! ```text -//! error[E0597]: `people` does not live long enough -//! --> src/main.rs:12:20 -//! | -//! 12 | for person in &people { -//! | ^^^^^^ borrowed value does not live long enough -//! ... -//! 21 | } -//! | - borrowed value only lives until here -//! | -//! = note: borrowed value must be valid for the static lifetime... -//! ``` -//! -//! The problem here is that spawned threads are not allowed to borrow variables on stack because -//! the compiler cannot prove they will be joined before `people` is destroyed. -//! -//! Scoped threads are a mechanism to guarantee to the compiler that spawned threads will be joined -//! before the scope ends. -//! -//! # How scoped threads work -//! -//! If a variable is borrowed by a thread, the thread must complete before the variable is -//! destroyed. Threads spawned using [`std::thread::spawn`] can only borrow variables with the -//! `'static` lifetime because the borrow checker cannot be sure when the thread will complete. -//! -//! A scope creates a clear boundary between variables outside the scope and threads inside the -//! scope. Whenever a scope spawns a thread, it promises to join the thread before the scope ends. -//! This way we guarantee to the borrow checker that scoped threads only live within the scope and -//! can safely access variables outside it. -//! -//! # Nesting scoped threads -//! -//! Sometimes scoped threads need to spawn more threads within the same scope. This is a little -//! tricky because argument `s` lives *inside* the invocation of `thread::scope()` and as such -//! cannot be borrowed by scoped threads: -//! -//! ```compile_fail,E0521 -//! use crossbeam_utils::thread; -//! -//! thread::scope(|s| { -//! s.spawn(|_| { -//! // Not going to compile because we're trying to borrow `s`, -//! // which lives *inside* the scope! :( -//! s.spawn(|_| println!("nested thread")); -//! }); -//! }); -//! ``` -//! -//! Fortunately, there is a solution. Every scoped thread is passed a reference to its scope as an -//! argument, which can be used for spawning nested threads: -//! -//! ``` -//! use crossbeam_utils::thread; -//! -//! thread::scope(|s| { -//! // Note the `|s|` here. -//! s.spawn(|s| { -//! // Yay, this works because we're using a fresh argument `s`! :) -//! s.spawn(|_| println!("nested thread")); -//! }); -//! }).unwrap(); -//! ``` - -use std::fmt; -use std::io; -use std::marker::PhantomData; -use std::mem; -use std::panic; -use std::sync::{Arc, Mutex}; -use std::thread; - -use crate::sync::WaitGroup; -use cfg_if::cfg_if; - -type SharedVec<T> = Arc<Mutex<Vec<T>>>; -type SharedOption<T> = Arc<Mutex<Option<T>>>; - -/// Creates a new scope for spawning threads. -/// -/// All child threads that haven't been manually joined will be automatically joined just before -/// this function invocation ends. If all joined threads have successfully completed, `Ok` is -/// returned with the return value of `f`. If any of the joined threads has panicked, an `Err` is -/// returned containing errors from panicked threads. Note that if panics are implemented by -/// aborting the process, no error is returned; see the notes of [std::panic::catch_unwind]. -/// -/// **Note:** Since Rust 1.63, this function is soft-deprecated in favor of the more efficient [`std::thread::scope`]. -/// -/// # Examples -/// -/// ``` -/// use crossbeam_utils::thread; -/// -/// let var = vec![1, 2, 3]; -/// -/// thread::scope(|s| { -/// s.spawn(|_| { -/// println!("A child thread borrowing `var`: {:?}", var); -/// }); -/// }).unwrap(); -/// ``` -pub fn scope<'env, F, R>(f: F) -> thread::Result<R> -where - F: FnOnce(&Scope<'env>) -> R, -{ - struct AbortOnPanic; - impl Drop for AbortOnPanic { - fn drop(&mut self) { - if thread::panicking() { - std::process::abort(); - } - } - } - - let wg = WaitGroup::new(); - let scope = Scope::<'env> { - handles: SharedVec::default(), - wait_group: wg.clone(), - _marker: PhantomData, - }; - - // Execute the scoped function, but catch any panics. - let result = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&scope))); - - // If an unwinding panic occurs before all threads are joined - // promote it to an aborting panic to prevent any threads from escaping the scope. - let guard = AbortOnPanic; - - // Wait until all nested scopes are dropped. - drop(scope.wait_group); - wg.wait(); - - // Join all remaining spawned threads. - let panics: Vec<_> = scope - .handles - .lock() - .unwrap() - // Filter handles that haven't been joined, join them, and collect errors. - .drain(..) - .filter_map(|handle| handle.lock().unwrap().take()) - .filter_map(|handle| handle.join().err()) - .collect(); - - mem::forget(guard); - - // If `f` has panicked, resume unwinding. - // If any of the child threads have panicked, return the panic errors. - // Otherwise, everything is OK and return the result of `f`. - match result { - Err(err) => panic::resume_unwind(err), - Ok(res) => { - if panics.is_empty() { - Ok(res) - } else { - Err(Box::new(panics)) - } - } - } -} - -/// A scope for spawning threads. -pub struct Scope<'env> { - /// The list of the thread join handles. - handles: SharedVec<SharedOption<thread::JoinHandle<()>>>, - - /// Used to wait until all subscopes all dropped. - wait_group: WaitGroup, - - /// Borrows data with invariant lifetime `'env`. - _marker: PhantomData<&'env mut &'env ()>, -} - -unsafe impl Sync for Scope<'_> {} - -impl<'env> Scope<'env> { - /// Spawns a scoped thread. - /// - /// This method is similar to the [`spawn`] function in Rust's standard library. The difference - /// is that this thread is scoped, meaning it's guaranteed to terminate before the scope exits, - /// allowing it to reference variables outside the scope. - /// - /// The scoped thread is passed a reference to this scope as an argument, which can be used for - /// spawning nested threads. - /// - /// The returned [handle](ScopedJoinHandle) can be used to manually - /// [join](ScopedJoinHandle::join) the thread before the scope exits. - /// - /// This will create a thread using default parameters of [`ScopedThreadBuilder`], if you want to specify the - /// stack size or the name of the thread, use this API instead. - /// - /// [`spawn`]: std::thread::spawn - /// - /// # Panics - /// - /// Panics if the OS fails to create a thread; use [`ScopedThreadBuilder::spawn`] - /// to recover from such errors. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::thread; - /// - /// thread::scope(|s| { - /// let handle = s.spawn(|_| { - /// println!("A child thread is running"); - /// 42 - /// }); - /// - /// // Join the thread and retrieve its result. - /// let res = handle.join().unwrap(); - /// assert_eq!(res, 42); - /// }).unwrap(); - /// ``` - pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T> - where - F: FnOnce(&Scope<'env>) -> T, - F: Send + 'env, - T: Send + 'env, - { - self.builder() - .spawn(f) - .expect("failed to spawn scoped thread") - } - - /// Creates a builder that can configure a thread before spawning. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::thread; - /// - /// thread::scope(|s| { - /// s.builder() - /// .spawn(|_| println!("A child thread is running")) - /// .unwrap(); - /// }).unwrap(); - /// ``` - pub fn builder<'scope>(&'scope self) -> ScopedThreadBuilder<'scope, 'env> { - ScopedThreadBuilder { - scope: self, - builder: thread::Builder::new(), - } - } -} - -impl fmt::Debug for Scope<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Scope { .. }") - } -} - -/// Configures the properties of a new thread. -/// -/// The two configurable properties are: -/// -/// - [`name`]: Specifies an [associated name for the thread][naming-threads]. -/// - [`stack_size`]: Specifies the [desired stack size for the thread][stack-size]. -/// -/// The [`spawn`] method will take ownership of the builder and return an [`io::Result`] of the -/// thread handle with the given configuration. -/// -/// The [`Scope::spawn`] method uses a builder with default configuration and unwraps its return -/// value. You may want to use this builder when you want to recover from a failure to launch a -/// thread. -/// -/// # Examples -/// -/// ``` -/// use crossbeam_utils::thread; -/// -/// thread::scope(|s| { -/// s.builder() -/// .spawn(|_| println!("Running a child thread")) -/// .unwrap(); -/// }).unwrap(); -/// ``` -/// -/// [`name`]: ScopedThreadBuilder::name -/// [`stack_size`]: ScopedThreadBuilder::stack_size -/// [`spawn`]: ScopedThreadBuilder::spawn -/// [`io::Result`]: std::io::Result -/// [naming-threads]: std::thread#naming-threads -/// [stack-size]: std::thread#stack-size -#[derive(Debug)] -pub struct ScopedThreadBuilder<'scope, 'env> { - scope: &'scope Scope<'env>, - builder: thread::Builder, -} - -impl<'scope, 'env> ScopedThreadBuilder<'scope, 'env> { - /// Sets the name for the new thread. - /// - /// The name must not contain null bytes (`\0`). - /// - /// For more information about named threads, see [here][naming-threads]. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::thread; - /// use std::thread::current; - /// - /// thread::scope(|s| { - /// s.builder() - /// .name("my thread".to_string()) - /// .spawn(|_| assert_eq!(current().name(), Some("my thread"))) - /// .unwrap(); - /// }).unwrap(); - /// ``` - /// - /// [naming-threads]: std::thread#naming-threads - pub fn name(mut self, name: String) -> ScopedThreadBuilder<'scope, 'env> { - self.builder = self.builder.name(name); - self - } - - /// Sets the size of the stack for the new thread. - /// - /// The stack size is measured in bytes. - /// - /// For more information about the stack size for threads, see [here][stack-size]. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::thread; - /// - /// thread::scope(|s| { - /// s.builder() - /// .stack_size(32 * 1024) - /// .spawn(|_| println!("Running a child thread")) - /// .unwrap(); - /// }).unwrap(); - /// ``` - /// - /// [stack-size]: std::thread#stack-size - pub fn stack_size(mut self, size: usize) -> ScopedThreadBuilder<'scope, 'env> { - self.builder = self.builder.stack_size(size); - self - } - - /// Spawns a scoped thread with this configuration. - /// - /// The scoped thread is passed a reference to this scope as an argument, which can be used for - /// spawning nested threads. - /// - /// The returned handle can be used to manually join the thread before the scope exits. - /// - /// # Errors - /// - /// Unlike the [`Scope::spawn`] method, this method yields an - /// [`io::Result`] to capture any failure to create the thread at - /// the OS level. - /// - /// [`io::Result`]: std::io::Result - /// - /// # Panics - /// - /// Panics if a thread name was set and it contained null bytes. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::thread; - /// - /// thread::scope(|s| { - /// let handle = s.builder() - /// .spawn(|_| { - /// println!("A child thread is running"); - /// 42 - /// }) - /// .unwrap(); - /// - /// // Join the thread and retrieve its result. - /// let res = handle.join().unwrap(); - /// assert_eq!(res, 42); - /// }).unwrap(); - /// ``` - pub fn spawn<F, T>(self, f: F) -> io::Result<ScopedJoinHandle<'scope, T>> - where - F: FnOnce(&Scope<'env>) -> T, - F: Send + 'env, - T: Send + 'env, - { - // The result of `f` will be stored here. - let result = SharedOption::default(); - - // Spawn the thread and grab its join handle and thread handle. - let (handle, thread) = { - let result = Arc::clone(&result); - - // A clone of the scope that will be moved into the new thread. - let scope = Scope::<'env> { - handles: Arc::clone(&self.scope.handles), - wait_group: self.scope.wait_group.clone(), - _marker: PhantomData, - }; - - // Spawn the thread. - let handle = { - let closure = move || { - // Make sure the scope is inside the closure with the proper `'env` lifetime. - let scope: Scope<'env> = scope; - - // Run the closure. - let res = f(&scope); - - // Store the result if the closure didn't panic. - *result.lock().unwrap() = Some(res); - }; - - // Allocate `closure` on the heap and erase the `'env` bound. - let closure: Box<dyn FnOnce() + Send + 'env> = Box::new(closure); - let closure: Box<dyn FnOnce() + Send + 'static> = - unsafe { mem::transmute(closure) }; - - // Finally, spawn the closure. - self.builder.spawn(closure)? - }; - - let thread = handle.thread().clone(); - let handle = Arc::new(Mutex::new(Some(handle))); - (handle, thread) - }; - - // Add the handle to the shared list of join handles. - self.scope.handles.lock().unwrap().push(Arc::clone(&handle)); - - Ok(ScopedJoinHandle { - handle, - result, - thread, - _marker: PhantomData, - }) - } -} - -unsafe impl<T> Send for ScopedJoinHandle<'_, T> {} -unsafe impl<T> Sync for ScopedJoinHandle<'_, T> {} - -/// A handle that can be used to join its scoped thread. -/// -/// This struct is created by the [`Scope::spawn`] method and the -/// [`ScopedThreadBuilder::spawn`] method. -pub struct ScopedJoinHandle<'scope, T> { - /// A join handle to the spawned thread. - handle: SharedOption<thread::JoinHandle<()>>, - - /// Holds the result of the inner closure. - result: SharedOption<T>, - - /// A handle to the the spawned thread. - thread: thread::Thread, - - /// Borrows the parent scope with lifetime `'scope`. - _marker: PhantomData<&'scope ()>, -} - -impl<T> ScopedJoinHandle<'_, T> { - /// Waits for the thread to finish and returns its result. - /// - /// If the child thread panics, an error is returned. Note that if panics are implemented by - /// aborting the process, no error is returned; see the notes of [std::panic::catch_unwind]. - /// - /// # Panics - /// - /// This function may panic on some platforms if a thread attempts to join itself or otherwise - /// may create a deadlock with joining threads. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::thread; - /// - /// thread::scope(|s| { - /// let handle1 = s.spawn(|_| println!("I'm a happy thread :)")); - /// let handle2 = s.spawn(|_| panic!("I'm a sad thread :(")); - /// - /// // Join the first thread and verify that it succeeded. - /// let res = handle1.join(); - /// assert!(res.is_ok()); - /// - /// // Join the second thread and verify that it panicked. - /// let res = handle2.join(); - /// assert!(res.is_err()); - /// }).unwrap(); - /// ``` - pub fn join(self) -> thread::Result<T> { - // Take out the handle. The handle will surely be available because the root scope waits - // for nested scopes before joining remaining threads. - let handle = self.handle.lock().unwrap().take().unwrap(); - - // Join the thread and then take the result out of its inner closure. - handle - .join() - .map(|()| self.result.lock().unwrap().take().unwrap()) - } - - /// Returns a handle to the underlying thread. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_utils::thread; - /// - /// thread::scope(|s| { - /// let handle = s.spawn(|_| println!("A child thread is running")); - /// println!("The child thread ID: {:?}", handle.thread().id()); - /// }).unwrap(); - /// ``` - pub fn thread(&self) -> &thread::Thread { - &self.thread - } -} - -cfg_if! { - if #[cfg(unix)] { - use std::os::unix::thread::{JoinHandleExt, RawPthread}; - - impl<T> JoinHandleExt for ScopedJoinHandle<'_, T> { - fn as_pthread_t(&self) -> RawPthread { - // Borrow the handle. The handle will surely be available because the root scope waits - // for nested scopes before joining remaining threads. - let handle = self.handle.lock().unwrap(); - handle.as_ref().unwrap().as_pthread_t() - } - fn into_pthread_t(self) -> RawPthread { - self.as_pthread_t() - } - } - } else if #[cfg(windows)] { - use std::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle}; - - impl<T> AsRawHandle for ScopedJoinHandle<'_, T> { - fn as_raw_handle(&self) -> RawHandle { - // Borrow the handle. The handle will surely be available because the root scope waits - // for nested scopes before joining remaining threads. - let handle = self.handle.lock().unwrap(); - handle.as_ref().unwrap().as_raw_handle() - } - } - - impl<T> IntoRawHandle for ScopedJoinHandle<'_, T> { - fn into_raw_handle(self) -> RawHandle { - self.as_raw_handle() - } - } - } -} - -impl<T> fmt::Debug for ScopedJoinHandle<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("ScopedJoinHandle { .. }") - } -} diff --git a/vendor/crossbeam-utils/tests/atomic_cell.rs b/vendor/crossbeam-utils/tests/atomic_cell.rs deleted file mode 100644 index 7a2689d..0000000 --- a/vendor/crossbeam-utils/tests/atomic_cell.rs +++ /dev/null @@ -1,374 +0,0 @@ -use std::mem; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::SeqCst; - -use crossbeam_utils::atomic::AtomicCell; - -#[test] -fn is_lock_free() { - struct UsizeWrap(usize); - struct U8Wrap(bool); - struct I16Wrap(i16); - #[repr(align(8))] - struct U64Align8(u64); - - assert!(AtomicCell::<usize>::is_lock_free()); - assert!(AtomicCell::<isize>::is_lock_free()); - assert!(AtomicCell::<UsizeWrap>::is_lock_free()); - - assert!(AtomicCell::<()>::is_lock_free()); - - assert!(AtomicCell::<u8>::is_lock_free()); - assert!(AtomicCell::<i8>::is_lock_free()); - assert!(AtomicCell::<bool>::is_lock_free()); - assert!(AtomicCell::<U8Wrap>::is_lock_free()); - - assert!(AtomicCell::<u16>::is_lock_free()); - assert!(AtomicCell::<i16>::is_lock_free()); - assert!(AtomicCell::<I16Wrap>::is_lock_free()); - - assert!(AtomicCell::<u32>::is_lock_free()); - assert!(AtomicCell::<i32>::is_lock_free()); - - // Sizes of both types must be equal, and the alignment of `u64` must be greater or equal than - // that of `AtomicU64`. In i686-unknown-linux-gnu, the alignment of `u64` is `4` and alignment - // of `AtomicU64` is `8`, so `AtomicCell<u64>` is not lock-free. - assert_eq!( - AtomicCell::<u64>::is_lock_free(), - cfg!(target_has_atomic = "64") && std::mem::align_of::<u64>() == 8 - ); - assert_eq!(mem::size_of::<U64Align8>(), 8); - assert_eq!(mem::align_of::<U64Align8>(), 8); - assert_eq!( - AtomicCell::<U64Align8>::is_lock_free(), - cfg!(target_has_atomic = "64") - ); - - // AtomicU128 is unstable - assert!(!AtomicCell::<u128>::is_lock_free()); -} - -#[test] -fn const_is_lock_free() { - const _U: bool = AtomicCell::<usize>::is_lock_free(); - const _I: bool = AtomicCell::<isize>::is_lock_free(); -} - -#[test] -fn drops_unit() { - static CNT: AtomicUsize = AtomicUsize::new(0); - CNT.store(0, SeqCst); - - #[derive(Debug, PartialEq, Eq)] - struct Foo(); - - impl Foo { - fn new() -> Foo { - CNT.fetch_add(1, SeqCst); - Foo() - } - } - - impl Drop for Foo { - fn drop(&mut self) { - CNT.fetch_sub(1, SeqCst); - } - } - - impl Default for Foo { - fn default() -> Foo { - Foo::new() - } - } - - let a = AtomicCell::new(Foo::new()); - - assert_eq!(a.swap(Foo::new()), Foo::new()); - assert_eq!(CNT.load(SeqCst), 1); - - a.store(Foo::new()); - assert_eq!(CNT.load(SeqCst), 1); - - assert_eq!(a.swap(Foo::default()), Foo::new()); - assert_eq!(CNT.load(SeqCst), 1); - - drop(a); - assert_eq!(CNT.load(SeqCst), 0); -} - -#[test] -fn drops_u8() { - static CNT: AtomicUsize = AtomicUsize::new(0); - CNT.store(0, SeqCst); - - #[derive(Debug, PartialEq, Eq)] - struct Foo(u8); - - impl Foo { - fn new(val: u8) -> Foo { - CNT.fetch_add(1, SeqCst); - Foo(val) - } - } - - impl Drop for Foo { - fn drop(&mut self) { - CNT.fetch_sub(1, SeqCst); - } - } - - impl Default for Foo { - fn default() -> Foo { - Foo::new(0) - } - } - - let a = AtomicCell::new(Foo::new(5)); - - assert_eq!(a.swap(Foo::new(6)), Foo::new(5)); - assert_eq!(a.swap(Foo::new(1)), Foo::new(6)); - assert_eq!(CNT.load(SeqCst), 1); - - a.store(Foo::new(2)); - assert_eq!(CNT.load(SeqCst), 1); - - assert_eq!(a.swap(Foo::default()), Foo::new(2)); - assert_eq!(CNT.load(SeqCst), 1); - - assert_eq!(a.swap(Foo::default()), Foo::new(0)); - assert_eq!(CNT.load(SeqCst), 1); - - drop(a); - assert_eq!(CNT.load(SeqCst), 0); -} - -#[test] -fn drops_usize() { - static CNT: AtomicUsize = AtomicUsize::new(0); - CNT.store(0, SeqCst); - - #[derive(Debug, PartialEq, Eq)] - struct Foo(usize); - - impl Foo { - fn new(val: usize) -> Foo { - CNT.fetch_add(1, SeqCst); - Foo(val) - } - } - - impl Drop for Foo { - fn drop(&mut self) { - CNT.fetch_sub(1, SeqCst); - } - } - - impl Default for Foo { - fn default() -> Foo { - Foo::new(0) - } - } - - let a = AtomicCell::new(Foo::new(5)); - - assert_eq!(a.swap(Foo::new(6)), Foo::new(5)); - assert_eq!(a.swap(Foo::new(1)), Foo::new(6)); - assert_eq!(CNT.load(SeqCst), 1); - - a.store(Foo::new(2)); - assert_eq!(CNT.load(SeqCst), 1); - - assert_eq!(a.swap(Foo::default()), Foo::new(2)); - assert_eq!(CNT.load(SeqCst), 1); - - assert_eq!(a.swap(Foo::default()), Foo::new(0)); - assert_eq!(CNT.load(SeqCst), 1); - - drop(a); - assert_eq!(CNT.load(SeqCst), 0); -} - -#[test] -fn modular_u8() { - #[derive(Clone, Copy, Eq, Debug, Default)] - struct Foo(u8); - - impl PartialEq for Foo { - fn eq(&self, other: &Foo) -> bool { - self.0 % 5 == other.0 % 5 - } - } - - let a = AtomicCell::new(Foo(1)); - - assert_eq!(a.load(), Foo(1)); - assert_eq!(a.swap(Foo(2)), Foo(11)); - assert_eq!(a.load(), Foo(52)); - - a.store(Foo(0)); - assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100))); - assert_eq!(a.load().0, 5); - assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100))); - assert_eq!(a.load().0, 15); -} - -#[test] -fn modular_usize() { - #[derive(Clone, Copy, Eq, Debug, Default)] - struct Foo(usize); - - impl PartialEq for Foo { - fn eq(&self, other: &Foo) -> bool { - self.0 % 5 == other.0 % 5 - } - } - - let a = AtomicCell::new(Foo(1)); - - assert_eq!(a.load(), Foo(1)); - assert_eq!(a.swap(Foo(2)), Foo(11)); - assert_eq!(a.load(), Foo(52)); - - a.store(Foo(0)); - assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100))); - assert_eq!(a.load().0, 5); - assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100))); - assert_eq!(a.load().0, 15); -} - -#[test] -fn garbage_padding() { - #[derive(Copy, Clone, Eq, PartialEq)] - struct Object { - a: i64, - b: i32, - } - - let cell = AtomicCell::new(Object { a: 0, b: 0 }); - let _garbage = [0xfe, 0xfe, 0xfe, 0xfe, 0xfe]; // Needed - let next = Object { a: 0, b: 0 }; - - let prev = cell.load(); - assert!(cell.compare_exchange(prev, next).is_ok()); - println!(); -} - -#[test] -fn const_atomic_cell_new() { - static CELL: AtomicCell<usize> = AtomicCell::new(0); - - CELL.store(1); - assert_eq!(CELL.load(), 1); -} - -// https://github.com/crossbeam-rs/crossbeam/pull/767 -macro_rules! test_arithmetic { - ($test_name:ident, $ty:ident) => { - #[test] - fn $test_name() { - let a: AtomicCell<$ty> = AtomicCell::new(7); - - assert_eq!(a.fetch_add(3), 7); - assert_eq!(a.load(), 10); - - assert_eq!(a.fetch_sub(3), 10); - assert_eq!(a.load(), 7); - - assert_eq!(a.fetch_and(3), 7); - assert_eq!(a.load(), 3); - - assert_eq!(a.fetch_or(16), 3); - assert_eq!(a.load(), 19); - - assert_eq!(a.fetch_xor(2), 19); - assert_eq!(a.load(), 17); - - assert_eq!(a.fetch_max(18), 17); - assert_eq!(a.load(), 18); - - assert_eq!(a.fetch_min(17), 18); - assert_eq!(a.load(), 17); - - assert_eq!(a.fetch_nand(7), 17); - assert_eq!(a.load(), !(17 & 7)); - } - }; -} -test_arithmetic!(arithmetic_u8, u8); -test_arithmetic!(arithmetic_i8, i8); -test_arithmetic!(arithmetic_u16, u16); -test_arithmetic!(arithmetic_i16, i16); -test_arithmetic!(arithmetic_u32, u32); -test_arithmetic!(arithmetic_i32, i32); -test_arithmetic!(arithmetic_u64, u64); -test_arithmetic!(arithmetic_i64, i64); -test_arithmetic!(arithmetic_u128, u128); -test_arithmetic!(arithmetic_i128, i128); - -// https://github.com/crossbeam-rs/crossbeam/issues/748 -#[cfg_attr(miri, ignore)] // TODO -#[test] -fn issue_748() { - #[allow(dead_code)] - #[repr(align(8))] - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - enum Test { - Field(u32), - FieldLess, - } - - assert_eq!(mem::size_of::<Test>(), 8); - assert_eq!( - AtomicCell::<Test>::is_lock_free(), - cfg!(target_has_atomic = "64") - ); - let x = AtomicCell::new(Test::FieldLess); - assert_eq!(x.load(), Test::FieldLess); -} - -// https://github.com/crossbeam-rs/crossbeam/issues/833 -#[test] -fn issue_833() { - use std::num::NonZeroU128; - use std::sync::atomic::{AtomicBool, Ordering}; - use std::thread; - - #[cfg(miri)] - const N: usize = 10_000; - #[cfg(not(miri))] - const N: usize = 1_000_000; - - #[allow(dead_code)] - enum Enum { - NeverConstructed, - Cell(AtomicCell<NonZeroU128>), - } - - static STATIC: Enum = Enum::Cell(AtomicCell::new(match NonZeroU128::new(1) { - Some(nonzero) => nonzero, - None => unreachable!(), - })); - static FINISHED: AtomicBool = AtomicBool::new(false); - - let handle = thread::spawn(|| { - let cell = match &STATIC { - Enum::NeverConstructed => unreachable!(), - Enum::Cell(cell) => cell, - }; - let x = NonZeroU128::new(0xFFFF_FFFF_FFFF_FFFF_0000_0000_0000_0000).unwrap(); - let y = NonZeroU128::new(0x0000_0000_0000_0000_FFFF_FFFF_FFFF_FFFF).unwrap(); - while !FINISHED.load(Ordering::Relaxed) { - cell.store(x); - cell.store(y); - } - }); - - for _ in 0..N { - if let Enum::NeverConstructed = STATIC { - unreachable!(":("); - } - } - - FINISHED.store(true, Ordering::Relaxed); - handle.join().unwrap(); -} diff --git a/vendor/crossbeam-utils/tests/cache_padded.rs b/vendor/crossbeam-utils/tests/cache_padded.rs deleted file mode 100644 index 86e9a77..0000000 --- a/vendor/crossbeam-utils/tests/cache_padded.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::cell::Cell; -use std::mem; - -use crossbeam_utils::CachePadded; - -#[test] -fn default() { - let x: CachePadded<u64> = Default::default(); - assert_eq!(*x, 0); -} - -#[test] -fn store_u64() { - let x: CachePadded<u64> = CachePadded::new(17); - assert_eq!(*x, 17); -} - -#[test] -fn store_pair() { - let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37)); - assert_eq!(x.0, 17); - assert_eq!(x.1, 37); -} - -#[test] -fn distance() { - let arr = [CachePadded::new(17u8), CachePadded::new(37u8)]; - let a = &*arr[0] as *const u8; - let b = &*arr[1] as *const u8; - let align = mem::align_of::<CachePadded<()>>(); - assert!(align >= 32); - assert_eq!(unsafe { a.add(align) }, b); -} - -#[test] -fn different_sizes() { - CachePadded::new(17u8); - CachePadded::new(17u16); - CachePadded::new(17u32); - CachePadded::new([17u64; 0]); - CachePadded::new([17u64; 1]); - CachePadded::new([17u64; 2]); - CachePadded::new([17u64; 3]); - CachePadded::new([17u64; 4]); - CachePadded::new([17u64; 5]); - CachePadded::new([17u64; 6]); - CachePadded::new([17u64; 7]); - CachePadded::new([17u64; 8]); -} - -#[test] -fn large() { - let a = [17u64; 9]; - let b = CachePadded::new(a); - assert!(mem::size_of_val(&a) <= mem::size_of_val(&b)); -} - -#[test] -fn debug() { - assert_eq!( - format!("{:?}", CachePadded::new(17u64)), - "CachePadded { value: 17 }" - ); -} - -#[test] -fn drops() { - let count = Cell::new(0); - - struct Foo<'a>(&'a Cell<usize>); - - impl<'a> Drop for Foo<'a> { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } - } - - let a = CachePadded::new(Foo(&count)); - let b = CachePadded::new(Foo(&count)); - - assert_eq!(count.get(), 0); - drop(a); - assert_eq!(count.get(), 1); - drop(b); - assert_eq!(count.get(), 2); -} - -#[allow(clippy::clone_on_copy)] // This is intentional. -#[test] -fn clone() { - let a = CachePadded::new(17); - let b = a.clone(); - assert_eq!(*a, *b); -} - -#[test] -fn runs_custom_clone() { - let count = Cell::new(0); - - struct Foo<'a>(&'a Cell<usize>); - - impl<'a> Clone for Foo<'a> { - fn clone(&self) -> Foo<'a> { - self.0.set(self.0.get() + 1); - Foo::<'a>(self.0) - } - } - - let a = CachePadded::new(Foo(&count)); - let _ = a.clone(); - - assert_eq!(count.get(), 1); -} diff --git a/vendor/crossbeam-utils/tests/parker.rs b/vendor/crossbeam-utils/tests/parker.rs deleted file mode 100644 index 2bf9c37..0000000 --- a/vendor/crossbeam-utils/tests/parker.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::thread::sleep; -use std::time::Duration; -use std::u32; - -use crossbeam_utils::sync::Parker; -use crossbeam_utils::thread; - -#[test] -fn park_timeout_unpark_before() { - let p = Parker::new(); - for _ in 0..10 { - p.unparker().unpark(); - p.park_timeout(Duration::from_millis(u32::MAX as u64)); - } -} - -#[test] -fn park_timeout_unpark_not_called() { - let p = Parker::new(); - for _ in 0..10 { - p.park_timeout(Duration::from_millis(10)) - } -} - -#[test] -fn park_timeout_unpark_called_other_thread() { - for _ in 0..10 { - let p = Parker::new(); - let u = p.unparker().clone(); - - thread::scope(|scope| { - scope.spawn(move |_| { - sleep(Duration::from_millis(50)); - u.unpark(); - }); - - p.park_timeout(Duration::from_millis(u32::MAX as u64)) - }) - .unwrap(); - } -} diff --git a/vendor/crossbeam-utils/tests/sharded_lock.rs b/vendor/crossbeam-utils/tests/sharded_lock.rs deleted file mode 100644 index 002f7f5..0000000 --- a/vendor/crossbeam-utils/tests/sharded_lock.rs +++ /dev/null @@ -1,252 +0,0 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::mpsc::channel; -use std::sync::{Arc, TryLockError}; -use std::thread; - -use crossbeam_utils::sync::ShardedLock; -use rand::Rng; - -#[derive(Eq, PartialEq, Debug)] -struct NonCopy(i32); - -#[test] -fn smoke() { - let l = ShardedLock::new(()); - drop(l.read().unwrap()); - drop(l.write().unwrap()); - drop((l.read().unwrap(), l.read().unwrap())); - drop(l.write().unwrap()); -} - -#[test] -fn frob() { - const N: u32 = 10; - #[cfg(miri)] - const M: usize = 50; - #[cfg(not(miri))] - const M: usize = 1000; - - let r = Arc::new(ShardedLock::new(())); - - let (tx, rx) = channel::<()>(); - for _ in 0..N { - let tx = tx.clone(); - let r = r.clone(); - thread::spawn(move || { - let mut rng = rand::thread_rng(); - for _ in 0..M { - if rng.gen_bool(1.0 / (N as f64)) { - drop(r.write().unwrap()); - } else { - drop(r.read().unwrap()); - } - } - drop(tx); - }); - } - drop(tx); - let _ = rx.recv(); -} - -#[test] -fn arc_poison_wr() { - let arc = Arc::new(ShardedLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }) - .join(); - assert!(arc.read().is_err()); -} - -#[test] -fn arc_poison_ww() { - let arc = Arc::new(ShardedLock::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }) - .join(); - assert!(arc.write().is_err()); - assert!(arc.is_poisoned()); -} - -#[test] -fn arc_no_poison_rr() { - let arc = Arc::new(ShardedLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!(); - }) - .join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 1); -} -#[test] -fn arc_no_poison_sl() { - let arc = Arc::new(ShardedLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!() - }) - .join(); - let lock = arc.write().unwrap(); - assert_eq!(*lock, 1); -} - -#[test] -fn arc() { - let arc = Arc::new(ShardedLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - thread::spawn(move || { - let mut lock = arc2.write().unwrap(); - for _ in 0..10 { - let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - } - tx.send(()).unwrap(); - }); - - // Readers try to catch the writer in the act - let mut children = Vec::new(); - for _ in 0..5 { - let arc3 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc3.read().unwrap(); - assert!(*lock >= 0); - })); - } - - // Wait for children to pass their asserts - for r in children { - assert!(r.join().is_ok()); - } - - // Wait for writer to finish - rx.recv().unwrap(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 10); -} - -#[test] -fn arc_access_in_unwind() { - let arc = Arc::new(ShardedLock::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - struct Unwinder { - i: Arc<ShardedLock<isize>>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - let mut lock = self.i.write().unwrap(); - *lock += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 2); -} - -#[test] -fn unsized_type() { - let sl: &ShardedLock<[i32]> = &ShardedLock::new([1, 2, 3]); - { - let b = &mut *sl.write().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*sl.read().unwrap(), comp); -} - -#[test] -fn try_write() { - let lock = ShardedLock::new(0isize); - let read_guard = lock.read().unwrap(); - - let write_result = lock.try_write(); - match write_result { - Err(TryLockError::WouldBlock) => (), - Ok(_) => panic!("try_write should not succeed while read_guard is in scope"), - Err(_) => panic!("unexpected error"), - } - - drop(read_guard); -} - -#[test] -fn test_into_inner() { - let m = ShardedLock::new(NonCopy(10)); - assert_eq!(m.into_inner().unwrap(), NonCopy(10)); -} - -#[test] -fn test_into_inner_drop() { - struct Foo(Arc<AtomicUsize>); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = ShardedLock::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner().unwrap(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); -} - -#[test] -fn test_into_inner_poison() { - let m = Arc::new(ShardedLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison ShardedLock"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { - Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned ShardedLock is Ok: {:?}", x), - } -} - -#[test] -fn test_get_mut() { - let mut m = ShardedLock::new(NonCopy(10)); - *m.get_mut().unwrap() = NonCopy(20); - assert_eq!(m.into_inner().unwrap(), NonCopy(20)); -} - -#[test] -fn test_get_mut_poison() { - let m = Arc::new(ShardedLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison ShardedLock"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { - Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned ShardedLock is Ok: {:?}", x), - } -} diff --git a/vendor/crossbeam-utils/tests/thread.rs b/vendor/crossbeam-utils/tests/thread.rs deleted file mode 100644 index 0dfad90..0000000 --- a/vendor/crossbeam-utils/tests/thread.rs +++ /dev/null @@ -1,215 +0,0 @@ -use std::any::Any; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::thread::sleep; -use std::time::Duration; - -use crossbeam_utils::thread; - -const THREADS: usize = 10; -const SMALL_STACK_SIZE: usize = 20; - -#[test] -fn join() { - let counter = AtomicUsize::new(0); - thread::scope(|scope| { - let handle = scope.spawn(|_| { - counter.store(1, Ordering::Relaxed); - }); - assert!(handle.join().is_ok()); - - let panic_handle = scope.spawn(|_| { - panic!("\"My honey is running out!\", said Pooh."); - }); - assert!(panic_handle.join().is_err()); - }) - .unwrap(); - - // There should be sufficient synchronization. - assert_eq!(1, counter.load(Ordering::Relaxed)); -} - -#[test] -fn counter() { - let counter = AtomicUsize::new(0); - thread::scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - counter.fetch_add(1, Ordering::Relaxed); - }); - } - }) - .unwrap(); - - assert_eq!(THREADS, counter.load(Ordering::Relaxed)); -} - -#[test] -fn counter_builder() { - let counter = AtomicUsize::new(0); - thread::scope(|scope| { - for i in 0..THREADS { - scope - .builder() - .name(format!("child-{}", i)) - .stack_size(SMALL_STACK_SIZE) - .spawn(|_| { - counter.fetch_add(1, Ordering::Relaxed); - }) - .unwrap(); - } - }) - .unwrap(); - - assert_eq!(THREADS, counter.load(Ordering::Relaxed)); -} - -#[test] -fn counter_panic() { - let counter = AtomicUsize::new(0); - let result = thread::scope(|scope| { - scope.spawn(|_| { - panic!("\"My honey is running out!\", said Pooh."); - }); - sleep(Duration::from_millis(100)); - - for _ in 0..THREADS { - scope.spawn(|_| { - counter.fetch_add(1, Ordering::Relaxed); - }); - } - }); - - assert_eq!(THREADS, counter.load(Ordering::Relaxed)); - assert!(result.is_err()); -} - -#[test] -fn panic_twice() { - let result = thread::scope(|scope| { - scope.spawn(|_| { - sleep(Duration::from_millis(500)); - panic!("thread #1"); - }); - scope.spawn(|_| { - panic!("thread #2"); - }); - }); - - let err = result.unwrap_err(); - let vec = err - .downcast_ref::<Vec<Box<dyn Any + Send + 'static>>>() - .unwrap(); - assert_eq!(2, vec.len()); - - let first = vec[0].downcast_ref::<&str>().unwrap(); - let second = vec[1].downcast_ref::<&str>().unwrap(); - assert_eq!("thread #1", *first); - assert_eq!("thread #2", *second) -} - -#[test] -fn panic_many() { - let result = thread::scope(|scope| { - scope.spawn(|_| panic!("deliberate panic #1")); - scope.spawn(|_| panic!("deliberate panic #2")); - scope.spawn(|_| panic!("deliberate panic #3")); - }); - - let err = result.unwrap_err(); - let vec = err - .downcast_ref::<Vec<Box<dyn Any + Send + 'static>>>() - .unwrap(); - assert_eq!(3, vec.len()); - - for panic in vec.iter() { - let panic = panic.downcast_ref::<&str>().unwrap(); - assert!( - *panic == "deliberate panic #1" - || *panic == "deliberate panic #2" - || *panic == "deliberate panic #3" - ); - } -} - -#[test] -fn nesting() { - let var = "foo".to_string(); - - struct Wrapper<'a> { - var: &'a String, - } - - impl<'a> Wrapper<'a> { - fn recurse(&'a self, scope: &thread::Scope<'a>, depth: usize) { - assert_eq!(self.var, "foo"); - - if depth > 0 { - scope.spawn(move |scope| { - self.recurse(scope, depth - 1); - }); - } - } - } - - let wrapper = Wrapper { var: &var }; - - thread::scope(|scope| { - scope.spawn(|scope| { - scope.spawn(|scope| { - wrapper.recurse(scope, 5); - }); - }); - }) - .unwrap(); -} - -#[test] -fn join_nested() { - thread::scope(|scope| { - scope.spawn(|scope| { - let handle = scope.spawn(|_| 7); - - sleep(Duration::from_millis(200)); - handle.join().unwrap(); - }); - - sleep(Duration::from_millis(100)); - }) - .unwrap(); -} - -#[test] -fn scope_returns_ok() { - let result = thread::scope(|scope| scope.spawn(|_| 1234).join().unwrap()).unwrap(); - assert_eq!(result, 1234); -} - -#[cfg(unix)] -#[test] -fn as_pthread_t() { - use std::os::unix::thread::JoinHandleExt; - thread::scope(|scope| { - let handle = scope.spawn(|_scope| { - sleep(Duration::from_millis(100)); - 42 - }); - let _pthread_t = handle.as_pthread_t(); - handle.join().unwrap(); - }) - .unwrap(); -} - -#[cfg(windows)] -#[test] -fn as_raw_handle() { - use std::os::windows::io::AsRawHandle; - thread::scope(|scope| { - let handle = scope.spawn(|_scope| { - sleep(Duration::from_millis(100)); - 42 - }); - let _raw_handle = handle.as_raw_handle(); - handle.join().unwrap(); - }) - .unwrap(); -} diff --git a/vendor/crossbeam-utils/tests/wait_group.rs b/vendor/crossbeam-utils/tests/wait_group.rs deleted file mode 100644 index 5b549b8..0000000 --- a/vendor/crossbeam-utils/tests/wait_group.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::sync::mpsc; -use std::thread; -use std::time::Duration; - -use crossbeam_utils::sync::WaitGroup; - -const THREADS: usize = 10; - -#[test] -fn wait() { - let wg = WaitGroup::new(); - let (tx, rx) = mpsc::channel(); - - for _ in 0..THREADS { - let wg = wg.clone(); - let tx = tx.clone(); - - thread::spawn(move || { - wg.wait(); - tx.send(()).unwrap(); - }); - } - - thread::sleep(Duration::from_millis(100)); - - // At this point, all spawned threads should be blocked, so we shouldn't get anything from the - // channel. - assert!(rx.try_recv().is_err()); - - wg.wait(); - - // Now, the wait group is cleared and we should receive messages. - for _ in 0..THREADS { - rx.recv().unwrap(); - } -} - -#[test] -fn wait_and_drop() { - let wg = WaitGroup::new(); - let wg2 = WaitGroup::new(); - let (tx, rx) = mpsc::channel(); - - for _ in 0..THREADS { - let wg = wg.clone(); - let wg2 = wg2.clone(); - let tx = tx.clone(); - - thread::spawn(move || { - wg2.wait(); - tx.send(()).unwrap(); - drop(wg); - }); - } - - // At this point, no thread has gotten past `wg2.wait()`, so we shouldn't get anything from the - // channel. - assert!(rx.try_recv().is_err()); - drop(wg2); - - wg.wait(); - - // Now, the wait group is cleared and we should receive messages. - for _ in 0..THREADS { - rx.try_recv().unwrap(); - } -} |