diff options
author | Jeff Vander Stoep <jeffv@google.com> | 2024-01-31 18:55:35 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2024-01-31 18:55:35 +0000 |
commit | ffc4a5b6cd3f1bb444e9dba28db7679c00aa8fc7 (patch) | |
tree | 60ab42877b507a5508e7eb0bca613d8ef46ade79 | |
parent | 4eb167967de93e5ec9aeec8f0815e3daf250f992 (diff) | |
parent | 839041b30bcf84a102f662c83870a4ca6db9a6b4 (diff) | |
download | atomic-ffc4a5b6cd3f1bb444e9dba28db7679c00aa8fc7.tar.gz |
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/atomic/+/2939603
Change-Id: Idf88a8335e8856f3a2933a3bfbcdf7c1e4db1af5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | .cargo_vcs_info.json | 6 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | .travis.yml | 18 | ||||
-rw-r--r-- | Android.bp | 13 | ||||
-rw-r--r-- | Cargo.toml | 18 | ||||
-rw-r--r-- | Cargo.toml.orig | 11 | ||||
-rw-r--r-- | METADATA | 24 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | build.rs | 16 | ||||
-rw-r--r-- | src/fallback.rs | 22 | ||||
-rw-r--r-- | src/lib.rs | 128 | ||||
-rw-r--r-- | src/ops.rs | 63 |
12 files changed, 198 insertions, 131 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json new file mode 100644 index 0000000..8498c3a --- /dev/null +++ b/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "79ace14a69d8d4a45cc7f6cd06ff0cbb5849b2fd" + }, + "path_in_vcs": "" +}
\ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9d37c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..eb618e1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: rust +sudo: false + +rust: +- nightly +- beta +- stable +- 1.45.0 + +script: +- cargo build +- cargo test +- cargo doc +- if [ $TRAVIS_RUST_VERSION = nightly ]; then rustup target add aarch64-unknown-none; fi +- if [ $TRAVIS_RUST_VERSION = nightly ]; then RUSTFLAGS="-Zcrate-attr=feature(integer_atomics)" cargo check --target=aarch64-unknown-none; fi + +notifications: + email: false @@ -42,23 +42,14 @@ rust_library { host_supported: true, crate_name: "atomic", cargo_env_compat: true, - cargo_pkg_version: "0.5.1", + cargo_pkg_version: "0.6.0", srcs: ["src/lib.rs"], edition: "2018", features: [ "fallback", "std", ], - cfgs: [ - "has_atomic_i16", - "has_atomic_i32", - "has_atomic_i64", - "has_atomic_i8", - "has_atomic_u16", - "has_atomic_u32", - "has_atomic_u64", - "has_atomic_u8", - ], + rustlibs: ["libbytemuck"], apex_available: [ "//apex_available:platform", "//apex_available:anyapex", @@ -12,18 +12,26 @@ [package] edition = "2018" name = "atomic" -version = "0.5.1" +version = "0.6.0" authors = ["Amanieu d'Antras <amanieu@gmail.com>"] description = "Generic Atomic<T> wrapper type" -documentation = "https://amanieu.github.io/atomic-rs/atomic/index.html" readme = "README.md" -keywords = ["atomic", "no_std"] +keywords = [ + "atomic", + "no_std", +] license = "Apache-2.0/MIT" repository = "https://github.com/Amanieu/atomic-rs" -[build-dependencies.autocfg] -version = "1" + +[dependencies.bytemuck] +version = "1.13.1" + +[dev-dependencies.bytemuck] +version = "1.13.1" +features = ["derive"] [features] default = ["fallback"] fallback = [] +nightly = [] std = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 80b613b..60faf7c 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,10 +1,9 @@ [package] name = "atomic" -version = "0.5.1" +version = "0.6.0" edition = "2018" authors = ["Amanieu d'Antras <amanieu@gmail.com>"] description = "Generic Atomic<T> wrapper type" -documentation = "https://amanieu.github.io/atomic-rs/atomic/index.html" license = "Apache-2.0/MIT" repository = "https://github.com/Amanieu/atomic-rs" readme = "README.md" @@ -14,6 +13,10 @@ keywords = ["atomic", "no_std"] default = ["fallback"] std = [] fallback = [] +nightly = [] -[build-dependencies] -autocfg = "1" +[dependencies] +bytemuck = "1.13.1" + +[dev-dependencies] +bytemuck = { version = "1.13.1", features = ["derive"] } @@ -1,20 +1,20 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update external/rust/crates/atomic +# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md + name: "atomic" description: "Generic Atomic<T> wrapper type" third_party { - url { - type: HOMEPAGE - value: "https://crates.io/crates/atomic" - } - url { - type: ARCHIVE - value: "https://static.crates.io/crates/atomic/atomic-0.5.1.crate" - } - version: "0.5.1" - # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same. license_type: NOTICE last_upgrade_date { - year: 2023 + year: 2024 month: 1 - day: 17 + day: 31 + } + homepage: "https://crates.io/crates/atomic" + identifier { + type: "Archive" + value: "https://static.crates.io/crates/atomic/atomic-0.6.0.crate" + version: "0.6.0" } } @@ -3,13 +3,15 @@ Generic `Atomic<T>` for Rust [![Build Status](https://travis-ci.org/Amanieu/atomic-rs.svg?branch=master)](https://travis-ci.org/Amanieu/atomic-rs) [![Crates.io](https://img.shields.io/crates/v/atomic.svg)](https://crates.io/crates/atomic) -A Rust library which provides a generic `Atomic<T>` type for all `T: Copy` types, unlike the standard library which only provides a few fixed atomic types (`AtomicBool`, `AtomicIsize`, `AtomicUsize`, `AtomicPtr`). +A Rust library which provides a generic `Atomic<T>` type for all `T: NoUninit` types, unlike the standard library which only provides a few fixed atomic types (`AtomicBool`, `AtomicIsize`, `AtomicUsize`, `AtomicPtr`). The `NoUninit` bound is from the [bytemuck] crate, and indicates that a type has no internal padding bytes. You will need to derive or implement this trait for all types used with `Atomic<T>`. This library will use native atomic instructions if possible, and will otherwise fall back to a lock-based mechanism. You can use the `Atomic::<T>::is_lock_free()` function to check whether native atomic operations are supported for a given type. Note that a type must have a power-of-2 size and alignment in order to be used by native atomic instructions. This crate uses `#![no_std]` and only depends on libcore. -[Documentation](https://amanieu.github.io/atomic-rs/atomic/index.html) +[bytemuck]: https://docs.rs/bytemuck + +[Documentation](https://docs.rs/atomic) ## Usage @@ -17,7 +19,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -atomic = "0.5" +atomic = "0.6" ``` and this to your crate root: diff --git a/build.rs b/build.rs deleted file mode 100644 index 4cf4274..0000000 --- a/build.rs +++ /dev/null @@ -1,16 +0,0 @@ -fn main() { - let ac = autocfg::new(); - - for root in &["core", "std"] { - for size in &[8, 16, 32, 64, 128] { - ac.emit_expression_cfg( - &format!("{}::sync::atomic::AtomicU{}::compare_exchange", root, size), - &format!("has_atomic_u{}", size), - ); - ac.emit_expression_cfg( - &format!("{}::sync::atomic::AtomicI{}::compare_exchange", root, size), - &format!("has_atomic_i{}", size), - ); - } - } -} diff --git a/src/fallback.rs b/src/fallback.rs index 8b7e861..949bbf3 100644 --- a/src/fallback.rs +++ b/src/fallback.rs @@ -6,12 +6,13 @@ // copied, modified, or distributed except according to those terms. use core::cmp; -use core::mem; +use core::hint; use core::num::Wrapping; use core::ops; use core::ptr; -use core::slice; -use core::sync::atomic::{self, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicUsize, Ordering}; + +use bytemuck::NoUninit; // We use an AtomicUsize instead of an AtomicBool because it performs better // on architectures that don't have byte-sized atomics. @@ -28,7 +29,7 @@ impl SpinLock { .is_err() { while self.0.load(Ordering::Relaxed) != 0 { - atomic::spin_loop_hint(); + hint::spin_loop(); } } } @@ -116,15 +117,16 @@ pub unsafe fn atomic_swap<T>(dst: *mut T, val: T) -> T { } #[inline] -pub unsafe fn atomic_compare_exchange<T>(dst: *mut T, current: T, new: T) -> Result<T, T> { +pub unsafe fn atomic_compare_exchange<T: NoUninit>( + dst: *mut T, + current: T, + new: T, +) -> Result<T, T> { let _l = lock(dst as usize); let result = ptr::read(dst); // compare_exchange compares with memcmp instead of Eq - let a = slice::from_raw_parts(&result as *const _ as *const u8, mem::size_of_val(&result)); - let b = slice::from_raw_parts( - ¤t as *const _ as *const u8, - mem::size_of_val(¤t), - ); + let a = bytemuck::bytes_of(&result); + let b = bytemuck::bytes_of(¤t); if a == b { ptr::write(dst, new); Ok(result) @@ -11,10 +11,14 @@ //! threads, and are the building blocks of other concurrent types. //! //! This library defines a generic atomic wrapper type `Atomic<T>` for all -//! `T: Copy` types. +//! `T: NoUninit` types. //! Atomic types present operations that, when used correctly, synchronize //! updates between threads. //! +//! The `NoUninit` bound is from the [bytemuck] crate, and indicates that a +//! type has no internal padding bytes. You will need to derive or implement +//! this trait for all types used with `Atomic<T>`. +//! //! Each method takes an `Ordering` which represents the strength of //! the memory barrier for that operation. These orderings are the //! same as [LLVM atomic orderings][1]. @@ -29,15 +33,19 @@ //! Most atomic types may be stored in static variables, initialized using //! the `const fn` constructors. Atomic statics are often used for lazy global //! initialization. +//! +//! [bytemuck]: https://docs.rs/bytemuck #![warn(missing_docs)] #![warn(rust_2018_idioms)] #![no_std] +#![cfg_attr(feature = "nightly", feature(integer_atomics))] #[cfg(any(test, feature = "std"))] #[macro_use] extern crate std; +use core::mem::MaybeUninit; // Re-export some useful definitions from libcore pub use core::sync::atomic::{fence, Ordering}; @@ -47,6 +55,8 @@ use core::fmt; #[cfg(feature = "std")] use std::panic::RefUnwindSafe; +use bytemuck::NoUninit; + #[cfg(feature = "fallback")] mod fallback; mod ops; @@ -55,7 +65,8 @@ mod ops; /// between threads. #[repr(transparent)] pub struct Atomic<T> { - v: UnsafeCell<T>, + // The MaybeUninit is here to work around rust-lang/rust#87341. + v: UnsafeCell<MaybeUninit<T>>, } // Atomic<T> is only Sync if T is Send @@ -68,16 +79,16 @@ unsafe impl<T: Copy + Send> Sync for Atomic<T> {} // `Atomic` API does not allow doing any panic-inducing operation after writing // to the target object. #[cfg(feature = "std")] -impl<T: Copy + RefUnwindSafe> RefUnwindSafe for Atomic<T> {} +impl<T: RefUnwindSafe> RefUnwindSafe for Atomic<T> {} -impl<T: Copy + Default> Default for Atomic<T> { +impl<T: Default> Default for Atomic<T> { #[inline] fn default() -> Self { Self::new(Default::default()) } } -impl<T: Copy + fmt::Debug> fmt::Debug for Atomic<T> { +impl<T: NoUninit + fmt::Debug> fmt::Debug for Atomic<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Atomic") .field(&self.load(Ordering::SeqCst)) @@ -90,7 +101,7 @@ impl<T> Atomic<T> { #[inline] pub const fn new(v: T) -> Atomic<T> { Atomic { - v: UnsafeCell::new(v), + v: UnsafeCell::new(MaybeUninit::new(v)), } } @@ -105,14 +116,19 @@ impl<T> Atomic<T> { } } -impl<T: Copy> Atomic<T> { +impl<T: NoUninit> Atomic<T> { + #[inline] + fn inner_ptr(&self) -> *mut T { + self.v.get() as *mut T + } + /// Returns a mutable reference to the underlying type. /// /// This is safe because the mutable reference guarantees that no other threads are /// concurrently accessing the atomic data. #[inline] pub fn get_mut(&mut self) -> &mut T { - unsafe { &mut *self.v.get() } + unsafe { &mut *self.inner_ptr() } } /// Consumes the atomic and returns the contained value. @@ -121,7 +137,7 @@ impl<T: Copy> Atomic<T> { /// concurrently accessing the atomic data. #[inline] pub fn into_inner(self) -> T { - self.v.into_inner() + unsafe { self.v.into_inner().assume_init() } } /// Loads a value from the `Atomic`. @@ -134,7 +150,7 @@ impl<T: Copy> Atomic<T> { /// Panics if `order` is `Release` or `AcqRel`. #[inline] pub fn load(&self, order: Ordering) -> T { - unsafe { ops::atomic_load(self.v.get(), order) } + unsafe { ops::atomic_load(self.inner_ptr(), order) } } /// Stores a value into the `Atomic`. @@ -148,7 +164,7 @@ impl<T: Copy> Atomic<T> { #[inline] pub fn store(&self, val: T, order: Ordering) { unsafe { - ops::atomic_store(self.v.get(), val, order); + ops::atomic_store(self.inner_ptr(), val, order); } } @@ -158,7 +174,7 @@ impl<T: Copy> Atomic<T> { /// of this operation. #[inline] pub fn swap(&self, val: T, order: Ordering) -> T { - unsafe { ops::atomic_swap(self.v.get(), val, order) } + unsafe { ops::atomic_swap(self.inner_ptr(), val, order) } } /// Stores a value into the `Atomic` if the current value is the same as the @@ -181,7 +197,7 @@ impl<T: Copy> Atomic<T> { success: Ordering, failure: Ordering, ) -> Result<T, T> { - unsafe { ops::atomic_compare_exchange(self.v.get(), current, new, success, failure) } + unsafe { ops::atomic_compare_exchange(self.inner_ptr(), current, new, success, failure) } } /// Stores a value into the `Atomic` if the current value is the same as the @@ -206,7 +222,9 @@ impl<T: Copy> Atomic<T> { success: Ordering, failure: Ordering, ) -> Result<T, T> { - unsafe { ops::atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) } + unsafe { + ops::atomic_compare_exchange_weak(self.inner_ptr(), current, new, success, failure) + } } /// Fetches the value, and applies a function to it that returns an optional @@ -275,7 +293,7 @@ impl Atomic<bool> { /// Returns the previous value. #[inline] pub fn fetch_and(&self, val: bool, order: Ordering) -> bool { - unsafe { ops::atomic_and(self.v.get(), val, order) } + unsafe { ops::atomic_and(self.inner_ptr(), val, order) } } /// Logical "or" with a boolean value. @@ -286,7 +304,7 @@ impl Atomic<bool> { /// Returns the previous value. #[inline] pub fn fetch_or(&self, val: bool, order: Ordering) -> bool { - unsafe { ops::atomic_or(self.v.get(), val, order) } + unsafe { ops::atomic_or(self.inner_ptr(), val, order) } } /// Logical "xor" with a boolean value. @@ -297,7 +315,7 @@ impl Atomic<bool> { /// Returns the previous value. #[inline] pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { - unsafe { ops::atomic_xor(self.v.get(), val, order) } + unsafe { ops::atomic_xor(self.inner_ptr(), val, order) } } } @@ -307,31 +325,31 @@ macro_rules! atomic_ops_common { /// Add to the current value, returning the previous value. #[inline] pub fn fetch_add(&self, val: $t, order: Ordering) -> $t { - unsafe { ops::atomic_add(self.v.get(), val, order) } + unsafe { ops::atomic_add(self.inner_ptr(), val, order) } } /// Subtract from the current value, returning the previous value. #[inline] pub fn fetch_sub(&self, val: $t, order: Ordering) -> $t { - unsafe { ops::atomic_sub(self.v.get(), val, order) } + unsafe { ops::atomic_sub(self.inner_ptr(), val, order) } } /// Bitwise and with the current value, returning the previous value. #[inline] pub fn fetch_and(&self, val: $t, order: Ordering) -> $t { - unsafe { ops::atomic_and(self.v.get(), val, order) } + unsafe { ops::atomic_and(self.inner_ptr(), val, order) } } /// Bitwise or with the current value, returning the previous value. #[inline] pub fn fetch_or(&self, val: $t, order: Ordering) -> $t { - unsafe { ops::atomic_or(self.v.get(), val, order) } + unsafe { ops::atomic_or(self.inner_ptr(), val, order) } } /// Bitwise xor with the current value, returning the previous value. #[inline] pub fn fetch_xor(&self, val: $t, order: Ordering) -> $t { - unsafe { ops::atomic_xor(self.v.get(), val, order) } + unsafe { ops::atomic_xor(self.inner_ptr(), val, order) } } } )*); @@ -344,13 +362,13 @@ macro_rules! atomic_ops_signed { /// Minimum with the current value. #[inline] pub fn fetch_min(&self, val: $t, order: Ordering) -> $t { - unsafe { ops::atomic_min(self.v.get(), val, order) } + unsafe { ops::atomic_min(self.inner_ptr(), val, order) } } /// Maximum with the current value. #[inline] pub fn fetch_max(&self, val: $t, order: Ordering) -> $t { - unsafe { ops::atomic_max(self.v.get(), val, order) } + unsafe { ops::atomic_max(self.inner_ptr(), val, order) } } } )* @@ -364,13 +382,13 @@ macro_rules! atomic_ops_unsigned { /// Minimum with the current value. #[inline] pub fn fetch_min(&self, val: $t, order: Ordering) -> $t { - unsafe { ops::atomic_umin(self.v.get(), val, order) } + unsafe { ops::atomic_umin(self.inner_ptr(), val, order) } } /// Maximum with the current value. #[inline] pub fn fetch_max(&self, val: $t, order: Ordering) -> $t { - unsafe { ops::atomic_umax(self.v.get(), val, order) } + unsafe { ops::atomic_umax(self.inner_ptr(), val, order) } } } )* @@ -382,19 +400,26 @@ atomic_ops_unsigned! { u8 u16 u32 u64 usize u128 } #[cfg(test)] mod tests { use super::{Atomic, Ordering::*}; + use bytemuck::NoUninit; use core::mem; - #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)] + #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, NoUninit)] + #[repr(C)] struct Foo(u8, u8); - #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)] + #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, NoUninit)] + #[repr(C)] struct Bar(u64, u64); - #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)] + #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, NoUninit)] + #[repr(C)] struct Quux(u32); #[test] fn atomic_bool() { let a = Atomic::new(false); - assert_eq!(Atomic::<bool>::is_lock_free(), cfg!(has_atomic_u8),); + assert_eq!( + Atomic::<bool>::is_lock_free(), + cfg!(target_has_atomic = "8"), + ); assert_eq!(format!("{:?}", a), "Atomic(false)"); assert_eq!(a.load(SeqCst), false); a.store(true, SeqCst); @@ -410,7 +435,7 @@ mod tests { #[test] fn atomic_i8() { let a = Atomic::new(0i8); - assert_eq!(Atomic::<i8>::is_lock_free(), cfg!(has_atomic_u8)); + assert_eq!(Atomic::<i8>::is_lock_free(), cfg!(target_has_atomic = "8")); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); a.store(1, SeqCst); @@ -431,7 +456,10 @@ mod tests { #[test] fn atomic_i16() { let a = Atomic::new(0i16); - assert_eq!(Atomic::<i16>::is_lock_free(), cfg!(has_atomic_u16)); + assert_eq!( + Atomic::<i16>::is_lock_free(), + cfg!(target_has_atomic = "16") + ); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); a.store(1, SeqCst); @@ -451,7 +479,10 @@ mod tests { #[test] fn atomic_i32() { let a = Atomic::new(0i32); - assert_eq!(Atomic::<i32>::is_lock_free(), cfg!(has_atomic_u32)); + assert_eq!( + Atomic::<i32>::is_lock_free(), + cfg!(target_has_atomic = "32") + ); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); a.store(1, SeqCst); @@ -473,7 +504,7 @@ mod tests { let a = Atomic::new(0i64); assert_eq!( Atomic::<i64>::is_lock_free(), - cfg!(has_atomic_u64) && mem::align_of::<i64>() == 8 + cfg!(target_has_atomic = "64") && mem::align_of::<i64>() == 8 ); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); @@ -494,7 +525,10 @@ mod tests { #[test] fn atomic_i128() { let a = Atomic::new(0i128); - assert_eq!(Atomic::<i128>::is_lock_free(), cfg!(has_atomic_u128)); + assert_eq!( + Atomic::<i128>::is_lock_free(), + cfg!(feature = "nightly") & cfg!(target_has_atomic = "128") + ); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); a.store(1, SeqCst); @@ -533,7 +567,7 @@ mod tests { #[test] fn atomic_u8() { let a = Atomic::new(0u8); - assert_eq!(Atomic::<u8>::is_lock_free(), cfg!(has_atomic_u8)); + assert_eq!(Atomic::<u8>::is_lock_free(), cfg!(target_has_atomic = "8")); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); a.store(1, SeqCst); @@ -553,7 +587,10 @@ mod tests { #[test] fn atomic_u16() { let a = Atomic::new(0u16); - assert_eq!(Atomic::<u16>::is_lock_free(), cfg!(has_atomic_u16)); + assert_eq!( + Atomic::<u16>::is_lock_free(), + cfg!(target_has_atomic = "16") + ); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); a.store(1, SeqCst); @@ -573,7 +610,10 @@ mod tests { #[test] fn atomic_u32() { let a = Atomic::new(0u32); - assert_eq!(Atomic::<u32>::is_lock_free(), cfg!(has_atomic_u32)); + assert_eq!( + Atomic::<u32>::is_lock_free(), + cfg!(target_has_atomic = "32") + ); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); a.store(1, SeqCst); @@ -595,7 +635,7 @@ mod tests { let a = Atomic::new(0u64); assert_eq!( Atomic::<u64>::is_lock_free(), - cfg!(has_atomic_u64) && mem::align_of::<u64>() == 8 + cfg!(target_has_atomic = "64") && mem::align_of::<u64>() == 8 ); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); @@ -616,7 +656,10 @@ mod tests { #[test] fn atomic_u128() { let a = Atomic::new(0u128); - assert_eq!(Atomic::<u128>::is_lock_free(), cfg!(has_atomic_u128)); + assert_eq!( + Atomic::<u128>::is_lock_free(), + cfg!(feature = "nightly") & cfg!(target_has_atomic = "128") + ); assert_eq!(format!("{:?}", a), "Atomic(0)"); assert_eq!(a.load(SeqCst), 0); a.store(1, SeqCst); @@ -693,7 +736,10 @@ mod tests { #[test] fn atomic_quxx() { let a = Atomic::default(); - assert_eq!(Atomic::<Quux>::is_lock_free(), cfg!(has_atomic_u32)); + assert_eq!( + Atomic::<Quux>::is_lock_free(), + cfg!(target_has_atomic = "32") + ); assert_eq!(format!("{:?}", a), "Atomic(Quux(0))"); assert_eq!(a.load(SeqCst), Quux(0)); a.store(Quux(1), SeqCst); @@ -5,6 +5,8 @@ // http://opensource.org/licenses/MIT>, at your option. This file may not be // copied, modified, or distributed except according to those terms. +use bytemuck::NoUninit; + #[cfg(feature = "fallback")] use crate::fallback; use core::cmp; @@ -16,31 +18,31 @@ use core::sync::atomic::Ordering; macro_rules! match_atomic { ($type:ident, $atomic:ident, $impl:expr, $fallback_impl:expr) => { match mem::size_of::<$type>() { - #[cfg(has_atomic_u8)] + #[cfg(target_has_atomic = "8")] 1 if mem::align_of::<$type>() >= 1 => { type $atomic = core::sync::atomic::AtomicU8; $impl } - #[cfg(has_atomic_u16)] + #[cfg(target_has_atomic = "16")] 2 if mem::align_of::<$type>() >= 2 => { type $atomic = core::sync::atomic::AtomicU16; $impl } - #[cfg(has_atomic_u32)] + #[cfg(target_has_atomic = "32")] 4 if mem::align_of::<$type>() >= 4 => { type $atomic = core::sync::atomic::AtomicU32; $impl } - #[cfg(has_atomic_u64)] + #[cfg(target_has_atomic = "64")] 8 if mem::align_of::<$type>() >= 8 => { type $atomic = core::sync::atomic::AtomicU64; $impl } - #[cfg(has_atomic_u128)] + #[cfg(all(feature = "nightly", target_has_atomic = "128"))] 16 if mem::align_of::<$type>() >= 16 => { type $atomic = core::sync::atomic::AtomicU128; @@ -57,31 +59,31 @@ macro_rules! match_atomic { macro_rules! match_signed_atomic { ($type:ident, $atomic:ident, $impl:expr, $fallback_impl:expr) => { match mem::size_of::<$type>() { - #[cfg(has_atomic_i8)] + #[cfg(target_has_atomic = "8")] 1 if mem::align_of::<$type>() >= 1 => { type $atomic = core::sync::atomic::AtomicI8; $impl } - #[cfg(has_atomic_i16)] + #[cfg(target_has_atomic = "16")] 2 if mem::align_of::<$type>() >= 2 => { type $atomic = core::sync::atomic::AtomicI16; $impl } - #[cfg(has_atomic_i32)] + #[cfg(target_has_atomic = "32")] 4 if mem::align_of::<$type>() >= 4 => { type $atomic = core::sync::atomic::AtomicI32; $impl } - #[cfg(has_atomic_i64)] + #[cfg(target_has_atomic = "64")] 8 if mem::align_of::<$type>() >= 8 => { type $atomic = core::sync::atomic::AtomicI64; $impl } - #[cfg(has_atomic_u128)] + #[cfg(all(feature = "nightly", target_has_atomic = "128"))] 16 if mem::align_of::<$type>() >= 16 => { type $atomic = core::sync::atomic::AtomicI128; @@ -100,15 +102,18 @@ pub const fn atomic_is_lock_free<T>() -> bool { let size = mem::size_of::<T>(); let align = mem::align_of::<T>(); - (cfg!(has_atomic_u8) & (size == 1) & (align >= 1)) - | (cfg!(has_atomic_u16) & (size == 2) & (align >= 2)) - | (cfg!(has_atomic_u32) & (size == 4) & (align >= 4)) - | (cfg!(has_atomic_u64) & (size == 8) & (align >= 8)) - | (cfg!(has_atomic_u128) & (size == 16) & (align >= 16)) + (cfg!(target_has_atomic = "8") & (size == 1) & (align >= 1)) + | (cfg!(target_has_atomic = "16") & (size == 2) & (align >= 2)) + | (cfg!(target_has_atomic = "32") & (size == 4) & (align >= 4)) + | (cfg!(target_has_atomic = "64") & (size == 8) & (align >= 8)) + | (cfg!(feature = "nightly") + & cfg!(target_has_atomic = "128") + & (size == 16) + & (align >= 16)) } #[inline] -pub unsafe fn atomic_load<T>(dst: *mut T, order: Ordering) -> T { +pub unsafe fn atomic_load<T: NoUninit>(dst: *mut T, order: Ordering) -> T { match_atomic!( T, A, @@ -118,7 +123,7 @@ pub unsafe fn atomic_load<T>(dst: *mut T, order: Ordering) -> T { } #[inline] -pub unsafe fn atomic_store<T>(dst: *mut T, val: T, order: Ordering) { +pub unsafe fn atomic_store<T: NoUninit>(dst: *mut T, val: T, order: Ordering) { match_atomic!( T, A, @@ -128,7 +133,7 @@ pub unsafe fn atomic_store<T>(dst: *mut T, val: T, order: Ordering) { } #[inline] -pub unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T { +pub unsafe fn atomic_swap<T: NoUninit>(dst: *mut T, val: T, order: Ordering) -> T { match_atomic!( T, A, @@ -146,7 +151,7 @@ unsafe fn map_result<T, U>(r: Result<T, T>) -> Result<U, U> { } #[inline] -pub unsafe fn atomic_compare_exchange<T>( +pub unsafe fn atomic_compare_exchange<T: NoUninit>( dst: *mut T, current: T, new: T, @@ -167,7 +172,7 @@ pub unsafe fn atomic_compare_exchange<T>( } #[inline] -pub unsafe fn atomic_compare_exchange_weak<T>( +pub unsafe fn atomic_compare_exchange_weak<T: NoUninit>( dst: *mut T, current: T, new: T, @@ -188,7 +193,7 @@ pub unsafe fn atomic_compare_exchange_weak<T>( } #[inline] -pub unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T +pub unsafe fn atomic_add<T: NoUninit>(dst: *mut T, val: T, order: Ordering) -> T where Wrapping<T>: ops::Add<Output = Wrapping<T>>, { @@ -201,7 +206,7 @@ where } #[inline] -pub unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T +pub unsafe fn atomic_sub<T: NoUninit>(dst: *mut T, val: T, order: Ordering) -> T where Wrapping<T>: ops::Sub<Output = Wrapping<T>>, { @@ -214,7 +219,7 @@ where } #[inline] -pub unsafe fn atomic_and<T: Copy + ops::BitAnd<Output = T>>( +pub unsafe fn atomic_and<T: NoUninit + ops::BitAnd<Output = T>>( dst: *mut T, val: T, order: Ordering, @@ -228,7 +233,7 @@ pub unsafe fn atomic_and<T: Copy + ops::BitAnd<Output = T>>( } #[inline] -pub unsafe fn atomic_or<T: Copy + ops::BitOr<Output = T>>( +pub unsafe fn atomic_or<T: NoUninit + ops::BitOr<Output = T>>( dst: *mut T, val: T, order: Ordering, @@ -242,7 +247,7 @@ pub unsafe fn atomic_or<T: Copy + ops::BitOr<Output = T>>( } #[inline] -pub unsafe fn atomic_xor<T: Copy + ops::BitXor<Output = T>>( +pub unsafe fn atomic_xor<T: NoUninit + ops::BitXor<Output = T>>( dst: *mut T, val: T, order: Ordering, @@ -256,7 +261,7 @@ pub unsafe fn atomic_xor<T: Copy + ops::BitXor<Output = T>>( } #[inline] -pub unsafe fn atomic_min<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T { +pub unsafe fn atomic_min<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T { match_signed_atomic!( T, A, @@ -266,7 +271,7 @@ pub unsafe fn atomic_min<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Orderin } #[inline] -pub unsafe fn atomic_max<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T { +pub unsafe fn atomic_max<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T { match_signed_atomic!( T, A, @@ -276,7 +281,7 @@ pub unsafe fn atomic_max<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Orderin } #[inline] -pub unsafe fn atomic_umin<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T { +pub unsafe fn atomic_umin<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T { match_atomic!( T, A, @@ -286,7 +291,7 @@ pub unsafe fn atomic_umin<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Orderi } #[inline] -pub unsafe fn atomic_umax<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T { +pub unsafe fn atomic_umax<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T { match_atomic!( T, A, |