atomic_maybe_uninit/lib.rs
1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3/*!
4<!-- Note: Document from sync-markdown-to-rustdoc:start through sync-markdown-to-rustdoc:end
5 is synchronized from README.md. Any changes to that range are not preserved. -->
6<!-- tidy:sync-markdown-to-rustdoc:start -->
7
8Atomic operations on potentially uninitialized integers.
9
10## Motivation
11
12Copying types containing uninitialized bytes (e.g., padding), via the standard library's atomic types
13is [undefined behavior because the copy goes through integers][undefined-behavior].
14
15This crate provides a way to soundly perform such operations.
16
17## Platform Support
18
19Currently, all CPU architectures supported by Rust (x86, x86_64, Arm, AArch64, Arm64EC, RISC-V, LoongArch, s390x, PowerPC, MIPS, SPARC, AVR, MSP430, Hexagon, M68k, C-SKY, and Xtensa) are supported.
20(You can use `cfg_{has,no}_*` macros to write code based on which primitive sizes are available for the current target and Rust version.)
21
22| target_arch | primitives | load/store | swap/CAS |
23| ------------------------------------------- | --------------------------------------------------- |:----------:|:--------:|
24| x86 | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64 | ✓ | ✓ |
25| x86_64 | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64 | ✓ | ✓ |
26| x86_64 (+cmpxchg16b) \[2] | i128,u128 | ✓ | ✓ |
27| arm (v6+ or Linux/Android) | isize,usize,i8,u8,i16,u16,i32,u32 | ✓ | ✓\[1] |
28| arm (except for M-profile) \[3] | i64,u64 | ✓ | ✓ |
29| aarch64 | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64,i128,u128 | ✓ | ✓ |
30| arm64ec \[10] | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64,i128,u128 | ✓ | ✓ |
31| riscv32 | isize,usize,i8,u8,i16,u16,i32,u32 | ✓ | ✓\[1] |
32| riscv32 (+zacas) \[4] | i64,u64 | ✓ | ✓ |
33| riscv64 | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64 | ✓ | ✓\[1] |
34| riscv64 (+zacas) \[4] | i128,u128 | ✓ | ✓ |
35| loongarch64 | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64 | ✓ | ✓ |
36| loongarch64 (+scq) \[5] | i128,u128 | ✓ | ✓ |
37| loongarch32 \[11] | isize,usize,i8,u8,i16,u16,i32,u32 | ✓ | ✓ |
38| s390x \[10] | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64,i128,u128 | ✓ | ✓ |
39| powerpc \[12] | isize,usize,i8,u8,i16,u16,i32,u32 | ✓ | ✓ |
40| powerpc64 \[12] | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64 | ✓ | ✓ |
41| powerpc64 (+quadword-atomics) \[6] \[12] | i128,u128 | ✓ | ✓ |
42| mips / mips32r6 (experimental \[13]) | isize,usize,i8,u8,i16,u16,i32,u32 | ✓ | ✓ |
43| mips64 / mips64r6 (experimental \[13]) | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64 | ✓ | ✓ |
44| sparc (experimental \[13]) | isize,usize,i8,u8,i16,u16,i32,u32 | ✓ | ✓\[1] |
45| sparc (+v8plus) \[8] (experimental \[13]) | i64,u64 | ✓ | ✓ |
46| sparc64 (experimental \[13]) | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64 | ✓ | ✓ |
47| avr (experimental \[13]) | isize,usize,i8,u8,i16,u16 | ✓ | ✓ |
48| msp430 (experimental \[13]) | isize,usize,i8,u8,i16,u16 | ✓ | ✓ |
49| hexagon (experimental \[13]) | isize,usize,i8,u8,i16,u16,i32,u32,i64,u64 | ✓ | ✓ |
50| m68k (experimental \[13]) | isize,usize,i8,u8,i16,u16,i32,u32 | ✓ | ✓\[1] |
51| m68k (+isa-68020) \[9] (experimental \[13]) | i64,u64 | ✓ | ✓ |
52| csky (experimental \[13]) | isize,usize,i8,u8,i16,u16,i32,u32 | ✓ | ✓\[1] |
53| xtensa (experimental \[13]) | isize,usize,i8,u8,i16,u16,i32,u32 | ✓ | ✓\[1] |
54
55\[1] Arm's RMW operations are not available on Armv6-M (thumbv6m). RISC-V's RMW operations are not available on targets without the A (or G which means IMAFD) or Zalrsc or Zacas extension, such as riscv32i, riscv32imc, etc. 32-bit SPARC's RMW operations requires `v9` or `leoncasa` target feature (enabled by default on Linux). M68k's atomic RMW operations requires target-cpu M68020+ (enabled by default on Linux). C-SKY's atomic RMW operations requires target-cpu ck860\* or c860\* (enabled by default on the hard-float target). Xtensa's atomic RMW operations are not available on esp32s2.<br>
56\[2] Requires `cmpxchg16b` target feature (enabled by default on Apple, Windows (except Windows 7), and Fuchsia targets).<br>
57\[3] Armv6+ or Linux/Android, except for M-profile architecture such as thumbv6m, thumbv7m, etc.<br>
58\[4] Requires `zacas` target feature.<br>
59\[5] Requires `scq` target feature and Rust 1.97+.<br>
60\[6] Requires `quadword-atomics` target feature (enabled by default on powerpc64le).<br>
61\[8] Requires `v9` and `v8plus` target features (both enabled by default on Linux).<br>
62\[9] Requires target-cpu M68020 (Linux's default), M68030, M68040, or M68060 (Linux/NetBSD only).<br>
63\[10] Requires Rust 1.84+.<br>
64\[11] Requires Rust 1.91+.<br>
65\[12] Requires Rust 1.95+.<br>
66\[13] Requires nightly due to `#![feature(asm_experimental_arch)]`.<br>
67<!-- mips32r6/mips64r6: \[7] Requires Release 6 Paired LL/SC family of instructions.<br> -->
68
69See also [Atomic operation overview by architecture](https://github.com/taiki-e/atomic-maybe-uninit/blob/HEAD/src/arch/README.md)
70for more information about atomic operations in these architectures.
71
72Feel free to submit an issue if your target is not supported yet.
73
74## Limitations
75
76This crate uses inline assembly to implement atomic operations (this is currently the only sound way to perform atomic operations on uninitialized values), so it is currently not compatible with [Miri](https://github.com/rust-lang/miri/issues/11) and [most kinds of Sanitizers](https://github.com/google/sanitizers/issues/192).
77
78## Related Projects
79
80- [portable-atomic]: Portable atomic types including support for 128-bit atomics, atomic float, etc.
81- [atomic-memcpy]: Byte-wise atomic memcpy.
82- [asmtest]: A library for tracking generated assemblies.
83
84[asmtest]: https://github.com/taiki-e/asmtest
85[atomic-memcpy]: https://github.com/taiki-e/atomic-memcpy
86[portable-atomic]: https://github.com/taiki-e/portable-atomic
87[undefined-behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
88
89<!-- tidy:sync-markdown-to-rustdoc:end -->
90*/
91
92#![no_std]
93#![doc(test(
94 no_crate_inject,
95 attr(allow(
96 dead_code,
97 unused_variables,
98 clippy::undocumented_unsafe_blocks,
99 clippy::unused_trait_names,
100 ))
101))]
102#![warn(
103 // Lints that may help when writing public library.
104 missing_debug_implementations,
105 missing_docs,
106 clippy::alloc_instead_of_core,
107 clippy::exhaustive_enums,
108 clippy::exhaustive_structs,
109 clippy::impl_trait_in_params,
110 clippy::std_instead_of_alloc,
111 clippy::std_instead_of_core,
112 clippy::missing_inline_in_public_items,
113 // Code outside of cfg(test) shouldn't use float.
114 clippy::float_arithmetic,
115 // Code outside of cfg(test) shouldn't use code that can panic except for assertions. (overflow also cause panic if overflow check is enabled)
116 clippy::arithmetic_side_effects,
117)]
118#![cfg_attr(atomic_maybe_uninit_no_strict_provenance, allow(unstable_name_collisions))]
119#![allow(clippy::inline_always, clippy::unreadable_literal, clippy::used_underscore_items)]
120#![cfg_attr(
121 all(
122 atomic_maybe_uninit_unstable_asm_experimental_arch,
123 not(any(
124 // These cases currently don't use asm!
125 all(target_arch = "sparc", atomic_maybe_uninit_no_stbar),
126 all(target_arch = "mips", atomic_maybe_uninit_no_sync),
127 )),
128 ),
129 feature(asm_experimental_arch)
130)]
131
132// There are currently no 128-bit or higher builtin targets.
133// (Although some of our generic code is written with the future
134// addition of 128-bit targets in mind.)
135// Note that Rust (and C99) pointers must be at least 16-bit (i.e., 8-bit targets are impossible): https://github.com/rust-lang/rust/pull/49305
136#[cfg(not(any(
137 target_pointer_width = "16",
138 target_pointer_width = "32",
139 target_pointer_width = "64",
140)))]
141compile_error!(
142 "atomic-maybe-uninit currently only supports targets with {16,32,64}-bit pointer width; \
143 if you need support for others, \
144 please submit an issue at <https://github.com/taiki-e/atomic-maybe-uninit>"
145);
146
147#[cfg(test)]
148extern crate std;
149
150#[macro_use]
151mod utils;
152
153#[cfg(test)]
154#[macro_use]
155mod tests;
156
157pub mod raw;
158
159#[cfg(doc)]
160use core::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release, SeqCst};
161use core::{
162 cell::UnsafeCell,
163 fmt,
164 mem::{self, MaybeUninit},
165 sync::atomic::Ordering,
166};
167
168use self::raw::{AtomicCompareExchange, AtomicLoad, AtomicStore, AtomicSwap, Primitive};
169
170// -----------------------------------------------------------------------------
171// AtomicMaybeUninit
172
173/// A potentially uninitialized integer type which can be safely shared between threads.
174///
175/// This type has the same in-memory representation as the underlying
176/// value type, `MaybeUninit<T>`.
177/// However, the alignment of this type is always equal to its
178/// size, even on targets where `MaybeUninit<T>` has a
179/// lesser alignment.
180#[repr(C)]
181pub struct AtomicMaybeUninit<T: Primitive> {
182 v: UnsafeCell<MaybeUninit<T>>,
183 /// `[T::Align; 0]` ensures alignment is at least that of `T::Align`.
184 ///
185 /// This is needed because x86's u64 is 4-byte aligned and x86_64's u128 is
186 /// 8-byte aligned and atomic operations normally require alignment greater
187 /// than or equal to the size.
188 _align: [T::Align; 0],
189}
190
191impl<T: Primitive> From<MaybeUninit<T>> for AtomicMaybeUninit<T> {
192 /// Creates a new atomic value from a potentially uninitialized value.
193 #[inline]
194 fn from(v: MaybeUninit<T>) -> Self {
195 Self::new(v)
196 }
197}
198
199impl<T: Primitive> From<T> for AtomicMaybeUninit<T> {
200 /// Creates a new atomic value from an initialized value.
201 #[inline]
202 fn from(v: T) -> Self {
203 Self::new(MaybeUninit::new(v))
204 }
205}
206
207impl<T: Primitive> fmt::Debug for AtomicMaybeUninit<T> {
208 #[inline] // fmt is not hot path, but #[inline] on fmt seems to still be useful: https://github.com/rust-lang/rust/pull/117727
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 f.write_str(core::any::type_name::<Self>())
211 }
212}
213
214// Send is implicitly implemented.
215// SAFETY: `T` is `Send` and any data races are prevented by atomic intrinsics.
216unsafe impl<T: Primitive> Sync for AtomicMaybeUninit<T> {}
217
218// UnwindSafe is implicitly implemented.
219impl<T: Primitive> core::panic::RefUnwindSafe for AtomicMaybeUninit<T> {}
220
221impl<T: Primitive> AtomicMaybeUninit<T> {
222 /// Creates a new atomic value from a potentially uninitialized value.
223 ///
224 /// # Examples
225 ///
226 /// ```
227 /// use std::mem::MaybeUninit;
228 ///
229 /// use atomic_maybe_uninit::AtomicMaybeUninit;
230 ///
231 /// let v = AtomicMaybeUninit::new(MaybeUninit::new(5_i32));
232 ///
233 /// // Equivalent to:
234 /// let v = AtomicMaybeUninit::from(5_i32);
235 /// ```
236 #[inline]
237 #[must_use]
238 pub const fn new(v: MaybeUninit<T>) -> Self {
239 Self { v: UnsafeCell::new(v), _align: [] }
240 }
241
242 /// Creates a new reference to an atomic value from a pointer.
243 ///
244 /// # Safety
245 ///
246 /// * `ptr` must be aligned to `align_of::<AtomicMaybeUninit<T>>()` (note that on some platforms this
247 /// can be bigger than `align_of::<MaybeUninit<T>>()`).
248 /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
249 /// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
250 /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
251 /// sizes, without synchronization.
252 ///
253 /// [valid]: core::ptr#safety
254 /// [Memory model for atomic accesses]: core::sync::atomic#memory-model-for-atomic-accesses
255 #[inline]
256 #[must_use]
257 pub const unsafe fn from_ptr<'a>(ptr: *mut MaybeUninit<T>) -> &'a Self {
258 // SAFETY: guaranteed by the caller
259 unsafe { &*ptr.cast::<Self>().cast_const() }
260 }
261
262 const_fn! {
263 const_if: #[cfg(not(atomic_maybe_uninit_no_const_mut_refs))];
264 /// Returns a mutable reference to the underlying value.
265 ///
266 /// This is safe because the mutable reference guarantees that no other threads are
267 /// concurrently accessing the atomic data.
268 ///
269 /// This is `const fn` on Rust 1.83+.
270 ///
271 /// # Examples
272 ///
273 /// ```
274 /// use std::mem::MaybeUninit;
275 ///
276 /// use atomic_maybe_uninit::AtomicMaybeUninit;
277 ///
278 /// let mut v = AtomicMaybeUninit::from(5_i32);
279 /// unsafe { assert_eq!((*v.get_mut()).assume_init(), 5) }
280 /// *v.get_mut() = MaybeUninit::new(10);
281 /// unsafe { assert_eq!((*v.get_mut()).assume_init(), 10) }
282 /// ```
283 #[inline]
284 pub const fn get_mut(&mut self) -> &mut MaybeUninit<T> {
285 // SAFETY: the mutable reference guarantees unique ownership.
286 // (core::cell::UnsafeCell::get_mut requires newer nightly)
287 unsafe { &mut *self.as_ptr() }
288 }
289 }
290
291 /// Consumes the atomic and returns the contained value.
292 ///
293 /// This is safe because passing `self` by value guarantees that no other threads are
294 /// concurrently accessing the atomic data.
295 ///
296 /// # Examples
297 ///
298 /// ```
299 /// use atomic_maybe_uninit::AtomicMaybeUninit;
300 ///
301 /// let v = AtomicMaybeUninit::from(5_i32);
302 /// unsafe { assert_eq!(v.into_inner().assume_init(), 5) }
303 /// ```
304 #[inline]
305 pub const fn into_inner(self) -> MaybeUninit<T> {
306 // SAFETY: AtomicMaybeUninit<T> and MaybeUninit<T> have the same size
307 // and in-memory representations, so they can be safely transmuted.
308 // (Equivalent to UnsafeCell::into_inner which is unstable in const context.)
309 unsafe { utils::transmute_copy_by_val::<Self, MaybeUninit<T>>(self) }
310 }
311
312 /// Loads a value from the atomic value.
313 ///
314 /// `load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
315 /// Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
316 ///
317 /// # Panics
318 ///
319 /// Panics if `order` is [`Release`] or [`AcqRel`].
320 ///
321 /// # Examples
322 ///
323 /// ```
324 /// use std::sync::atomic::Ordering;
325 ///
326 /// use atomic_maybe_uninit::AtomicMaybeUninit;
327 ///
328 /// let v = AtomicMaybeUninit::from(5_i32);
329 /// unsafe { assert_eq!(v.load(Ordering::Relaxed).assume_init(), 5) }
330 /// ```
331 #[inline]
332 #[cfg_attr(debug_assertions, track_caller)]
333 pub fn load(&self, order: Ordering) -> MaybeUninit<T>
334 where
335 T: AtomicLoad,
336 {
337 utils::assert_load_ordering(order);
338 // SAFETY: any data races are prevented by atomic intrinsics, the raw
339 // pointer passed in is valid because we got it from a reference,
340 // and we've checked the order is valid. Alignment is upheld because
341 // `PrimitivePriv`'s safety requirement ensures sufficient alignment
342 // of `T::Align`, and we got our `_align` field.
343 unsafe { T::atomic_load(self.v.get(), order) }
344 }
345
346 /// Stores a value into the atomic value.
347 ///
348 /// `store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
349 /// Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
350 ///
351 /// # Panics
352 ///
353 /// Panics if `order` is [`Acquire`] or [`AcqRel`].
354 ///
355 /// # Examples
356 ///
357 /// ```
358 /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
359 ///
360 /// use atomic_maybe_uninit::AtomicMaybeUninit;
361 ///
362 /// let v = AtomicMaybeUninit::from(5_i32);
363 /// v.store(MaybeUninit::new(10), Ordering::Relaxed);
364 /// unsafe { assert_eq!(v.load(Ordering::Relaxed).assume_init(), 10) }
365 /// ```
366 #[inline]
367 #[cfg_attr(debug_assertions, track_caller)]
368 pub fn store(&self, val: MaybeUninit<T>, order: Ordering)
369 where
370 T: AtomicStore,
371 {
372 utils::assert_store_ordering(order);
373 // SAFETY: any data races are prevented by atomic intrinsics, the raw
374 // pointer passed in is valid because we got it from a reference,
375 // and we've checked the order is valid. Alignment is upheld because
376 // `PrimitivePriv`'s safety requirement ensures sufficient alignment
377 // of `T::Align`, and we got our `_align` field.
378 unsafe { T::atomic_store(self.v.get(), val, order) }
379 }
380
381 /// Stores a value into the atomic value, returning the previous value.
382 ///
383 /// `swap` takes an [`Ordering`] argument which describes the memory ordering
384 /// of this operation. All ordering modes are possible. Note that using
385 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
386 /// using [`Release`] makes the load part [`Relaxed`].
387 ///
388 /// # Examples
389 ///
390 /// ```
391 /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
392 ///
393 /// use atomic_maybe_uninit::AtomicMaybeUninit;
394 ///
395 /// let v = AtomicMaybeUninit::from(5_i32);
396 /// unsafe {
397 /// assert_eq!(v.swap(MaybeUninit::new(10), Ordering::Relaxed).assume_init(), 5);
398 /// assert_eq!(v.load(Ordering::Relaxed).assume_init(), 10);
399 /// }
400 /// ```
401 #[inline]
402 pub fn swap(&self, val: MaybeUninit<T>, order: Ordering) -> MaybeUninit<T>
403 where
404 T: AtomicSwap,
405 {
406 // SAFETY: any data races are prevented by atomic intrinsics and the raw
407 // pointer passed in is valid because we got it from a reference.
408 // Alignment is upheld because `PrimitivePriv`'s safety requirement
409 // ensures sufficient alignment of `T::Align`, and we got our `_align`
410 // field.
411 unsafe { T::atomic_swap(self.v.get(), val, order) }
412 }
413
414 /// Stores a value into the atomic value if the current value is the same as
415 /// the `current` value. Here, "the same" is determined using byte-wise
416 /// equality, not `PartialEq`.
417 ///
418 /// The return value is a result indicating whether the new value was written and
419 /// containing the previous value. On success this value is guaranteed to be equal to
420 /// `current`.
421 ///
422 /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
423 /// ordering of this operation. `success` describes the required ordering for the
424 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
425 /// `failure` describes the required ordering for the load operation that takes place when
426 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
427 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
428 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
429 ///
430 /// # Panics
431 ///
432 /// Panics if `failure` is [`Release`], [`AcqRel`].
433 ///
434 /// # Notes
435 ///
436 /// Comparison of two values containing uninitialized bytes may fail even if
437 /// they are equivalent as Rust's type, because values can be byte-wise
438 /// inequal even when they are equal as Rust values.
439 ///
440 /// For example, the following example could be an infinite loop:
441 ///
442 /// ```no_run
443 /// use std::{
444 /// mem::{self, MaybeUninit},
445 /// sync::atomic::Ordering,
446 /// };
447 ///
448 /// use atomic_maybe_uninit::AtomicMaybeUninit;
449 ///
450 /// #[derive(Clone, Copy, PartialEq, Eq)]
451 /// #[repr(C, align(4))]
452 /// struct Test(u8, u16);
453 ///
454 /// unsafe {
455 /// let x = mem::transmute::<Test, MaybeUninit<u32>>(Test(0, 0));
456 /// let v = AtomicMaybeUninit::new(x);
457 /// while v
458 /// .compare_exchange(
459 /// mem::transmute::<Test, MaybeUninit<u32>>(Test(0, 0)),
460 /// mem::transmute::<Test, MaybeUninit<u32>>(Test(1, 0)),
461 /// Ordering::AcqRel,
462 /// Ordering::Acquire,
463 /// )
464 /// .is_err()
465 /// {}
466 /// }
467 /// ```
468 ///
469 /// To work around this problem, you need to use a helper like the following.
470 ///
471 /// ```
472 /// # use std::{
473 /// # mem::{self, MaybeUninit},
474 /// # sync::atomic::Ordering,
475 /// # };
476 /// # use atomic_maybe_uninit::AtomicMaybeUninit;
477 /// # #[derive(Clone, Copy, PartialEq, Eq)]
478 /// # #[repr(C, align(4))]
479 /// # struct Test(u8, u16);
480 /// // Adapted from https://github.com/crossbeam-rs/crossbeam/blob/crossbeam-utils-0.8.10/crossbeam-utils/src/atomic/atomic_cell.rs#L1081-L1110
481 /// unsafe fn atomic_compare_exchange(
482 /// v: &AtomicMaybeUninit<u32>,
483 /// mut current: Test,
484 /// new: Test,
485 /// ) -> Result<Test, Test> {
486 /// let mut current_raw = unsafe { mem::transmute::<Test, MaybeUninit<u32>>(current) };
487 /// let new_raw = unsafe { mem::transmute::<Test, MaybeUninit<u32>>(new) };
488 /// loop {
489 /// match v.compare_exchange_weak(current_raw, new_raw, Ordering::AcqRel, Ordering::Acquire)
490 /// {
491 /// Ok(_) => {
492 /// // The values are byte-wise equal; for `Test` we know this implies they are `PartialEq`-equal.
493 /// break Ok(current);
494 /// }
495 /// Err(previous_raw) => {
496 /// let previous = unsafe { mem::transmute::<MaybeUninit<u32>, Test>(previous_raw) };
497 ///
498 /// if !Test::eq(&previous, ¤t) {
499 /// break Err(previous);
500 /// }
501 ///
502 /// // The compare-exchange operation has failed and didn't store `new`. The
503 /// // failure is either spurious, or `previous` was semantically equal to
504 /// // `current` but not byte-equal. Let's retry with `previous` as the new
505 /// // `current`.
506 /// current = previous;
507 /// current_raw = previous_raw;
508 /// }
509 /// }
510 /// }
511 /// }
512 /// # if cfg!(valgrind) { return; }
513 ///
514 /// unsafe {
515 /// let x = mem::transmute::<Test, MaybeUninit<u32>>(Test(0, 0));
516 /// let v = AtomicMaybeUninit::new(x);
517 /// while atomic_compare_exchange(&v, Test(0, 0), Test(1, 0)).is_err() {}
518 /// }
519 /// ```
520 ///
521 /// Also, Valgrind reports "Conditional jump or move depends on uninitialized value(s)"
522 /// error if there is such a comparison -- which is correct, that's exactly
523 /// what the implementation does, but we are doing this inside inline
524 /// assembly so it should be fine. (Effectively we are adding partial
525 /// `freeze` capabilities to Rust via inline assembly. This pattern has not
526 /// been blessed by the language team, but is also not known to cause any
527 /// problems.)
528 ///
529 /// # Examples
530 ///
531 /// ```
532 /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
533 ///
534 /// use atomic_maybe_uninit::AtomicMaybeUninit;
535 ///
536 /// unsafe {
537 /// let v = AtomicMaybeUninit::from(5_i32);
538 ///
539 /// assert_eq!(
540 /// v.compare_exchange(
541 /// MaybeUninit::new(5),
542 /// MaybeUninit::new(10),
543 /// Ordering::Acquire,
544 /// Ordering::Relaxed
545 /// )
546 /// .unwrap()
547 /// .assume_init(),
548 /// 5
549 /// );
550 /// assert_eq!(v.load(Ordering::Relaxed).assume_init(), 10);
551 ///
552 /// assert_eq!(
553 /// v.compare_exchange(
554 /// MaybeUninit::new(6),
555 /// MaybeUninit::new(12),
556 /// Ordering::SeqCst,
557 /// Ordering::Acquire
558 /// )
559 /// .unwrap_err()
560 /// .assume_init(),
561 /// 10
562 /// );
563 /// assert_eq!(v.load(Ordering::Relaxed).assume_init(), 10);
564 /// }
565 /// ```
566 #[doc(alias = "compare_and_swap")]
567 #[inline]
568 #[cfg_attr(debug_assertions, track_caller)]
569 pub fn compare_exchange(
570 &self,
571 current: MaybeUninit<T>,
572 new: MaybeUninit<T>,
573 success: Ordering,
574 failure: Ordering,
575 ) -> Result<MaybeUninit<T>, MaybeUninit<T>>
576 where
577 T: AtomicCompareExchange,
578 {
579 utils::assert_compare_exchange_ordering(success, failure);
580 // SAFETY: any data races are prevented by atomic intrinsics and the raw
581 // pointer passed in is valid because we got it from a reference.
582 // Alignment is upheld because `PrimitivePriv`'s safety requirement
583 // ensures sufficient alignment of `T::Align`, and we got our `_align`
584 // field.
585 let (out, ok) =
586 unsafe { T::atomic_compare_exchange(self.v.get(), current, new, success, failure) };
587 if ok { Ok(out) } else { Err(out) }
588 }
589
590 /// Stores a value into the atomic value if the current value is the same as
591 /// the `current` value. Here, "the same" is determined using byte-wise
592 /// equality, not `PartialEq`.
593 ///
594 /// This function is allowed to spuriously fail even when the comparison succeeds,
595 /// which can result in more efficient code on some platforms. The return value
596 /// is a result indicating whether the new value was written and containing
597 /// the previous value.
598 ///
599 /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
600 /// ordering of this operation. `success` describes the required ordering for the
601 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
602 /// `failure` describes the required ordering for the load operation that takes place when
603 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
604 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
605 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
606 ///
607 /// # Panics
608 ///
609 /// Panics if `failure` is [`Release`], [`AcqRel`].
610 ///
611 /// # Notes
612 ///
613 /// Comparison of two values containing uninitialized bytes may fail even if
614 /// they are equivalent as Rust's type, because values can be byte-wise
615 /// inequal even when they are equal as Rust values.
616 ///
617 /// See [`compare_exchange`](Self::compare_exchange) for details.
618 ///
619 /// # Examples
620 ///
621 /// ```
622 /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
623 ///
624 /// use atomic_maybe_uninit::AtomicMaybeUninit;
625 ///
626 /// let v = AtomicMaybeUninit::from(5_i32);
627 ///
628 /// unsafe {
629 /// let mut old = v.load(Ordering::Relaxed);
630 /// loop {
631 /// let new = old.assume_init() * 2;
632 /// match v.compare_exchange_weak(
633 /// old,
634 /// MaybeUninit::new(new),
635 /// Ordering::SeqCst,
636 /// Ordering::Relaxed,
637 /// ) {
638 /// Ok(_) => break,
639 /// Err(x) => old = x,
640 /// }
641 /// }
642 /// }
643 /// ```
644 #[doc(alias = "compare_and_swap")]
645 #[inline]
646 #[cfg_attr(debug_assertions, track_caller)]
647 pub fn compare_exchange_weak(
648 &self,
649 current: MaybeUninit<T>,
650 new: MaybeUninit<T>,
651 success: Ordering,
652 failure: Ordering,
653 ) -> Result<MaybeUninit<T>, MaybeUninit<T>>
654 where
655 T: AtomicCompareExchange,
656 {
657 utils::assert_compare_exchange_ordering(success, failure);
658 // SAFETY: any data races are prevented by atomic intrinsics and the raw
659 // pointer passed in is valid because we got it from a reference.
660 // Alignment is upheld because `PrimitivePriv`'s safety requirement
661 // ensures sufficient alignment of `T::Align`, and we got our `_align`
662 // field.
663 let (out, ok) = unsafe {
664 T::atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
665 };
666 if ok { Ok(out) } else { Err(out) }
667 }
668
669 /// An alias for [`try_update`](Self::try_update).
670 #[inline]
671 #[deprecated(note = "renamed to `try_update` for consistency")]
672 pub fn fetch_update<F>(
673 &self,
674 set_order: Ordering,
675 fetch_order: Ordering,
676 f: F,
677 ) -> Result<MaybeUninit<T>, MaybeUninit<T>>
678 where
679 F: FnMut(MaybeUninit<T>) -> Option<MaybeUninit<T>>,
680 T: AtomicCompareExchange,
681 {
682 self.try_update(set_order, fetch_order, f)
683 }
684
685 /// Fetches the value, and applies a function to it that returns an optional
686 /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
687 /// `Err(previous_value)`.
688 /// See also: [`update`](Self::update).
689 ///
690 /// Note: This may call the function multiple times if the value has been changed from other threads in
691 /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
692 /// only once to the stored value.
693 ///
694 /// `try_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
695 /// The first describes the required ordering for when the operation finally succeeds while the second
696 /// describes the required ordering for loads. These correspond to the success and failure orderings of
697 /// [`compare_exchange`](Self::compare_exchange) respectively.
698 ///
699 /// Using [`Acquire`] as success ordering makes the store part
700 /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
701 /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
702 ///
703 /// # Panics
704 ///
705 /// Panics if `fetch_order` is [`Release`], [`AcqRel`].
706 ///
707 /// # Considerations
708 ///
709 /// This method is not magic; it is not provided by the hardware, and does not act like a
710 /// critical section or mutex.
711 ///
712 /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
713 /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
714 /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
715 /// of the atomic is not in and of itself sufficient to ensure any required preconditions.
716 ///
717 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
718 /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
719 ///
720 /// # Examples
721 ///
722 /// ```
723 /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
724 ///
725 /// use atomic_maybe_uninit::AtomicMaybeUninit;
726 ///
727 /// unsafe {
728 /// let v = AtomicMaybeUninit::from(5_i32);
729 /// assert_eq!(
730 /// v.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None).unwrap_err().assume_init(),
731 /// 5
732 /// );
733 /// assert_eq!(
734 /// v.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(MaybeUninit::new(
735 /// x.assume_init() + 1
736 /// )))
737 /// .unwrap()
738 /// .assume_init(),
739 /// 5
740 /// );
741 /// assert_eq!(v.load(Ordering::SeqCst).assume_init(), 6);
742 /// }
743 /// ```
744 #[allow(clippy::impl_trait_in_params)] // Align to core::sync::atomic
745 #[inline]
746 pub fn try_update(
747 &self,
748 set_order: Ordering,
749 fetch_order: Ordering,
750 mut f: impl FnMut(MaybeUninit<T>) -> Option<MaybeUninit<T>>,
751 ) -> Result<MaybeUninit<T>, MaybeUninit<T>>
752 where
753 T: AtomicCompareExchange,
754 {
755 let mut prev = self.load(fetch_order);
756 while let Some(next) = f(prev) {
757 match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
758 x @ Ok(_) => return x,
759 Err(next_prev) => prev = next_prev,
760 }
761 }
762 Err(prev)
763 }
764
765 /// Fetches the value, applies a function to it that it return a new value.
766 /// The new value is stored and the old value is returned.
767 /// See also: [`try_update`](Self::try_update).
768 ///
769 /// Note: This may call the function multiple times if the value has been changed from other threads in
770 /// the meantime, but the function will have been applied only once to the stored value.
771 ///
772 /// `update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
773 /// The first describes the required ordering for when the operation finally succeeds while the second
774 /// describes the required ordering for loads. These correspond to the success and failure orderings of
775 /// [`compare_exchange`](Self::compare_exchange) respectively.
776 ///
777 /// Using [`Acquire`] as success ordering makes the store part
778 /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
779 /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
780 ///
781 /// # Panics
782 ///
783 /// Panics if `fetch_order` is [`Release`], [`AcqRel`].
784 ///
785 /// # Considerations
786 ///
787 /// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap
788 /// This method is not magic; it is not provided by the hardware, and does not act like a
789 /// critical section or mutex.
790 ///
791 /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
792 /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
793 /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
794 /// of the atomic is not in and of itself sufficient to ensure any required preconditions.
795 ///
796 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
797 /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
798 ///
799 /// # Examples
800 ///
801 /// ```
802 /// use std::{mem::MaybeUninit, sync::atomic::Ordering};
803 ///
804 /// use atomic_maybe_uninit::AtomicMaybeUninit;
805 ///
806 /// unsafe {
807 /// let v = AtomicMaybeUninit::from(5_i32);
808 /// assert_eq!(
809 /// v.update(Ordering::SeqCst, Ordering::SeqCst, |x| MaybeUninit::new(x.assume_init() + 1))
810 /// .assume_init(),
811 /// 5
812 /// );
813 /// assert_eq!(
814 /// v.update(Ordering::SeqCst, Ordering::SeqCst, |x| MaybeUninit::new(x.assume_init() + 1))
815 /// .assume_init(),
816 /// 6
817 /// );
818 /// assert_eq!(v.load(Ordering::SeqCst).assume_init(), 7);
819 /// }
820 /// ```
821 #[allow(clippy::impl_trait_in_params)] // Align to core::sync::atomic
822 #[inline]
823 pub fn update(
824 &self,
825 set_order: Ordering,
826 fetch_order: Ordering,
827 mut f: impl FnMut(MaybeUninit<T>) -> MaybeUninit<T>,
828 ) -> MaybeUninit<T>
829 where
830 T: AtomicCompareExchange,
831 {
832 let mut prev = self.load(fetch_order);
833 loop {
834 match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
835 Ok(x) => break x,
836 Err(next_prev) => prev = next_prev,
837 }
838 }
839 }
840
841 /// Returns a mutable pointer to the underlying value.
842 ///
843 /// Doing non-atomic reads and writes on the resulting value can be a data race.
844 /// This method is mostly useful for FFI, where the function signature may use
845 /// `*mut T` instead of `&AtomicMaybeUninit<T>`.
846 ///
847 /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
848 /// atomic types work with interior mutability. All modifications of an atomic change the value
849 /// through a shared reference, and can do so safely as long as they use atomic operations. Any
850 /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the
851 /// requirements of the [memory model].
852 ///
853 /// [memory model]: core::sync::atomic#memory-model-for-atomic-accesses
854 #[inline]
855 pub const fn as_ptr(&self) -> *mut MaybeUninit<T> {
856 self.v.get()
857 }
858}
859
860macro_rules! int {
861 ($($ty:ident),* => $align:ident) => {$(
862 impl raw::Primitive for $ty {}
863 const _: () = {
864 assert!(mem::size_of::<AtomicMaybeUninit<$ty>>() == mem::size_of::<$ty>());
865 assert!(mem::align_of::<AtomicMaybeUninit<$ty>>() >= mem::size_of::<$ty>());
866 };
867 // SAFETY: the static assertion above ensures safety requirement.
868 unsafe impl private::PrimitivePriv for $ty {
869 type Align = private::$align;
870 }
871 impl AtomicMaybeUninit<$ty> {
872 /// Creates a new atomic value from a potentially uninitialized value.
873 #[inline]
874 #[must_use]
875 // TODO(semver): remove in the next breaking release.
876 #[deprecated(
877 since = "0.3.10",
878 note = "use `new` instead because it is now always `const fn`"
879 )]
880 pub const fn const_new(v: MaybeUninit<$ty>) -> Self {
881 Self { v: UnsafeCell::new(v), _align: [] }
882 }
883 }
884 )*};
885}
886int!(i8, u8 => Align1);
887int!(i16, u16 => Align2);
888int!(i32, u32 => Align4);
889int!(i64, u64 => Align8);
890int!(i128, u128 => Align16);
891int!(isize, usize => AlignPtr);
892
893#[cfg(target_pointer_width = "16")]
894pub use {cfg_has_atomic_16 as cfg_has_atomic_ptr, cfg_no_atomic_16 as cfg_no_atomic_ptr};
895#[cfg(target_pointer_width = "32")]
896pub use {cfg_has_atomic_32 as cfg_has_atomic_ptr, cfg_no_atomic_32 as cfg_no_atomic_ptr};
897#[cfg(target_pointer_width = "64")]
898pub use {cfg_has_atomic_64 as cfg_has_atomic_ptr, cfg_no_atomic_64 as cfg_no_atomic_ptr};
899#[cfg(target_pointer_width = "128")]
900pub use {cfg_has_atomic_128 as cfg_has_atomic_ptr, cfg_no_atomic_128 as cfg_no_atomic_ptr};
901
902// -----------------------------------------------------------------------------
903// Internals
904
905#[cfg_attr(
906 any(target_arch = "aarch64", all(target_arch = "arm64ec", not(atomic_maybe_uninit_no_asm))),
907 path = "arch/aarch64.rs"
908)]
909#[cfg_attr(
910 all(
911 target_arch = "arm",
912 // Pre-v6 Arm has no Data Memory Barrier (DMB) operation, so we cannot implement non-relaxed atomics.
913 // However, Linux kernel provides helpers for it, so we can provide it on Linux/Android.
914 any(
915 target_feature = "v6",
916 atomic_maybe_uninit_target_feature = "v6",
917 target_os = "linux",
918 target_os = "android",
919 ),
920 // Use armv8.rs for Armv8+.
921 not(any(
922 target_feature = "v8",
923 target_feature = "acquire-release",
924 atomic_maybe_uninit_target_feature = "acquire-release",
925 )),
926 ),
927 path = "arch/arm.rs"
928)]
929#[cfg_attr(
930 all(
931 target_arch = "arm",
932 // Use arm.rs for pre-v8 Arm.
933 any(
934 target_feature = "v8",
935 target_feature = "acquire-release",
936 atomic_maybe_uninit_target_feature = "acquire-release",
937 ),
938 ),
939 path = "arch/armv8.rs"
940)]
941#[cfg_attr(
942 all(target_arch = "avr", atomic_maybe_uninit_unstable_asm_experimental_arch),
943 path = "arch/avr.rs"
944)]
945#[cfg_attr(
946 all(target_arch = "csky", atomic_maybe_uninit_unstable_asm_experimental_arch),
947 path = "arch/csky.rs"
948)]
949#[cfg_attr(
950 all(target_arch = "hexagon", atomic_maybe_uninit_unstable_asm_experimental_arch),
951 path = "arch/hexagon.rs"
952)]
953#[cfg_attr(
954 any(
955 all(target_arch = "loongarch32", not(atomic_maybe_uninit_no_asm)),
956 target_arch = "loongarch64",
957 ),
958 path = "arch/loongarch.rs"
959)]
960#[cfg_attr(
961 all(target_arch = "m68k", atomic_maybe_uninit_unstable_asm_experimental_arch),
962 path = "arch/m68k.rs"
963)]
964#[cfg_attr(
965 all(
966 any(
967 // MIPS-I has no SYNC, so we cannot implement non-relaxed atomics.
968 all(target_arch = "mips", not(atomic_maybe_uninit_no_sync)),
969 target_arch = "mips32r6",
970 target_arch = "mips64",
971 target_arch = "mips64r6",
972 ),
973 atomic_maybe_uninit_unstable_asm_experimental_arch,
974 ),
975 path = "arch/mips.rs"
976)]
977#[cfg_attr(
978 all(target_arch = "msp430", atomic_maybe_uninit_unstable_asm_experimental_arch),
979 path = "arch/msp430.rs"
980)]
981#[cfg_attr(
982 all(any(target_arch = "powerpc", target_arch = "powerpc64"), not(atomic_maybe_uninit_no_asm)),
983 path = "arch/powerpc.rs"
984)]
985#[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), path = "arch/riscv.rs")]
986#[cfg_attr(all(target_arch = "s390x", not(atomic_maybe_uninit_no_asm)), path = "arch/s390x.rs")]
987#[cfg_attr(
988 all(
989 any(
990 // SPARC-V7 has no STBAR, so we cannot implement non-relaxed atomics.
991 all(target_arch = "sparc", not(atomic_maybe_uninit_no_stbar)),
992 target_arch = "sparc64",
993 ),
994 atomic_maybe_uninit_unstable_asm_experimental_arch,
995 ),
996 path = "arch/sparc.rs"
997)]
998#[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), path = "arch/x86.rs")]
999#[cfg_attr(
1000 all(target_arch = "xtensa", atomic_maybe_uninit_unstable_asm_experimental_arch),
1001 path = "arch/xtensa.rs"
1002)]
1003#[allow(missing_docs)] // For cfg_* macros.
1004mod arch;
1005
1006mod private {
1007 #![allow(missing_debug_implementations)]
1008
1009 use core::panic::{RefUnwindSafe, UnwindSafe};
1010
1011 /// This trait is private and cannot be implemented for types outside of `atomic-maybe-uninit`.
1012 ///
1013 /// # Safety
1014 ///
1015 /// The implementer must guarantee that `align_of::<Self::Align>() == size_of::<Self>()`.
1016 // Auto traits are needed to better docs.
1017 #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1018 pub unsafe trait PrimitivePriv:
1019 Copy + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe
1020 {
1021 // See _align field of AtomicMaybeUninit.
1022 type Align: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe;
1023 }
1024
1025 #[repr(align(1))]
1026 #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1027 pub struct Align1(#[allow(dead_code)] u8);
1028 #[repr(align(2))]
1029 #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1030 pub struct Align2(#[allow(dead_code)] u16);
1031 #[repr(align(4))]
1032 #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1033 pub struct Align4(#[allow(dead_code)] u32);
1034 #[repr(align(8))]
1035 #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1036 pub struct Align8(#[allow(dead_code)] u64);
1037 #[repr(align(16))]
1038 #[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
1039 pub struct Align16(#[allow(dead_code)] u128);
1040 #[cfg(target_pointer_width = "16")]
1041 pub(crate) type AlignPtr = Align2;
1042 #[cfg(target_pointer_width = "32")]
1043 pub(crate) type AlignPtr = Align4;
1044 #[cfg(target_pointer_width = "64")]
1045 pub(crate) type AlignPtr = Align8;
1046 #[cfg(target_pointer_width = "128")]
1047 pub(crate) type AlignPtr = Align16;
1048
1049 // Check that all cfg_ macros work.
1050 use crate::{
1051 AtomicMaybeUninit, cfg_has_atomic_8, cfg_has_atomic_16, cfg_has_atomic_32,
1052 cfg_has_atomic_64, cfg_has_atomic_128, cfg_has_atomic_cas, cfg_has_atomic_ptr,
1053 cfg_no_atomic_8, cfg_no_atomic_16, cfg_no_atomic_32, cfg_no_atomic_64, cfg_no_atomic_128,
1054 cfg_no_atomic_cas, cfg_no_atomic_ptr,
1055 };
1056 // TODO: make these type aliases public?
1057 cfg_has_atomic_8! {
1058 type _AtomicMaybeUninitI8 = AtomicMaybeUninit<i8>;
1059 type _AtomicMaybeUninitU8 = AtomicMaybeUninit<u8>;
1060 }
1061 cfg_no_atomic_8! {
1062 type _AtomicMaybeUninitI8 = AtomicMaybeUninit<i8>;
1063 type _AtomicMaybeUninitU8 = AtomicMaybeUninit<u8>;
1064 }
1065 cfg_has_atomic_16! {
1066 type _AtomicMaybeUninitI16 = AtomicMaybeUninit<i16>;
1067 type _AtomicMaybeUninitU16 = AtomicMaybeUninit<u16>;
1068 }
1069 cfg_no_atomic_16! {
1070 type _AtomicMaybeUninitI16 = AtomicMaybeUninit<i16>;
1071 type _AtomicMaybeUninitU16 = AtomicMaybeUninit<u16>;
1072 }
1073 cfg_has_atomic_32! {
1074 type _AtomicMaybeUninitI32 = AtomicMaybeUninit<i32>;
1075 type _AtomicMaybeUninitU32 = AtomicMaybeUninit<u32>;
1076 }
1077 cfg_no_atomic_32! {
1078 type _AtomicMaybeUninitI32 = AtomicMaybeUninit<i32>;
1079 type _AtomicMaybeUninitU32 = AtomicMaybeUninit<u32>;
1080 }
1081 cfg_has_atomic_64! {
1082 type _AtomicMaybeUninitI64 = AtomicMaybeUninit<i64>;
1083 type _AtomicMaybeUninitU64 = AtomicMaybeUninit<u64>;
1084 }
1085 cfg_no_atomic_64! {
1086 type _AtomicMaybeUninitI64 = AtomicMaybeUninit<i64>;
1087 type _AtomicMaybeUninitU64 = AtomicMaybeUninit<u64>;
1088 }
1089 cfg_has_atomic_128! {
1090 type _AtomicMaybeUninitI128 = AtomicMaybeUninit<i128>;
1091 type _AtomicMaybeUninitU128 = AtomicMaybeUninit<u128>;
1092 }
1093 cfg_no_atomic_128! {
1094 type _AtomicMaybeUninitI128 = AtomicMaybeUninit<i128>;
1095 type _AtomicMaybeUninitU128 = AtomicMaybeUninit<u128>;
1096 }
1097 cfg_has_atomic_ptr! {
1098 type _AtomicMaybeUninitIsize = AtomicMaybeUninit<isize>;
1099 type _AtomicMaybeUninitUsize = AtomicMaybeUninit<usize>;
1100 }
1101 cfg_no_atomic_ptr! {
1102 type _AtomicMaybeUninitIsize = AtomicMaybeUninit<isize>;
1103 type _AtomicMaybeUninitUsize = AtomicMaybeUninit<usize>;
1104 }
1105 cfg_has_atomic_cas! {
1106 type __AtomicMaybeUninitIsize = AtomicMaybeUninit<isize>;
1107 type __AtomicMaybeUninitUsize = AtomicMaybeUninit<usize>;
1108 }
1109 cfg_no_atomic_cas! {
1110 type __AtomicMaybeUninitIsize = AtomicMaybeUninit<isize>;
1111 type __AtomicMaybeUninitUsize = AtomicMaybeUninit<usize>;
1112 }
1113}