From e65783dac936ab87dac0cf9f02105e2afafdc8bd Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Wed, 18 Sep 2024 23:05:16 -0400 Subject: [PATCH] add generic Atomic type alias --- library/core/src/sync/atomic.rs | 94 +++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index b06a3bd4487d3..88989e7cc60f2 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -227,6 +227,100 @@ use crate::cell::UnsafeCell; use crate::hint::spin_loop; use crate::{fmt, intrinsics}; +trait Sealed {} + +/// A marker trait for primitive types which can be modified atomically. +/// +/// This is an implementation detail for [Atomic]\ which may disappear or be replaced at any time. +/// +/// # Safety +/// +/// Types implementing this trait must be primitives that can be modified atomically. +/// +/// The associated `Self::AtomicInner` type must have the same size and bit validity as `Self`, +/// but may have a higher alignment requirement, so the following `transmute`s are sound: +/// +/// - `&mut Self::AtomicInner` as `&mut Self` +/// - `Self` as `Self::AtomicInner` or the reverse +#[unstable( + feature = "atomic_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +#[allow(private_bounds)] +pub unsafe trait AtomicPrimitive: Sized + Copy + Sealed { + #[doc(hidden)] + type AtomicInner: Sized; +} + +macro impl_atomic_primitive( + $Atom:ident $(<$T:ident>)? ($Primitive:ty), + size($size:literal), + align($align:literal) $(,)? +) { + impl $(<$T>)? Sealed for $Primitive {} + + #[unstable( + feature = "atomic_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + #[cfg(target_has_atomic_load_store = $size)] + unsafe impl $(<$T>)? AtomicPrimitive for $Primitive { + type AtomicInner = $Atom $(<$T>)?; + } +} + +impl_atomic_primitive!(AtomicBool(bool), size("8"), align(1)); +impl_atomic_primitive!(AtomicI8(i8), size("8"), align(1)); +impl_atomic_primitive!(AtomicU8(u8), size("8"), align(1)); +impl_atomic_primitive!(AtomicI16(i16), size("16"), align(2)); +impl_atomic_primitive!(AtomicU16(u16), size("16"), align(2)); +impl_atomic_primitive!(AtomicI32(i32), size("32"), align(4)); +impl_atomic_primitive!(AtomicU32(u32), size("32"), align(4)); +impl_atomic_primitive!(AtomicI64(i64), size("64"), align(8)); +impl_atomic_primitive!(AtomicU64(u64), size("64"), align(8)); +impl_atomic_primitive!(AtomicI128(i128), size("128"), align(16)); +impl_atomic_primitive!(AtomicU128(u128), size("128"), align(16)); + +#[cfg(target_pointer_width = "16")] +impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(2)); +#[cfg(target_pointer_width = "32")] +impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(4)); +#[cfg(target_pointer_width = "64")] +impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(8)); + +#[cfg(target_pointer_width = "16")] +impl_atomic_primitive!(AtomicUsize(usize), size("ptr"), align(2)); +#[cfg(target_pointer_width = "32")] +impl_atomic_primitive!(AtomicUsize(usize), size("ptr"), align(4)); +#[cfg(target_pointer_width = "64")] +impl_atomic_primitive!(AtomicUsize(usize), size("ptr"), align(8)); + +#[cfg(target_pointer_width = "16")] +impl_atomic_primitive!(AtomicPtr(*mut T), size("ptr"), align(2)); +#[cfg(target_pointer_width = "32")] +impl_atomic_primitive!(AtomicPtr(*mut T), size("ptr"), align(4)); +#[cfg(target_pointer_width = "64")] +impl_atomic_primitive!(AtomicPtr(*mut T), size("ptr"), align(8)); + +/// A memory location which can be safely modified from multiple threads. +/// +/// This has the same size and bit validity as the underlying type `T`. However, +/// the alignment of this type is always equal to its size, even on targets where +/// `T` has alignment less than its size. +/// +/// For more about the differences between atomic types and non-atomic types as +/// well as information about the portability of this type, please see the +/// [module-level documentation]. +/// +/// **Note:** This type is only available on platforms that support atomic loads +/// and stores of `T`. +/// +/// [module-level documentation]: crate::sync::atomic +#[unstable(feature = "generic_atomic", issue = "130539")] +pub type Atomic = ::AtomicInner; + // Some architectures don't have byte-sized atomics, which results in LLVM // emulating them using a LL/SC loop. However for AtomicBool we can take // advantage of the fact that it only ever contains 0 or 1 and use atomic OR/AND