aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:05:44 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:05:44 +0000
commit3a03ccb840974bbd23e9cf666ad9e7cb7d3372cf (patch)
tree9920d6c25aa95c5ccff5cf61965f1a8d34973523
parentf85f5d224d731630716bfd9a48489056a68919dc (diff)
parentcff857dd15d4e02379b3dba00804c84bf8c4049f (diff)
downloadcrossbeam-utils-3a03ccb840974bbd23e9cf666ad9e7cb7d3372cf.tar.gz
Snap for 8564071 from cff857dd15d4e02379b3dba00804c84bf8c4049f to mainline-conscrypt-releaseaml_con_331413000aml_con_331411000aml_con_331312000aml_con_331115000aml_con_331011010android13-mainline-conscrypt-release
Change-Id: I832373654fa6559b2f4d3abf058846d3725d1841
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--Android.bp134
-rw-r--r--CHANGELOG.md20
-rw-r--r--Cargo.toml38
-rw-r--r--Cargo.toml.orig22
-rw-r--r--METADATA8
-rw-r--r--README.md2
-rw-r--r--TEST_MAPPING64
-rw-r--r--build.rs62
-rw-r--r--cargo2android.json9
-rw-r--r--no_atomic.rs71
-rw-r--r--patches/disable_panic_tests_on_android.patch8
-rw-r--r--src/atomic/atomic_cell.rs566
-rw-r--r--src/atomic/consume.rs24
-rw-r--r--src/atomic/mod.rs8
-rw-r--r--src/lib.rs27
-rw-r--r--src/sync/parker.rs2
-rw-r--r--src/thread.rs2
-rw-r--r--tests/atomic_cell.rs120
-rw-r--r--tests/cache_padded.rs1
-rw-r--r--tests/sharded_lock.rs5
21 files changed, 837 insertions, 363 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 1d9c34d..0d40a83 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
{
"git": {
- "sha1": "d841a2028dc72b4e09739116f07e865db60f3690"
- }
-}
+ "sha1": "2988f873f87d2263a7fd2b9465fb9c28f43a6490"
+ },
+ "path_in_vcs": "crossbeam-utils"
+} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 1a2c24f..5f17007 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --run --device --dependencies --tests.
+// This file is generated by cargo2android.py --config cargo2android.json.
// Do not modify this file as changes will be overridden on upgrade.
package {
@@ -39,47 +39,37 @@ license {
],
}
-rust_defaults {
- name: "crossbeam-utils_defaults",
+rust_test {
+ name: "crossbeam-utils_test_src_lib",
+ host_supported: true,
crate_name: "crossbeam_utils",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.8.7",
srcs: ["src/lib.rs"],
test_suites: ["general-tests"],
auto_gen_config: true,
+ test_options: {
+ unit_test: true,
+ },
edition: "2018",
features: [
"default",
"lazy_static",
"std",
],
- cfgs: [
- "has_atomic_u16",
- "has_atomic_u32",
- "has_atomic_u64",
- "has_atomic_u8",
- ],
rustlibs: [
"libcfg_if",
"liblazy_static",
"librand",
],
-}
-
-rust_test_host {
- name: "crossbeam-utils_host_test_src_lib",
- defaults: ["crossbeam-utils_defaults"],
- test_options: {
- unit_test: true,
- },
-}
-
-rust_test {
- name: "crossbeam-utils_device_test_src_lib",
- defaults: ["crossbeam-utils_defaults"],
+ proc_macros: ["librustversion"],
}
rust_defaults {
- name: "crossbeam-utils_defaults_crossbeam_utils",
+ name: "crossbeam-utils_test_defaults",
crate_name: "crossbeam_utils",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.8.7",
test_suites: ["general-tests"],
auto_gen_config: true,
edition: "2018",
@@ -88,23 +78,19 @@ rust_defaults {
"lazy_static",
"std",
],
- cfgs: [
- "has_atomic_u16",
- "has_atomic_u32",
- "has_atomic_u64",
- "has_atomic_u8",
- ],
rustlibs: [
"libcfg_if",
"libcrossbeam_utils",
"liblazy_static",
"librand",
],
+ proc_macros: ["librustversion"],
}
-rust_test_host {
- name: "crossbeam-utils_host_test_tests_atomic_cell",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
+rust_test {
+ name: "crossbeam-utils_test_tests_atomic_cell",
+ defaults: ["crossbeam-utils_test_defaults"],
+ host_supported: true,
srcs: ["tests/atomic_cell.rs"],
test_options: {
unit_test: true,
@@ -112,14 +98,9 @@ rust_test_host {
}
rust_test {
- name: "crossbeam-utils_device_test_tests_atomic_cell",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
- srcs: ["tests/atomic_cell.rs"],
-}
-
-rust_test_host {
- name: "crossbeam-utils_host_test_tests_cache_padded",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
+ name: "crossbeam-utils_test_tests_cache_padded",
+ defaults: ["crossbeam-utils_test_defaults"],
+ host_supported: true,
srcs: ["tests/cache_padded.rs"],
test_options: {
unit_test: true,
@@ -127,14 +108,9 @@ rust_test_host {
}
rust_test {
- name: "crossbeam-utils_device_test_tests_cache_padded",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
- srcs: ["tests/cache_padded.rs"],
-}
-
-rust_test_host {
- name: "crossbeam-utils_host_test_tests_parker",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
+ name: "crossbeam-utils_test_tests_parker",
+ defaults: ["crossbeam-utils_test_defaults"],
+ host_supported: true,
srcs: ["tests/parker.rs"],
test_options: {
unit_test: true,
@@ -142,14 +118,9 @@ rust_test_host {
}
rust_test {
- name: "crossbeam-utils_device_test_tests_parker",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
- srcs: ["tests/parker.rs"],
-}
-
-rust_test_host {
- name: "crossbeam-utils_host_test_tests_sharded_lock",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
+ name: "crossbeam-utils_test_tests_sharded_lock",
+ defaults: ["crossbeam-utils_test_defaults"],
+ host_supported: true,
srcs: ["tests/sharded_lock.rs"],
test_options: {
unit_test: true,
@@ -157,14 +128,9 @@ rust_test_host {
}
rust_test {
- name: "crossbeam-utils_device_test_tests_sharded_lock",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
- srcs: ["tests/sharded_lock.rs"],
-}
-
-rust_test_host {
- name: "crossbeam-utils_host_test_tests_thread",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
+ name: "crossbeam-utils_test_tests_thread",
+ defaults: ["crossbeam-utils_test_defaults"],
+ host_supported: true,
srcs: ["tests/thread.rs"],
test_options: {
unit_test: true,
@@ -172,30 +138,21 @@ rust_test_host {
}
rust_test {
- name: "crossbeam-utils_device_test_tests_thread",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
- srcs: ["tests/thread.rs"],
-}
-
-rust_test_host {
- name: "crossbeam-utils_host_test_tests_wait_group",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
+ name: "crossbeam-utils_test_tests_wait_group",
+ defaults: ["crossbeam-utils_test_defaults"],
+ host_supported: true,
srcs: ["tests/wait_group.rs"],
test_options: {
unit_test: true,
},
}
-rust_test {
- name: "crossbeam-utils_device_test_tests_wait_group",
- defaults: ["crossbeam-utils_defaults_crossbeam_utils"],
- srcs: ["tests/wait_group.rs"],
-}
-
rust_library {
name: "libcrossbeam_utils",
host_supported: true,
crate_name: "crossbeam_utils",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.8.7",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
@@ -203,25 +160,12 @@ rust_library {
"lazy_static",
"std",
],
- cfgs: [
- "has_atomic_u16",
- "has_atomic_u32",
- "has_atomic_u64",
- "has_atomic_u8",
- ],
rustlibs: [
"libcfg_if",
"liblazy_static",
],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
-
-// dependent_library ["feature_list"]
-// autocfg-1.0.1
-// cfg-if-1.0.0
-// getrandom-0.2.2 "std"
-// lazy_static-1.4.0
-// libc-0.2.93
-// ppv-lite86-0.2.10 "simd,std"
-// rand-0.8.3 "alloc,default,getrandom,libc,rand_chacha,rand_hc,std,std_rng"
-// rand_chacha-0.3.0 "std"
-// rand_core-0.6.2 "alloc,getrandom,std"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c4a92bf..98088c5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,23 @@
+# 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
+
+- 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
+
+- Add `AtomicCell::fetch_update`. (#704)
+- Support targets that do not have atomic CAS on stable Rust. (#698)
+
+# Version 0.8.4
+
+- Bump `loom` dependency to version 0.5. (#686)
+
# Version 0.8.3
- Make `loom` dependency optional. (#666)
diff --git a/Cargo.toml b/Cargo.toml
index a7d694c..10d3240 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,40 +3,52 @@
# 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
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
+rust-version = "1.36"
name = "crossbeam-utils"
-version = "0.8.3"
-authors = ["The Crossbeam Project Developers"]
+version = "0.8.7"
description = "Utilities for concurrent programming"
homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils"
-documentation = "https://docs.rs/crossbeam-utils"
-keywords = ["scoped", "thread", "atomic", "cache"]
-categories = ["algorithms", "concurrency", "data-structures", "no-std"]
+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"
[dependencies.lazy_static]
version = "1.4.0"
optional = true
+
[dev-dependencies.rand]
version = "0.8"
-[build-dependencies.autocfg]
-version = "1.0.0"
+
+[dev-dependencies.rustversion]
+version = "1"
[features]
default = ["std"]
nightly = []
std = ["lazy_static"]
+
[target."cfg(crossbeam_loom)".dependencies.loom]
-version = "0.4"
+version = "0.5"
optional = true
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 30697d2..73508a9 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -4,13 +4,12 @@ name = "crossbeam-utils"
# - Update CHANGELOG.md
# - Update README.md
# - Create "crossbeam-utils-X.Y.Z" git tag
-version = "0.8.3"
-authors = ["The Crossbeam Project Developers"]
+version = "0.8.7"
edition = "2018"
+rust-version = "1.36"
license = "MIT OR Apache-2.0"
repository = "https://github.com/crossbeam-rs/crossbeam"
homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils"
-documentation = "https://docs.rs/crossbeam-utils"
description = "Utilities for concurrent programming"
keywords = ["scoped", "thread", "atomic", "cache"]
categories = ["algorithms", "concurrency", "data-structures", "no-std"]
@@ -22,10 +21,13 @@ default = ["std"]
# This is enabled by default.
std = ["lazy_static"]
+# These features are no longer used.
+# TODO: remove in the next major version.
# Enable to use of unstable functionality.
# This is disabled by default and requires recent nightly compiler.
-# Note that this is outside of the normal semver guarantees and minor versions
-# of crossbeam may make breaking changes to them at any time.
+#
+# NOTE: This feature is outside of the normal semver guarantees and minor or
+# patch versions of crossbeam may make breaking changes to them at any time.
nightly = []
[dependencies]
@@ -34,13 +36,11 @@ lazy_static = { version = "1.4.0", optional = true }
# Enable the use of loom for concurrency testing.
#
-# This configuration option is outside of the normal semver guarantees: minor
-# versions of crossbeam may make breaking changes to it at any time.
+# NOTE: This feature is outside of the normal semver guarantees and minor or
+# patch versions of crossbeam may make breaking changes to them at any time.
[target.'cfg(crossbeam_loom)'.dependencies]
-loom = { version = "0.4", optional = true }
-
-[build-dependencies]
-autocfg = "1.0.0"
+loom = { version = "0.5", optional = true }
[dev-dependencies]
rand = "0.8"
+rustversion = "1"
diff --git a/METADATA b/METADATA
index e66f8d0..2c55b77 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/crossbeam-utils/crossbeam-utils-0.8.3.crate"
+ value: "https://static.crates.io/crates/crossbeam-utils/crossbeam-utils-0.8.7.crate"
}
- version: "0.8.3"
+ version: "0.8.7"
license_type: NOTICE
last_upgrade_date {
- year: 2021
- month: 4
+ year: 2022
+ month: 3
day: 1
}
}
diff --git a/README.md b/README.md
index fd0943b..6e9a8e4 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ https://crates.io/crates/crossbeam-utils)
https://docs.rs/crossbeam-utils)
[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)](
https://www.rust-lang.org)
-[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq)
+[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ)
This crate provides miscellaneous tools for concurrent programming:
diff --git a/TEST_MAPPING b/TEST_MAPPING
index a68b776..eb8da39 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,32 +1,78 @@
// Generated by update_crate_tests.py for tests that depend on this crate.
{
+ "imports": [
+ {
+ "path": "external/rust/crates/base64"
+ },
+ {
+ "path": "external/rust/crates/crossbeam-deque"
+ },
+ {
+ "path": "external/rust/crates/crossbeam-epoch"
+ },
+ {
+ "path": "external/rust/crates/crossbeam-queue"
+ },
+ {
+ "path": "external/rust/crates/once_cell"
+ },
+ {
+ "path": "external/rust/crates/tinytemplate"
+ },
+ {
+ "path": "external/rust/crates/tinyvec"
+ },
+ {
+ "path": "external/rust/crates/unicode-xid"
+ },
+ {
+ "path": "external/rust/crates/vulkano"
+ }
+ ],
"presubmit": [
{
- "name": "crossbeam-epoch_device_test_src_lib"
+ "name": "crossbeam-utils_test_src_lib"
+ },
+ {
+ "name": "crossbeam-utils_test_tests_atomic_cell"
+ },
+ {
+ "name": "crossbeam-utils_test_tests_cache_padded"
+ },
+ {
+ "name": "crossbeam-utils_test_tests_parker"
},
{
- "name": "crossbeam-epoch_device_test_tests_loom"
+ "name": "crossbeam-utils_test_tests_sharded_lock"
},
{
- "name": "crossbeam-utils_device_test_src_lib"
+ "name": "crossbeam-utils_test_tests_thread"
+ },
+ {
+ "name": "crossbeam-utils_test_tests_wait_group"
+ }
+ ],
+ "presubmit-rust": [
+ {
+ "name": "crossbeam-utils_test_src_lib"
},
{
- "name": "crossbeam-utils_device_test_tests_atomic_cell"
+ "name": "crossbeam-utils_test_tests_atomic_cell"
},
{
- "name": "crossbeam-utils_device_test_tests_cache_padded"
+ "name": "crossbeam-utils_test_tests_cache_padded"
},
{
- "name": "crossbeam-utils_device_test_tests_parker"
+ "name": "crossbeam-utils_test_tests_parker"
},
{
- "name": "crossbeam-utils_device_test_tests_sharded_lock"
+ "name": "crossbeam-utils_test_tests_sharded_lock"
},
{
- "name": "crossbeam-utils_device_test_tests_thread"
+ "name": "crossbeam-utils_test_tests_thread"
},
{
- "name": "crossbeam-utils_device_test_tests_wait_group"
+ "name": "crossbeam-utils_test_tests_wait_group"
}
]
}
diff --git a/build.rs b/build.rs
index 3e51021..a7557fd 100644
--- a/build.rs
+++ b/build.rs
@@ -1,23 +1,61 @@
-use autocfg::AutoCfg;
+// The rustc-cfg listed below are considered public API, but it is *unstable*
+// and outside of the normal semver guarantees:
+//
+// - `crossbeam_no_atomic_cas`
+// Assume the target does *not* support atomic CAS 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.
+//
+// - `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.
+//
+// - `crossbeam_no_atomic_64`
+// Assume the target does *not* support AtomicU64/AtomicI64.
+// 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");
-// The rustc-cfg strings below are *not* public API. Please let us know by
-// opening a GitHub issue if your build environment requires some way to enable
-// these cfgs other than by executing our build script.
fn main() {
- let cfg = match AutoCfg::new() {
- Ok(cfg) => cfg,
+ let target = match env::var("TARGET") {
+ Ok(target) => target,
Err(e) => {
println!(
- "cargo:warning=crossbeam-utils: unable to determine rustc version: {}",
+ "cargo:warning={}: unable to get TARGET environment variable: {}",
+ env!("CARGO_PKG_NAME"),
e
);
return;
}
};
- cfg.emit_type_cfg("core::sync::atomic::AtomicU8", "has_atomic_u8");
- cfg.emit_type_cfg("core::sync::atomic::AtomicU16", "has_atomic_u16");
- cfg.emit_type_cfg("core::sync::atomic::AtomicU32", "has_atomic_u32");
- cfg.emit_type_cfg("core::sync::atomic::AtomicU64", "has_atomic_u64");
- cfg.emit_type_cfg("core::sync::atomic::AtomicU128", "has_atomic_u128");
+ // Note that this is `no_*`, not `has_*`. This allows treating
+ // `cfg(target_has_atomic = "ptr")` as true when the build script doesn't
+ // run. This is needed for compatibility with non-cargo build systems that
+ // don't run the build script.
+ if NO_ATOMIC_CAS.contains(&&*target) {
+ println!("cargo:rustc-cfg=crossbeam_no_atomic_cas");
+ }
+ if NO_ATOMIC.contains(&&*target) {
+ println!("cargo:rustc-cfg=crossbeam_no_atomic");
+ println!("cargo:rustc-cfg=crossbeam_no_atomic_64");
+ } else if NO_ATOMIC_64.contains(&&*target) {
+ println!("cargo:rustc-cfg=crossbeam_no_atomic_64");
+ } else {
+ // Otherwise, assuming `"max-atomic-width" == 64` or `"max-atomic-width" == 128`.
+ }
+
+ println!("cargo:rerun-if-changed=no_atomic.rs");
}
diff --git a/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..6e516e0
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,9 @@
+{
+ "apex-available": [
+ "//apex_available:platform",
+ "com.android.virt"
+ ],
+ "device": true,
+ "run": true,
+ "tests": true
+} \ No newline at end of file
diff --git a/no_atomic.rs b/no_atomic.rs
new file mode 100644
index 0000000..90ac60a
--- /dev/null
+++ b/no_atomic.rs
@@ -0,0 +1,71 @@
+// This file is @generated by no_atomic.sh.
+// It is not intended for manual editing.
+
+const NO_ATOMIC_CAS: &[&str] = &[
+ "avr-unknown-gnu-atmega328",
+ "bpfeb-unknown-none",
+ "bpfel-unknown-none",
+ "msp430-none-elf",
+ "riscv32i-unknown-none-elf",
+ "riscv32imc-unknown-none-elf",
+ "thumbv4t-none-eabi",
+ "thumbv6m-none-eabi",
+];
+
+#[allow(dead_code)] // Only crossbeam-utils uses this.
+const NO_ATOMIC_64: &[&str] = &[
+ "arm-linux-androideabi",
+ "armebv7r-none-eabi",
+ "armebv7r-none-eabihf",
+ "armv4t-unknown-linux-gnueabi",
+ "armv5te-unknown-linux-gnueabi",
+ "armv5te-unknown-linux-musleabi",
+ "armv5te-unknown-linux-uclibceabi",
+ "armv6k-nintendo-3ds",
+ "armv7r-none-eabi",
+ "armv7r-none-eabihf",
+ "avr-unknown-gnu-atmega328",
+ "hexagon-unknown-linux-musl",
+ "m68k-unknown-linux-gnu",
+ "mips-unknown-linux-gnu",
+ "mips-unknown-linux-musl",
+ "mips-unknown-linux-uclibc",
+ "mipsel-sony-psp",
+ "mipsel-unknown-linux-gnu",
+ "mipsel-unknown-linux-musl",
+ "mipsel-unknown-linux-uclibc",
+ "mipsel-unknown-none",
+ "mipsisa32r6-unknown-linux-gnu",
+ "mipsisa32r6el-unknown-linux-gnu",
+ "msp430-none-elf",
+ "powerpc-unknown-freebsd",
+ "powerpc-unknown-linux-gnu",
+ "powerpc-unknown-linux-gnuspe",
+ "powerpc-unknown-linux-musl",
+ "powerpc-unknown-netbsd",
+ "powerpc-unknown-openbsd",
+ "powerpc-wrs-vxworks",
+ "powerpc-wrs-vxworks-spe",
+ "riscv32gc-unknown-linux-gnu",
+ "riscv32gc-unknown-linux-musl",
+ "riscv32i-unknown-none-elf",
+ "riscv32imac-unknown-none-elf",
+ "riscv32imc-esp-espidf",
+ "riscv32imc-unknown-none-elf",
+ "thumbv4t-none-eabi",
+ "thumbv6m-none-eabi",
+ "thumbv7em-none-eabi",
+ "thumbv7em-none-eabihf",
+ "thumbv7m-none-eabi",
+ "thumbv8m.base-none-eabi",
+ "thumbv8m.main-none-eabi",
+ "thumbv8m.main-none-eabihf",
+];
+
+#[allow(dead_code)] // Only crossbeam-utils uses this.
+const NO_ATOMIC: &[&str] = &[
+ "avr-unknown-gnu-atmega328",
+ "msp430-none-elf",
+ "riscv32i-unknown-none-elf",
+ "riscv32imc-unknown-none-elf",
+];
diff --git a/patches/disable_panic_tests_on_android.patch b/patches/disable_panic_tests_on_android.patch
index 49e4758..3306735 100644
--- a/patches/disable_panic_tests_on_android.patch
+++ b/patches/disable_panic_tests_on_android.patch
@@ -1,5 +1,5 @@
---- tests/sharded_lock.rs
-+++ tests/sharded_lock.rs
+--- a/tests/sharded_lock.rs
++++ b/tests/sharded_lock.rs
@@ -46,6 +46,8 @@ fn frob() {
}
@@ -63,8 +63,8 @@
fn test_get_mut_poison() {
let m = Arc::new(ShardedLock::new(NonCopy(10)));
let m2 = m.clone();
---- tests/thread.rs
-+++ tests/thread.rs
+--- a/tests/thread.rs
++++ b/tests/thread.rs
@@ -9,6 +9,8 @@ const THREADS: usize = 10;
const SMALL_STACK_SIZE: usize = 20;
diff --git a/src/atomic/atomic_cell.rs b/src/atomic/atomic_cell.rs
index ad094b2..8a49464 100644
--- a/src/atomic/atomic_cell.rs
+++ b/src/atomic/atomic_cell.rs
@@ -1,9 +1,9 @@
// Necessary for implementing atomic methods for `AtomicUnit`
#![allow(clippy::unit_arg)]
-#![allow(clippy::let_unit_value)]
use crate::primitive::sync::atomic::{self, AtomicBool};
use core::cell::UnsafeCell;
+use core::cmp;
use core::fmt;
use core::mem;
use core::sync::atomic::Ordering;
@@ -258,10 +258,44 @@ impl<T: Copy + Eq> AtomicCell<T> {
pub fn compare_exchange(&self, current: T, new: T) -> Result<T, T> {
unsafe { atomic_compare_exchange_weak(self.value.get(), 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)
+ }
}
macro_rules! impl_arithmetic {
- ($t:ty, $example:tt) => {
+ ($t:ty, fallback, $example:tt) => {
impl AtomicCell<$t> {
/// Increments the current value by `val` and returns the previous value.
///
@@ -279,10 +313,13 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_add(&self, val: $t) -> $t {
- if can_transmute::<$t, atomic::AtomicUsize>() {
- let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
- a.fetch_add(val as usize, Ordering::AcqRel) as $t
- } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
@@ -307,10 +344,13 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_sub(&self, val: $t) -> $t {
- if can_transmute::<$t, atomic::AtomicUsize>() {
- let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
- a.fetch_sub(val as usize, Ordering::AcqRel) as $t
- } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
@@ -333,10 +373,13 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_and(&self, val: $t) -> $t {
- if can_transmute::<$t, atomic::AtomicUsize>() {
- let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
- a.fetch_and(val as usize, Ordering::AcqRel) as $t
- } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
@@ -345,6 +388,35 @@ macro_rules! impl_arithmetic {
}
}
+ /// 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 {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ let old = *value;
+ *value = !(old & val);
+ old
+ }
+ }
+
/// Applies bitwise "or" to the current value and returns the previous value.
///
/// # Examples
@@ -359,10 +431,13 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_or(&self, val: $t) -> $t {
- if can_transmute::<$t, atomic::AtomicUsize>() {
- let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
- a.fetch_or(val as usize, Ordering::AcqRel) as $t
- } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
@@ -385,10 +460,13 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_xor(&self, val: $t) -> $t {
- if can_transmute::<$t, atomic::AtomicUsize>() {
- let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) };
- a.fetch_xor(val as usize, Ordering::AcqRel) as $t
- } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
@@ -396,6 +474,66 @@ macro_rules! impl_arithmetic {
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 {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ 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 {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ let old = *value;
+ *value = cmp::min(old, val);
+ old
+ }
+ }
}
};
($t:ty, $atomic:ty, $example:tt) => {
@@ -416,8 +554,24 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_add(&self, val: $t) -> $t {
- let a = unsafe { &*(self.value.get() as *const $atomic) };
- a.fetch_add(val, Ordering::AcqRel)
+ if can_transmute::<$t, $atomic>() {
+ let a = unsafe { &*(self.value.get() as *const $atomic) };
+ a.fetch_add(val, Ordering::AcqRel)
+ } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ let old = *value;
+ *value = value.wrapping_add(val);
+ old
+ }
+ }
}
/// Decrements the current value by `val` and returns the previous value.
@@ -436,8 +590,24 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_sub(&self, val: $t) -> $t {
- let a = unsafe { &*(self.value.get() as *const $atomic) };
- a.fetch_sub(val, Ordering::AcqRel)
+ if can_transmute::<$t, $atomic>() {
+ let a = unsafe { &*(self.value.get() as *const $atomic) };
+ a.fetch_sub(val, Ordering::AcqRel)
+ } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ let old = *value;
+ *value = value.wrapping_sub(val);
+ old
+ }
+ }
}
/// Applies bitwise "and" to the current value and returns the previous value.
@@ -454,8 +624,58 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_and(&self, val: $t) -> $t {
- let a = unsafe { &*(self.value.get() as *const $atomic) };
- a.fetch_and(val, Ordering::AcqRel)
+ if can_transmute::<$t, $atomic>() {
+ let a = unsafe { &*(self.value.get() as *const $atomic) };
+ a.fetch_and(val, Ordering::AcqRel)
+ } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ 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 {
+ if can_transmute::<$t, $atomic>() {
+ let a = unsafe { &*(self.value.get() as *const $atomic) };
+ a.fetch_nand(val, Ordering::AcqRel)
+ } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ let old = *value;
+ *value = !(old & val);
+ old
+ }
+ }
}
/// Applies bitwise "or" to the current value and returns the previous value.
@@ -472,8 +692,24 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_or(&self, val: $t) -> $t {
- let a = unsafe { &*(self.value.get() as *const $atomic) };
- a.fetch_or(val, Ordering::AcqRel)
+ if can_transmute::<$t, $atomic>() {
+ let a = unsafe { &*(self.value.get() as *const $atomic) };
+ a.fetch_or(val, Ordering::AcqRel)
+ } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ let old = *value;
+ *value |= val;
+ old
+ }
+ }
}
/// Applies bitwise "xor" to the current value and returns the previous value.
@@ -490,40 +726,124 @@ macro_rules! impl_arithmetic {
/// ```
#[inline]
pub fn fetch_xor(&self, val: $t) -> $t {
- let a = unsafe { &*(self.value.get() as *const $atomic) };
- a.fetch_xor(val, Ordering::AcqRel)
+ if can_transmute::<$t, $atomic>() {
+ let a = unsafe { &*(self.value.get() as *const $atomic) };
+ a.fetch_xor(val, Ordering::AcqRel)
+ } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ 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 {
+ if can_transmute::<$t, $atomic>() {
+ // TODO: Atomic*::fetch_max requires Rust 1.45.
+ self.fetch_update(|old| Some(cmp::max(old, val))).unwrap()
+ } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ 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 {
+ if can_transmute::<$t, $atomic>() {
+ // TODO: Atomic*::fetch_min requires Rust 1.45.
+ self.fetch_update(|old| Some(cmp::min(old, val))).unwrap()
+ } else {
+ #[cfg(crossbeam_loom)]
+ {
+ let _ = val;
+ unimplemented!("loom does not support non-atomic atomic ops");
+ }
+ #[cfg(not(crossbeam_loom))]
+ {
+ let _guard = lock(self.value.get() as usize).write();
+ let value = unsafe { &mut *(self.value.get()) };
+ let old = *value;
+ *value = cmp::min(old, val);
+ old
+ }
+ }
}
}
};
}
-#[cfg(has_atomic_u8)]
impl_arithmetic!(u8, atomic::AtomicU8, "let a = AtomicCell::new(7u8);");
-#[cfg(all(has_atomic_u8, not(crossbeam_loom)))]
impl_arithmetic!(i8, atomic::AtomicI8, "let a = AtomicCell::new(7i8);");
-#[cfg(has_atomic_u16)]
impl_arithmetic!(u16, atomic::AtomicU16, "let a = AtomicCell::new(7u16);");
-#[cfg(all(has_atomic_u16, not(crossbeam_loom)))]
impl_arithmetic!(i16, atomic::AtomicI16, "let a = AtomicCell::new(7i16);");
-#[cfg(has_atomic_u32)]
impl_arithmetic!(u32, atomic::AtomicU32, "let a = AtomicCell::new(7u32);");
-#[cfg(all(has_atomic_u32, not(crossbeam_loom)))]
impl_arithmetic!(i32, atomic::AtomicI32, "let a = AtomicCell::new(7i32);");
-#[cfg(has_atomic_u64)]
+#[cfg(not(crossbeam_no_atomic_64))]
impl_arithmetic!(u64, atomic::AtomicU64, "let a = AtomicCell::new(7u64);");
-#[cfg(all(has_atomic_u64, not(crossbeam_loom)))]
+#[cfg(not(crossbeam_no_atomic_64))]
impl_arithmetic!(i64, atomic::AtomicI64, "let a = AtomicCell::new(7i64);");
-#[cfg(all(has_atomic_u128, not(crossbeam_loom)))]
-impl_arithmetic!(u128, atomic::AtomicU128, "let a = AtomicCell::new(7u128);");
-#[cfg(all(has_atomic_u128, not(crossbeam_loom)))]
-impl_arithmetic!(i128, atomic::AtomicI128, "let a = AtomicCell::new(7i128);");
+#[cfg(crossbeam_no_atomic_64)]
+impl_arithmetic!(u64, fallback, "let a = AtomicCell::new(7u64);");
+#[cfg(crossbeam_no_atomic_64)]
+impl_arithmetic!(i64, fallback, "let a = AtomicCell::new(7i64);");
+// TODO: AtomicU128 is unstable
+// impl_arithmetic!(u128, atomic::AtomicU128, "let a = AtomicCell::new(7u128);");
+// impl_arithmetic!(i128, atomic::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,
atomic::AtomicUsize,
"let a = AtomicCell::new(7usize);"
);
-#[cfg(not(crossbeam_loom))]
impl_arithmetic!(
isize,
atomic::AtomicIsize,
@@ -552,6 +872,30 @@ impl AtomicCell<bool> {
a.fetch_and(val, Ordering::AcqRel)
}
+ /// 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 {
+ let a = unsafe { &*(self.value.get() as *const AtomicBool) };
+ a.fetch_nand(val, Ordering::AcqRel)
+ }
+
/// Applies logical "or" to the current value and returns the previous value.
///
/// # Examples
@@ -657,105 +1001,13 @@ fn lock(addr: usize) -> &'static SeqLock {
// 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 = 97;
-
+ #[allow(clippy::declare_interior_mutable_const)]
+ const L: SeqLock = SeqLock::new();
static LOCKS: [SeqLock; LEN] = [
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
- SeqLock::new(),
+ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
+ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
+ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L,
+ L, L, L, L, L, L, L,
];
// If the modulus is a constant number, the compiler will use crazy math to transform this into
@@ -778,7 +1030,6 @@ impl AtomicUnit {
#[inline]
fn swap(&self, _val: (), _order: Ordering) {}
- #[allow(clippy::unnecessary_wraps)] // This is intentional.
#[inline]
fn compare_exchange_weak(
&self,
@@ -807,18 +1058,14 @@ macro_rules! atomic {
($t:ty, $a:ident, $atomic_op:expr, $fallback_op:expr) => {
loop {
atomic!(@check, $t, AtomicUnit, $a, $atomic_op);
- atomic!(@check, $t, atomic::AtomicUsize, $a, $atomic_op);
- #[cfg(has_atomic_u8)]
atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op);
- #[cfg(has_atomic_u16)]
atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op);
- #[cfg(has_atomic_u32)]
atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op);
- #[cfg(has_atomic_u64)]
+ #[cfg(not(crossbeam_no_atomic_64))]
atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op);
- #[cfg(has_atomic_u128)]
- atomic!(@check, $t, atomic::AtomicU128, $a, $atomic_op);
+ // TODO: AtomicU128 is unstable
+ // atomic!(@check, $t, atomic::AtomicU128, $a, $atomic_op);
#[cfg(crossbeam_loom)]
unimplemented!("loom does not support non-atomic atomic ops");
@@ -831,17 +1078,14 @@ macro_rules! atomic {
/// Returns `true` if operations on `AtomicCell<T>` are lock-free.
const fn atomic_is_lock_free<T>() -> bool {
// HACK(taiki-e): This is equivalent to `atomic! { T, _a, true, false }`, but can be used in const fn even in Rust 1.36.
- let is_lock_free = can_transmute::<T, AtomicUnit>() | can_transmute::<T, atomic::AtomicUsize>();
- #[cfg(has_atomic_u8)]
- let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU8>();
- #[cfg(has_atomic_u16)]
- let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU16>();
- #[cfg(has_atomic_u32)]
- let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU32>();
- #[cfg(has_atomic_u64)]
+ let is_lock_free = can_transmute::<T, AtomicUnit>()
+ | can_transmute::<T, atomic::AtomicU8>()
+ | can_transmute::<T, atomic::AtomicU16>()
+ | can_transmute::<T, atomic::AtomicU32>();
+ #[cfg(not(crossbeam_no_atomic_64))]
let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU64>();
- #[cfg(has_atomic_u128)]
- let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU128>();
+ // TODO: AtomicU128 is unstable
+ // let is_lock_free = is_lock_free | can_transmute::<T, atomic::AtomicU128>();
is_lock_free
}
diff --git a/src/atomic/consume.rs b/src/atomic/consume.rs
index 0fbd93e..277b370 100644
--- a/src/atomic/consume.rs
+++ b/src/atomic/consume.rs
@@ -1,5 +1,6 @@
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
use crate::primitive::sync::atomic::compiler_fence;
+#[cfg(not(crossbeam_no_atomic))]
use core::sync::atomic::Ordering;
/// Trait which allows reading from primitive atomic types with "consume" ordering.
@@ -25,6 +26,7 @@ pub trait AtomicConsume {
fn load_consume(&self) -> Self::Val;
}
+#[cfg(not(crossbeam_no_atomic))]
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
macro_rules! impl_consume {
() => {
@@ -37,6 +39,7 @@ macro_rules! impl_consume {
};
}
+#[cfg(not(crossbeam_no_atomic))]
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
macro_rules! impl_consume {
() => {
@@ -49,12 +52,13 @@ macro_rules! impl_consume {
macro_rules! impl_atomic {
($atomic:ident, $val:ty) => {
- impl AtomicConsume for ::core::sync::atomic::$atomic {
+ #[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 {
+ impl AtomicConsume for loom::sync::atomic::$atomic {
type Val = $val;
impl_consume!();
}
@@ -63,32 +67,26 @@ macro_rules! impl_atomic {
impl_atomic!(AtomicBool, bool);
impl_atomic!(AtomicUsize, usize);
-#[cfg(not(crossbeam_loom))]
impl_atomic!(AtomicIsize, isize);
-#[cfg(has_atomic_u8)]
impl_atomic!(AtomicU8, u8);
-#[cfg(has_atomic_u8)]
impl_atomic!(AtomicI8, i8);
-#[cfg(has_atomic_u16)]
impl_atomic!(AtomicU16, u16);
-#[cfg(has_atomic_u16)]
impl_atomic!(AtomicI16, i16);
-#[cfg(has_atomic_u32)]
impl_atomic!(AtomicU32, u32);
-#[cfg(has_atomic_u32)]
impl_atomic!(AtomicI32, i32);
-#[cfg(has_atomic_u64)]
+#[cfg(not(crossbeam_no_atomic_64))]
impl_atomic!(AtomicU64, u64);
-#[cfg(has_atomic_u64)]
+#[cfg(not(crossbeam_no_atomic_64))]
impl_atomic!(AtomicI64, i64);
-impl<T> AtomicConsume for ::core::sync::atomic::AtomicPtr<T> {
+#[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> {
+impl<T> AtomicConsume for loom::sync::atomic::AtomicPtr<T> {
type Val = *mut T;
impl_consume!();
}
diff --git a/src/atomic/mod.rs b/src/atomic/mod.rs
index 874eaf2..fc713fc 100644
--- a/src/atomic/mod.rs
+++ b/src/atomic/mod.rs
@@ -3,11 +3,9 @@
//! * [`AtomicCell`], a thread-safe mutable memory location.
//! * [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering.
+#[cfg(not(crossbeam_no_atomic_cas))]
#[cfg(not(crossbeam_loom))]
-use cfg_if::cfg_if;
-
-#[cfg(not(crossbeam_loom))]
-cfg_if! {
+cfg_if::cfg_if! {
// Use "wide" sequence lock if the pointer width <= 32 for preventing its counter against wrap
// around.
//
@@ -25,8 +23,10 @@ cfg_if! {
}
}
+#[cfg(not(crossbeam_no_atomic_cas))]
mod atomic_cell;
mod consume;
+#[cfg(not(crossbeam_no_atomic_cas))]
pub use self::atomic_cell::AtomicCell;
pub use self::consume::AtomicConsume;
diff --git a/src/lib.rs b/src/lib.rs
index 880d37e..191c5a1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -38,7 +38,6 @@
unreachable_pub
)]
#![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))]
#[cfg(crossbeam_loom)]
#[allow(unused_imports)]
@@ -47,7 +46,8 @@ mod primitive {
pub(crate) mod atomic {
pub(crate) use loom::sync::atomic::spin_loop_hint;
pub(crate) use loom::sync::atomic::{
- AtomicBool, AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize,
+ AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16,
+ AtomicU32, AtomicU64, AtomicU8, AtomicUsize,
};
// FIXME: loom does not support compiler_fence at the moment.
@@ -70,15 +70,13 @@ mod primitive {
// use [`core::hint::spin_loop`] instead.
#[allow(deprecated)]
pub(crate) use core::sync::atomic::spin_loop_hint;
- pub(crate) use core::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize};
- #[cfg(has_atomic_u16)]
- pub(crate) use core::sync::atomic::{AtomicI16, AtomicU16};
- #[cfg(has_atomic_u32)]
- pub(crate) use core::sync::atomic::{AtomicI32, AtomicU32};
- #[cfg(has_atomic_u64)]
+ #[cfg(not(crossbeam_no_atomic))]
+ pub(crate) use core::sync::atomic::{
+ AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
+ AtomicU8, AtomicUsize,
+ };
+ #[cfg(not(crossbeam_no_atomic_64))]
pub(crate) use core::sync::atomic::{AtomicI64, AtomicU64};
- #[cfg(has_atomic_u8)]
- pub(crate) use core::sync::atomic::{AtomicI8, AtomicU8};
}
#[cfg(feature = "std")]
@@ -86,15 +84,6 @@ mod primitive {
}
}
-cfg_if! {
- if #[cfg(feature = "alloc")] {
- extern crate alloc;
- } else if #[cfg(feature = "std")] {
- extern crate std as alloc;
- }
-}
-
-#[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))]
pub mod atomic;
mod cache_padded;
diff --git a/src/sync/parker.rs b/src/sync/parker.rs
index aefa515..531f5a5 100644
--- a/src/sync/parker.rs
+++ b/src/sync/parker.rs
@@ -175,6 +175,7 @@ impl 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)
@@ -258,6 +259,7 @@ impl 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) as *const ()
diff --git a/src/thread.rs b/src/thread.rs
index c57d076..a59a4f5 100644
--- a/src/thread.rs
+++ b/src/thread.rs
@@ -446,7 +446,7 @@ impl<'scope, 'env> ScopedThreadBuilder<'scope, 'env> {
unsafe { mem::transmute(closure) };
// Finally, spawn the closure.
- self.builder.spawn(move || closure())?
+ self.builder.spawn(closure)?
};
let thread = handle.thread().clone();
diff --git a/tests/atomic_cell.rs b/tests/atomic_cell.rs
index 3d91d81..da7a6e1 100644
--- a/tests/atomic_cell.rs
+++ b/tests/atomic_cell.rs
@@ -1,3 +1,4 @@
+use std::mem;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
@@ -8,18 +9,47 @@ fn is_lock_free() {
struct UsizeWrap(usize);
struct U8Wrap(bool);
struct I16Wrap(i16);
-
- assert_eq!(AtomicCell::<usize>::is_lock_free(), true);
- assert_eq!(AtomicCell::<isize>::is_lock_free(), true);
- assert_eq!(AtomicCell::<UsizeWrap>::is_lock_free(), true);
-
- assert_eq!(AtomicCell::<u8>::is_lock_free(), cfg!(has_atomic_u8));
- assert_eq!(AtomicCell::<bool>::is_lock_free(), cfg!(has_atomic_u8));
- assert_eq!(AtomicCell::<U8Wrap>::is_lock_free(), cfg!(has_atomic_u8));
-
- assert_eq!(AtomicCell::<I16Wrap>::is_lock_free(), cfg!(has_atomic_u16));
-
- assert_eq!(AtomicCell::<u128>::is_lock_free(), cfg!(has_atomic_u128));
+ #[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!(not(crossbeam_no_atomic_64))
+ && cfg!(any(
+ target_pointer_width = "64",
+ target_pointer_width = "128"
+ ))
+ );
+ assert_eq!(mem::size_of::<U64Align8>(), 8);
+ assert_eq!(mem::align_of::<U64Align8>(), 8);
+ assert_eq!(
+ AtomicCell::<U64Align8>::is_lock_free(),
+ cfg!(not(crossbeam_no_atomic_64))
+ );
+
+ // AtomicU128 is unstable
+ assert!(!AtomicCell::<u128>::is_lock_free());
}
#[test]
@@ -234,3 +264,69 @@ fn const_atomic_cell_new() {
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
+#[rustversion::since(1.37)] // #[repr(align(N))] requires Rust 1.37
+#[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!(not(crossbeam_no_atomic_64))
+ );
+ let x = AtomicCell::new(Test::FieldLess);
+ assert_eq!(x.load(), Test::FieldLess);
+}
diff --git a/tests/cache_padded.rs b/tests/cache_padded.rs
index c9e7687..86e9a77 100644
--- a/tests/cache_padded.rs
+++ b/tests/cache_padded.rs
@@ -85,6 +85,7 @@ fn drops() {
assert_eq!(count.get(), 2);
}
+#[allow(clippy::clone_on_copy)] // This is intentional.
#[test]
fn clone() {
let a = CachePadded::new(17);
diff --git a/tests/sharded_lock.rs b/tests/sharded_lock.rs
index b4b8565..0718b44 100644
--- a/tests/sharded_lock.rs
+++ b/tests/sharded_lock.rs
@@ -21,6 +21,9 @@ fn smoke() {
#[test]
fn frob() {
const N: u32 = 10;
+ #[cfg(miri)]
+ const M: usize = 100;
+ #[cfg(not(miri))]
const M: usize = 1000;
let r = Arc::new(ShardedLock::new(()));
@@ -148,7 +151,7 @@ fn arc() {
fn arc_access_in_unwind() {
let arc = Arc::new(ShardedLock::new(1));
let arc2 = arc.clone();
- let _ = thread::spawn(move || -> () {
+ let _ = thread::spawn(move || {
struct Unwinder {
i: Arc<ShardedLock<isize>>,
}