diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-03-04 02:04:42 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-03-04 02:04:42 +0000 |
commit | d201e11ea9ac2722786cd62f5686a862639ddca3 (patch) | |
tree | 9920d6c25aa95c5ccff5cf61965f1a8d34973523 | |
parent | 59787aa13af814ec90d9850b5952849b4032ed14 (diff) | |
parent | 19b01ce760bb8a81c73d5ffabd3af621ee8dcffe (diff) | |
download | crossbeam-utils-android-platform-13.0.0_r21.tar.gz |
Snap for 8249732 from 19b01ce760bb8a81c73d5ffabd3af621ee8dcffe to tm-releaseandroid-vts-13.0_r8android-vts-13.0_r7android-vts-13.0_r6android-vts-13.0_r5android-vts-13.0_r4android-vts-13.0_r3android-vts-13.0_r2android-vts-13.0_r1android-security-13.0.0_r9android-security-13.0.0_r8android-security-13.0.0_r7android-security-13.0.0_r6android-security-13.0.0_r5android-security-13.0.0_r4android-security-13.0.0_r3android-security-13.0.0_r2android-security-13.0.0_r19android-security-13.0.0_r18android-security-13.0.0_r17android-security-13.0.0_r16android-security-13.0.0_r15android-security-13.0.0_r14android-security-13.0.0_r13android-security-13.0.0_r12android-security-13.0.0_r11android-security-13.0.0_r10android-security-13.0.0_r1android-platform-13.0.0_r9android-platform-13.0.0_r8android-platform-13.0.0_r7android-platform-13.0.0_r6android-platform-13.0.0_r5android-platform-13.0.0_r4android-platform-13.0.0_r3android-platform-13.0.0_r21android-platform-13.0.0_r20android-platform-13.0.0_r2android-platform-13.0.0_r19android-platform-13.0.0_r18android-platform-13.0.0_r17android-platform-13.0.0_r16android-platform-13.0.0_r15android-platform-13.0.0_r14android-platform-13.0.0_r13android-platform-13.0.0_r12android-platform-13.0.0_r11android-platform-13.0.0_r10android-platform-13.0.0_r1android-cts-13.0_r8android-cts-13.0_r7android-cts-13.0_r6android-cts-13.0_r5android-cts-13.0_r4android-cts-13.0_r3android-cts-13.0_r2android-cts-13.0_r1android-13.0.0_r8android-13.0.0_r7android-13.0.0_r6android-13.0.0_r5android-13.0.0_r4android-13.0.0_r31android-13.0.0_r3android-13.0.0_r2android-13.0.0_r12android-13.0.0_r1android13-tests-releaseandroid13-security-releaseandroid13-s3-releaseandroid13-s2-releaseandroid13-s1-releaseandroid13-releaseandroid13-platform-releaseandroid13-gsi
Change-Id: Id13775b1052b3725f5daab0587c846e8aecd4aa3
-rw-r--r-- | .cargo_vcs_info.json | 7 | ||||
-rw-r--r-- | Android.bp | 8 | ||||
-rw-r--r-- | CHANGELOG.md | 15 | ||||
-rw-r--r-- | Cargo.toml | 34 | ||||
-rw-r--r-- | Cargo.toml.orig | 6 | ||||
-rw-r--r-- | METADATA | 10 | ||||
-rw-r--r-- | build.rs | 29 | ||||
-rw-r--r-- | no_atomic.rs | 22 | ||||
-rw-r--r-- | src/atomic/atomic_cell.rs | 489 | ||||
-rw-r--r-- | src/sync/parker.rs | 2 | ||||
-rw-r--r-- | src/thread.rs | 2 | ||||
-rw-r--r-- | tests/atomic_cell.rs | 66 | ||||
-rw-r--r-- | tests/sharded_lock.rs | 3 |
13 files changed, 524 insertions, 169 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 1f53d5d..0d40a83 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "6d4cdd4daf9a897deef6cde9569f2fbf12c29bc5" - } -} + "sha1": "2988f873f87d2263a7fd2b9465fb9c28f43a6490" + }, + "path_in_vcs": "crossbeam-utils" +}
\ No newline at end of file @@ -44,7 +44,7 @@ rust_test { host_supported: true, crate_name: "crossbeam_utils", cargo_env_compat: true, - cargo_pkg_version: "0.8.5", + cargo_pkg_version: "0.8.7", srcs: ["src/lib.rs"], test_suites: ["general-tests"], auto_gen_config: true, @@ -62,13 +62,14 @@ rust_test { "liblazy_static", "librand", ], + proc_macros: ["librustversion"], } rust_defaults { name: "crossbeam-utils_test_defaults", crate_name: "crossbeam_utils", cargo_env_compat: true, - cargo_pkg_version: "0.8.5", + cargo_pkg_version: "0.8.7", test_suites: ["general-tests"], auto_gen_config: true, edition: "2018", @@ -83,6 +84,7 @@ rust_defaults { "liblazy_static", "librand", ], + proc_macros: ["librustversion"], } rust_test { @@ -150,7 +152,7 @@ rust_library { host_supported: true, crate_name: "crossbeam_utils", cargo_env_compat: true, - cargo_pkg_version: "0.8.5", + cargo_pkg_version: "0.8.7", srcs: ["src/lib.rs"], edition: "2018", features: [ diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c485ef..98088c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,18 @@ +# 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) +- Add `AtomicCell::fetch_update`. (#704) +- Support targets that do not have atomic CAS on stable Rust. (#698) # Version 0.8.4 @@ -3,38 +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.5" -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" +[dev-dependencies.rustversion] +version = "1" + [features] default = ["std"] nightly = [] std = ["lazy_static"] + [target."cfg(crossbeam_loom)".dependencies.loom] version = "0.5" optional = true diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 16488cb..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.5" -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"] @@ -44,3 +43,4 @@ loom = { version = "0.5", optional = true } [dev-dependencies] rand = "0.8" +rustversion = "1" @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/crossbeam-utils/crossbeam-utils-0.8.5.crate" + value: "https://static.crates.io/crates/crossbeam-utils/crossbeam-utils-0.8.7.crate" } - version: "0.8.5" + version: "0.8.7" license_type: NOTICE last_upgrade_date { - year: 2021 - month: 6 - day: 21 + year: 2022 + month: 3 + day: 1 } } @@ -1,12 +1,33 @@ +// 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 target = match env::var("TARGET") { Ok(target) => target, @@ -33,7 +54,7 @@ fn main() { } else if NO_ATOMIC_64.contains(&&*target) { println!("cargo:rustc-cfg=crossbeam_no_atomic_64"); } else { - // Otherwise, assuming `"max-atomic-width" == 64`. + // Otherwise, assuming `"max-atomic-width" == 64` or `"max-atomic-width" == 128`. } println!("cargo:rerun-if-changed=no_atomic.rs"); diff --git a/no_atomic.rs b/no_atomic.rs index 522b3b8..90ac60a 100644 --- a/no_atomic.rs +++ b/no_atomic.rs @@ -3,13 +3,16 @@ 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)] + +#[allow(dead_code)] // Only crossbeam-utils uses this. const NO_ATOMIC_64: &[&str] = &[ "arm-linux-androideabi", "armebv7r-none-eabi", @@ -18,18 +21,24 @@ const NO_ATOMIC_64: &[&str] = &[ "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", @@ -39,18 +48,21 @@ const NO_ATOMIC_64: &[&str] = &[ "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", - "mipsel-sony-psp", - "thumbv4t-none-eabi", - "thumbv6m-none-eabi", ]; -#[allow(dead_code)] + +#[allow(dead_code)] // Only crossbeam-utils uses this. const NO_ATOMIC: &[&str] = &[ "avr-unknown-gnu-atmega328", "msp430-none-elf", diff --git a/src/atomic/atomic_cell.rs b/src/atomic/atomic_cell.rs index 1a1c464..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; @@ -295,7 +295,7 @@ impl<T: Copy + Eq> AtomicCell<T> { } 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. /// @@ -313,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; @@ -341,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; @@ -367,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; @@ -379,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 @@ -393,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; @@ -419,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; @@ -430,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) => { @@ -450,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. @@ -470,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. @@ -488,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. @@ -506,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. @@ -524,8 +726,94 @@ 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 + } + } } } }; @@ -541,9 +829,15 @@ impl_arithmetic!(i32, atomic::AtomicI32, "let a = AtomicCell::new(7i32);"); impl_arithmetic!(u64, atomic::AtomicU64, "let a = AtomicCell::new(7u64);"); #[cfg(not(crossbeam_no_atomic_64))] impl_arithmetic!(i64, atomic::AtomicI64, "let a = AtomicCell::new(7i64);"); +#[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, @@ -578,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 @@ -683,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 @@ -804,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, @@ -833,7 +1058,6 @@ 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); atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op); atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op); @@ -855,7 +1079,6 @@ macro_rules! atomic { 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>() | can_transmute::<T, atomic::AtomicU8>() | can_transmute::<T, atomic::AtomicU16>() | can_transmute::<T, atomic::AtomicU32>(); 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 28208ee..da7a6e1 100644 --- a/tests/atomic_cell.rs +++ b/tests/atomic_cell.rs @@ -264,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/sharded_lock.rs b/tests/sharded_lock.rs index d999008..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(())); |