Skip to content

Commit

Permalink
Rollup merge of rust-lang#130543 - CAD97:generic-atomic, r=Noratrieb
Browse files Browse the repository at this point in the history
Create `Atomic<T>` type alias

and use it in core/alloc/std where possible, ignoring test files for now.

This is step one, creating the alias from `Atomic<T>` to `AtomicT`. The next step of flipping this and aliasing `AtomicT` to `Atomic<T>` will have a bigger impact, since `AtomicT` imports can be dropped once `Atomic::new` is a usable name.

First commit is the true change. Second commit is mostly mechanical replacement of `AtomicT` type names with `Atomic<T>`.

See [how this was done for `NonZero`](rust-lang#120257) for the rough blueprint I'm following.

- ACP: rust-lang/libs-team#443 (comment)
- Tracking issue: rust-lang#130539
  • Loading branch information
workingjubilee committed Sep 19, 2024
2 parents cfa2951 + fbf092e commit 8fab921
Show file tree
Hide file tree
Showing 75 changed files with 340 additions and 240 deletions.
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
#![feature(extend_one_unchecked)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(generic_atomic)]
#![feature(hasher_prefixfree_extras)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
Expand Down
10 changes: 5 additions & 5 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use core::pin::{Pin, PinCoerceUnsized};
use core::ptr::{self, NonNull};
#[cfg(not(no_global_oom_handling))]
use core::slice::from_raw_parts_mut;
use core::sync::atomic;
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
use core::sync::atomic::{self, Atomic};
use core::{borrow, fmt, hint};

#[cfg(not(no_global_oom_handling))]
Expand Down Expand Up @@ -346,12 +346,12 @@ impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> {
// inner types.
#[repr(C)]
struct ArcInner<T: ?Sized> {
strong: atomic::AtomicUsize,
strong: Atomic<usize>,

// the value usize::MAX acts as a sentinel for temporarily "locking" the
// ability to upgrade weak pointers or downgrade strong ones; this is used
// to avoid races in `make_mut` and `get_mut`.
weak: atomic::AtomicUsize,
weak: Atomic<usize>,

data: T,
}
Expand Down Expand Up @@ -2706,8 +2706,8 @@ impl<T, A: Allocator> Weak<T, A> {
/// Helper type to allow accessing the reference counts without
/// making any assertions about the data field.
struct WeakInner<'a> {
weak: &'a atomic::AtomicUsize,
strong: &'a atomic::AtomicUsize,
weak: &'a Atomic<usize>,
strong: &'a Atomic<usize>,
}

impl<T: ?Sized> Weak<T> {
Expand Down
100 changes: 97 additions & 3 deletions library/core/src/sync/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>[Atomic]\<T></code> 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<T>(*mut T), size("ptr"), align(2));
#[cfg(target_pointer_width = "32")]
impl_atomic_primitive!(AtomicPtr<T>(*mut T), size("ptr"), align(4));
#[cfg(target_pointer_width = "64")]
impl_atomic_primitive!(AtomicPtr<T>(*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<T> = <T as AtomicPrimitive>::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
Expand Down Expand Up @@ -388,7 +482,7 @@ pub enum Ordering {
note = "the `new` function is now preferred",
suggestion = "AtomicBool::new(false)"
)]
pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false);
pub const ATOMIC_BOOL_INIT: Atomic<bool> = AtomicBool::new(false);

#[cfg(target_has_atomic_load_store = "8")]
impl AtomicBool {
Expand Down Expand Up @@ -3253,7 +3347,7 @@ macro_rules! atomic_int_ptr_sized {
note = "the `new` function is now preferred",
suggestion = "AtomicIsize::new(0)",
)]
pub const ATOMIC_ISIZE_INIT: AtomicIsize = AtomicIsize::new(0);
pub const ATOMIC_ISIZE_INIT: Atomic<isize> = AtomicIsize::new(0);

/// An [`AtomicUsize`] initialized to `0`.
#[cfg(target_pointer_width = $target_pointer_width)]
Expand All @@ -3263,7 +3357,7 @@ macro_rules! atomic_int_ptr_sized {
note = "the `new` function is now preferred",
suggestion = "AtomicUsize::new(0)",
)]
pub const ATOMIC_USIZE_INIT: AtomicUsize = AtomicUsize::new(0);
pub const ATOMIC_USIZE_INIT: Atomic<usize> = AtomicUsize::new(0);
)* };
}

Expand Down
4 changes: 2 additions & 2 deletions library/std/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
#![stable(feature = "alloc_module", since = "1.28.0")]

use core::ptr::NonNull;
use core::sync::atomic::{AtomicPtr, Ordering};
use core::sync::atomic::{Atomic, AtomicPtr, Ordering};
use core::{hint, mem, ptr};

#[stable(feature = "alloc_module", since = "1.28.0")]
Expand Down Expand Up @@ -287,7 +287,7 @@ unsafe impl Allocator for System {
}
}

static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
static HOOK: Atomic<*mut ()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom allocation error hook, replacing any that was previously registered.
///
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ mod tests;
use crate::backtrace_rs::{self, BytesOrWideString};
use crate::ffi::c_void;
use crate::panic::UnwindSafe;
use crate::sync::atomic::AtomicU8;
use crate::sync::atomic::Ordering::Relaxed;
use crate::sync::atomic::{Atomic, AtomicU8};
use crate::sync::LazyLock;
use crate::sys::backtrace::{lock, output_filename, set_image_base};
use crate::{env, fmt};
Expand Down Expand Up @@ -254,7 +254,7 @@ impl Backtrace {
// Cache the result of reading the environment variables to make
// backtrace captures speedy, because otherwise reading environment
// variables every time can be somewhat slow.
static ENABLED: AtomicU8 = AtomicU8::new(0);
static ENABLED: Atomic<u8> = AtomicU8::new(0);
match ENABLED.load(Relaxed) {
0 => {}
1 => return false,
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/io/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::io::{
self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, SpecReadByte,
};
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantLock, ReentrantLockGuard};
use crate::sys::stdio;
use crate::thread::AccessError;
Expand All @@ -37,7 +37,7 @@ thread_local! {
/// have a consistent order between set_output_capture and print_to *within
/// the same thread*. Within the same thread, things always have a perfectly
/// consistent order. So Ordering::Relaxed is fine.
static OUTPUT_CAPTURE_USED: AtomicBool = AtomicBool::new(false);
static OUTPUT_CAPTURE_USED: Atomic<bool> = AtomicBool::new(false);

/// A handle to a raw instance of the standard input stream of this process.
///
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@
#![feature(float_minimum_maximum)]
#![feature(float_next_up_down)]
#![feature(fmt_internals)]
#![feature(generic_atomic)]
#![feature(hasher_prefixfree_extras)]
#![feature(hashmap_internals)]
#![feature(ip)]
Expand Down
8 changes: 4 additions & 4 deletions library/std/src/os/uefi/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

use crate::ffi::c_void;
use crate::ptr::NonNull;
use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, Ordering};

static SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
static IMAGE_HANDLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
static SYSTEM_TABLE: Atomic<*mut c_void> = AtomicPtr::new(crate::ptr::null_mut());
static IMAGE_HANDLE: Atomic<*mut c_void> = AtomicPtr::new(crate::ptr::null_mut());
// Flag to check if BootServices are still valid.
// Start with assuming that they are not available
static BOOT_SERVICES_FLAG: AtomicBool = AtomicBool::new(false);
static BOOT_SERVICES_FLAG: Atomic<bool> = AtomicBool::new(false);

/// Initializes the global System Table and Image Handle pointers.
///
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/os/xous/services.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::sync::atomic::{AtomicU32, Ordering};
use core::sync::atomic::{Atomic, AtomicU32, Ordering};

use crate::os::xous::ffi::Connection;

Expand Down Expand Up @@ -106,7 +106,7 @@ pub fn try_connect(name: &str) -> Option<Connection> {
ns::try_connect_with_name(name)
}

static NAME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
static NAME_SERVER_CONNECTION: Atomic<u32> = AtomicU32::new(0);

/// Returns a `Connection` to the name server. If the name server has not been started,
/// then this call will block until the name server has been started. The `Connection`
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/os/xous/services/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl Into<usize> for DnsLendMut {
/// Returns a `Connection` to the DNS lookup server. This server is used for
/// querying domain name values.
pub(crate) fn dns_server() -> Connection {
static DNS_CONNECTION: AtomicU32 = AtomicU32::new(0);
static DNS_CONNECTION: Atomic<u32> = AtomicU32::new(0);
let cid = DNS_CONNECTION.load(Ordering::Relaxed);
if cid != 0 {
return cid.into();
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/os/xous/services/log.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::sync::atomic::{AtomicU32, Ordering};
use core::sync::atomic::{Atomic, AtomicU32, Ordering};

use crate::os::xous::ffi::Connection;

Expand Down Expand Up @@ -64,7 +64,7 @@ impl Into<usize> for LogLend {
/// running. It is safe to call this multiple times, because the address is
/// shared among all threads in a process.
pub(crate) fn log_server() -> Connection {
static LOG_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
static LOG_SERVER_CONNECTION: Atomic<u32> = AtomicU32::new(0);

let cid = LOG_SERVER_CONNECTION.load(Ordering::Relaxed);
if cid != 0 {
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/os/xous/services/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl<'a> Into<[usize; 5]> for NetBlockingScalar {
/// Returns a `Connection` to the Network server. This server provides all
/// OS-level networking functions.
pub(crate) fn net_server() -> Connection {
static NET_CONNECTION: AtomicU32 = AtomicU32::new(0);
static NET_CONNECTION: Atomic<u32> = AtomicU32::new(0);
let cid = NET_CONNECTION.load(Ordering::Relaxed);
if cid != 0 {
return cid.into();
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/os/xous/services/systime.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::sync::atomic::{AtomicU32, Ordering};
use core::sync::atomic::{Atomic, AtomicU32, Ordering};

use crate::os::xous::ffi::{connect, Connection};

Expand All @@ -17,7 +17,7 @@ impl Into<[usize; 5]> for SystimeScalar {
/// Returns a `Connection` to the systime server. This server is used for reporting the
/// realtime clock.
pub(crate) fn systime_server() -> Connection {
static SYSTIME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
static SYSTIME_SERVER_CONNECTION: Atomic<u32> = AtomicU32::new(0);
let cid = SYSTIME_SERVER_CONNECTION.load(Ordering::Relaxed);
if cid != 0 {
return cid.into();
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/os/xous/services/ticktimer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::sync::atomic::{AtomicU32, Ordering};
use core::sync::atomic::{Atomic, AtomicU32, Ordering};

use crate::os::xous::ffi::Connection;

Expand Down Expand Up @@ -31,7 +31,7 @@ impl Into<[usize; 5]> for TicktimerScalar {
/// Returns a `Connection` to the ticktimer server. This server is used for synchronization
/// primitives such as sleep, Mutex, and Condvar.
pub(crate) fn ticktimer_server() -> Connection {
static TICKTIMER_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
static TICKTIMER_SERVER_CONNECTION: Atomic<u32> = AtomicU32::new(0);
let cid = TICKTIMER_SERVER_CONNECTION.load(Ordering::Relaxed);
if cid != 0 {
return cid.into();
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![stable(feature = "std_panic", since = "1.9.0")]

use crate::any::Any;
use crate::sync::atomic::{AtomicU8, Ordering};
use crate::sync::atomic::{Atomic, AtomicU8, Ordering};
use crate::sync::{Condvar, Mutex, RwLock};
use crate::thread::Result;
use crate::{collections, fmt, panicking};
Expand Down Expand Up @@ -456,7 +456,7 @@ impl BacktraceStyle {
// that backtrace.
//
// Internally stores equivalent of an Option<BacktraceStyle>.
static SHOULD_CAPTURE: AtomicU8 = AtomicU8::new(0);
static SHOULD_CAPTURE: Atomic<u8> = AtomicU8::new(0);

/// Configures whether the default panic hook will capture and display a
/// backtrace.
Expand Down
8 changes: 4 additions & 4 deletions library/std/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::any::Any;
use crate::io::try_set_output_capture;
use crate::mem::{self, ManuallyDrop};
use crate::panic::{BacktraceStyle, PanicHookInfo};
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
use crate::sync::{PoisonError, RwLock};
use crate::sys::stdio::panic_output;
use crate::sys::{backtrace, dbg};
Expand Down Expand Up @@ -257,7 +257,7 @@ fn default_hook(info: &PanicHookInfo<'_>) {
let mut lock = backtrace::lock();
let _ = writeln!(err, "thread '{name}' panicked at {location}:\n{msg}");

static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
static FIRST_PANIC: Atomic<bool> = AtomicBool::new(true);

match backtrace {
// SAFETY: we took out a lock just a second ago.
Expand Down Expand Up @@ -342,7 +342,7 @@ pub mod panic_count {
#[unstable(feature = "update_panic_count", issue = "none")]
pub mod panic_count {
use crate::cell::Cell;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};

const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1);

Expand Down Expand Up @@ -384,7 +384,7 @@ pub mod panic_count {
//
// Stealing a bit is fine because it just amounts to assuming that each
// panicking thread consumes at least 2 bytes of address space.
static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
static GLOBAL_PANIC_COUNT: Atomic<usize> = AtomicUsize::new(0);

// Increases the global and local panic count, and returns whether an
// immediate abort is required.
Expand Down
Loading

0 comments on commit 8fab921

Please sign in to comment.