atomic_maybe_uninit/raw.rs
1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3//! Low level API.
4
5#[cfg(doc)]
6use core::{
7 cell::UnsafeCell,
8 sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release, SeqCst},
9};
10use core::{mem::MaybeUninit, sync::atomic::Ordering};
11
12// TODO(semver): merge AtomicLoad and AtomicStore and rename to AtomicLoadStore?
13
14/// Primitive types that may support atomic operations.
15///
16/// This trait is sealed and cannot be implemented for types outside of `atomic-maybe-uninit`.
17///
18/// Currently this is implemented only for integer types.
19pub trait Primitive: crate::private::PrimitivePriv {}
20
21/// Atomic load.
22///
23/// This trait is sealed and cannot be implemented for types outside of `atomic-maybe-uninit`.
24#[cfg_attr(
25 not(atomic_maybe_uninit_no_diagnostic_namespace),
26 diagnostic::on_unimplemented(
27 message = "atomic load of `{Self}` is not available on this target",
28 label = "this associated function is not available on this target",
29 note = "see <https://docs.rs/atomic-maybe-uninit/latest/atomic_maybe_uninit/#platform-support> for more."
30 )
31)]
32pub trait AtomicLoad: Primitive {
33 /// Loads a value from `src`.
34 ///
35 /// `atomic_load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
36 /// Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
37 ///
38 /// # Safety
39 ///
40 /// Behavior is undefined if any of the following conditions are violated:
41 ///
42 /// - `src` must be [valid] for reads.
43 /// - `src` must be aligned to `size_of::<MaybeUninit<T>>()` (note that on some platforms this
44 /// can be bigger than `align_of::<MaybeUninit<T>>()`).
45 /// - `order` must be [`SeqCst`], [`Acquire`], or [`Relaxed`].
46 /// - You must adhere to the [Memory model for atomic accesses]. In particular, it is not
47 /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
48 /// sizes, without synchronization.
49 ///
50 /// Compatibility with read-only memory applies only to relaxed operations with a register or smaller width.
51 /// See the ["Atomic accesses to read-only memory" section in the `core::sync::atomic` docs][read-only-memory]
52 /// for more.
53 ///
54 /// [valid]: core::ptr#safety
55 /// [Memory model for atomic accesses]: core::sync::atomic#memory-model-for-atomic-accesses
56 /// [read-only-memory]: core::sync::atomic#atomic-accesses-to-read-only-memory
57 unsafe fn atomic_load(src: *const MaybeUninit<Self>, order: Ordering) -> MaybeUninit<Self>;
58}
59
60/// Atomic store.
61///
62/// This trait is sealed and cannot be implemented for types outside of `atomic-maybe-uninit`.
63#[cfg_attr(
64 not(atomic_maybe_uninit_no_diagnostic_namespace),
65 diagnostic::on_unimplemented(
66 message = "atomic store of `{Self}` is not available on this target",
67 label = "this associated function is not available on this target",
68 note = "see <https://docs.rs/atomic-maybe-uninit/latest/atomic_maybe_uninit/#platform-support> for more."
69 )
70)]
71pub trait AtomicStore: Primitive {
72 /// Stores a value into `dst`.
73 ///
74 /// `atomic_store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
75 /// Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
76 ///
77 /// # Safety
78 ///
79 /// Behavior is undefined if any of the following conditions are violated:
80 ///
81 /// - `dst` must be [valid] for writes
82 /// - `dst` must be aligned to `size_of::<MaybeUninit<T>>()` (note that on some platforms this
83 /// can be bigger than `align_of::<MaybeUninit<T>>()`).
84 /// - `order` must be [`SeqCst`], [`Release`], or [`Relaxed`].
85 /// - You must adhere to the [Memory model for atomic accesses]. In particular, it is not
86 /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
87 /// sizes, without synchronization.
88 ///
89 /// Compatibility with write-only memory applies only to relaxed operations with a register or smaller width.
90 /// See the ["Atomic accesses to read-only memory" section in the `core::sync::atomic` docs][read-only-memory]
91 /// for more.
92 ///
93 /// [valid]: core::ptr#safety
94 /// [Memory model for atomic accesses]: core::sync::atomic#memory-model-for-atomic-accesses
95 /// [read-only-memory]: core::sync::atomic#atomic-accesses-to-read-only-memory
96 #[inline]
97 unsafe fn atomic_store(dst: *mut MaybeUninit<Self>, val: MaybeUninit<Self>, order: Ordering) {
98 // Workaround LLVM pre-20 bug: https://github.com/rust-lang/rust/issues/129585#issuecomment-2360273081
99 #[cfg(not(atomic_maybe_uninit_llvm_20_or_later))]
100 let val = core::hint::black_box(val);
101 // SAFETY: the caller must uphold the safety contract.
102 unsafe { Self::__atomic_store_impl(dst, val, order) }
103 }
104
105 #[doc(hidden)] // Not public API.
106 unsafe fn __atomic_store_impl(
107 dst: *mut MaybeUninit<Self>,
108 val: MaybeUninit<Self>,
109 order: Ordering,
110 );
111}
112
113/// Atomic swap.
114///
115/// This trait is sealed and cannot be implemented for types outside of `atomic-maybe-uninit`.
116#[cfg_attr(
117 not(atomic_maybe_uninit_no_diagnostic_namespace),
118 diagnostic::on_unimplemented(
119 message = "atomic swap of `{Self}` is not available on this target",
120 label = "this associated function is not available on this target",
121 note = "see <https://docs.rs/atomic-maybe-uninit/latest/atomic_maybe_uninit/#platform-support> for more."
122 )
123)]
124pub trait AtomicSwap: AtomicLoad + AtomicStore {
125 /// Stores a value into `dst`, returning the previous value.
126 ///
127 /// `atomic_swap` takes an [`Ordering`] argument which describes the memory ordering
128 /// of this operation. All ordering modes are possible. Note that using
129 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
130 /// using [`Release`] makes the load part [`Relaxed`].
131 ///
132 /// # Safety
133 ///
134 /// Behavior is undefined if any of the following conditions are violated:
135 ///
136 /// - `dst` must be [valid] for both reads and writes.
137 /// - `dst` must be aligned to `size_of::<MaybeUninit<T>>()` (note that on some platforms this
138 /// can be bigger than `align_of::<MaybeUninit<T>>()`).
139 /// - `order` must be [`SeqCst`], [`AcqRel`], [`Acquire`], [`Release`], or [`Relaxed`].
140 /// - You must adhere to the [Memory model for atomic accesses]. In particular, it is not
141 /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
142 /// sizes, without synchronization.
143 ///
144 /// [valid]: core::ptr#safety
145 /// [Memory model for atomic accesses]: core::sync::atomic#memory-model-for-atomic-accesses
146 #[inline]
147 unsafe fn atomic_swap(
148 dst: *mut MaybeUninit<Self>,
149 val: MaybeUninit<Self>,
150 order: Ordering,
151 ) -> MaybeUninit<Self> {
152 // Workaround LLVM pre-20 bug: https://github.com/rust-lang/rust/issues/129585#issuecomment-2360273081
153 #[cfg(not(atomic_maybe_uninit_llvm_20_or_later))]
154 let val = core::hint::black_box(val);
155 // SAFETY: the caller must uphold the safety contract.
156 unsafe { Self::__atomic_swap_impl(dst, val, order) }
157 }
158
159 #[doc(hidden)] // Not public API.
160 unsafe fn __atomic_swap_impl(
161 dst: *mut MaybeUninit<Self>,
162 val: MaybeUninit<Self>,
163 order: Ordering,
164 ) -> MaybeUninit<Self>;
165}
166
167/// Atomic compare and exchange.
168///
169/// This trait is sealed and cannot be implemented for types outside of `atomic-maybe-uninit`.
170#[cfg_attr(
171 not(atomic_maybe_uninit_no_diagnostic_namespace),
172 diagnostic::on_unimplemented(
173 message = "atomic compare and exchange of `{Self}` is not available on this target",
174 label = "this associated function is not available on this target",
175 note = "see <https://docs.rs/atomic-maybe-uninit/latest/atomic_maybe_uninit/#platform-support> for more."
176 )
177)]
178pub trait AtomicCompareExchange: AtomicLoad + AtomicStore {
179 /// Stores a value into `dst` if the current value is the same as
180 /// the `current` value. Here, "the same" is determined using byte-wise
181 /// equality, not `PartialEq`.
182 ///
183 /// The return value is a tuple of the previous value and the result indicating whether the new
184 /// value was written and containing the previous value. On success, the returned value is
185 /// guaranteed to be equal to the value at `current`.
186 ///
187 /// `atomic_compare_exchange` takes two [`Ordering`] arguments to describe the memory
188 /// ordering of this operation. `success` describes the required ordering for the
189 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
190 /// `failure` describes the required ordering for the load operation that takes place when
191 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
192 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
193 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
194 ///
195 /// # Safety
196 ///
197 /// Behavior is undefined if any of the following conditions are violated:
198 ///
199 /// - `dst` must be valid for both reads and writes.
200 /// - `dst` must be aligned to `size_of::<MaybeUninit<T>>()` (note that on some platforms this
201 /// can be bigger than `align_of::<MaybeUninit<T>>()`).
202 /// - `success` must be [`SeqCst`], [`AcqRel`], [`Acquire`], [`Release`], or [`Relaxed`].
203 /// - `failure` must be [`SeqCst`], [`Acquire`], or [`Relaxed`].
204 /// - You must adhere to the [Memory model for atomic accesses]. In particular, it is not
205 /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
206 /// sizes, without synchronization.
207 ///
208 /// [valid]: core::ptr#safety
209 /// [Memory model for atomic accesses]: core::sync::atomic#memory-model-for-atomic-accesses
210 ///
211 /// # Notes
212 ///
213 /// Comparison of two values containing uninitialized bytes may fail even if
214 /// they are equivalent as Rust's type, because values can be byte-wise
215 /// inequal even when they are equal as Rust values.
216 ///
217 /// See [`AtomicMaybeUninit::compare_exchange`](crate::AtomicMaybeUninit::compare_exchange) for details.
218 #[inline]
219 unsafe fn atomic_compare_exchange(
220 dst: *mut MaybeUninit<Self>,
221 current: MaybeUninit<Self>,
222 new: MaybeUninit<Self>,
223 success: Ordering,
224 failure: Ordering,
225 ) -> (MaybeUninit<Self>, bool) {
226 // Workaround LLVM pre-20 bug: https://github.com/rust-lang/rust/issues/129585#issuecomment-2360273081
227 #[cfg(not(atomic_maybe_uninit_llvm_20_or_later))]
228 let current = core::hint::black_box(current);
229 #[cfg(not(atomic_maybe_uninit_llvm_20_or_later))]
230 let new = core::hint::black_box(new);
231 // SAFETY: the caller must uphold the safety contract.
232 unsafe { Self::__atomic_compare_exchange_impl(dst, current, new, success, failure) }
233 }
234
235 #[doc(hidden)] // Not public API.
236 unsafe fn __atomic_compare_exchange_impl(
237 dst: *mut MaybeUninit<Self>,
238 current: MaybeUninit<Self>,
239 new: MaybeUninit<Self>,
240 success: Ordering,
241 failure: Ordering,
242 ) -> (MaybeUninit<Self>, bool);
243
244 /// Stores a value into `dst` if the current value is the same as
245 /// the `current` value. Here, "the same" is determined using byte-wise
246 /// equality, not `PartialEq`.
247 ///
248 /// This function is allowed to spuriously fail even when the comparison succeeds, which can
249 /// result in more efficient code on some platforms. The return value is a tuple of the previous
250 /// value and the result indicating whether the new value was written and containing the
251 /// previous value.
252 ///
253 /// `atomic_compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
254 /// ordering of this operation. `success` describes the required ordering for the
255 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
256 /// `failure` describes the required ordering for the load operation that takes place when
257 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
258 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
259 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
260 ///
261 /// # Safety
262 ///
263 /// Behavior is undefined if any of the following conditions are violated:
264 ///
265 /// - `dst` must be [valid] for both reads and writes.
266 /// - `dst` must be aligned to `size_of::<MaybeUninit<T>>()` (note that on some platforms this
267 /// can be bigger than `align_of::<MaybeUninit<T>>()`).
268 /// - `success` must be [`SeqCst`], [`AcqRel`], [`Acquire`], [`Release`], or [`Relaxed`].
269 /// - `failure` must be [`SeqCst`], [`Acquire`], or [`Relaxed`].
270 /// - You must adhere to the [Memory model for atomic accesses]. In particular, it is not
271 /// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
272 /// sizes, without synchronization.
273 ///
274 /// [valid]: core::ptr#safety
275 /// [Memory model for atomic accesses]: core::sync::atomic#memory-model-for-atomic-accesses
276 ///
277 /// # Notes
278 ///
279 /// Comparison of two values containing uninitialized bytes may fail even if
280 /// they are equivalent as Rust's type, because values can be byte-wise
281 /// inequal even when they are equal as Rust values.
282 ///
283 /// See [`AtomicMaybeUninit::compare_exchange`](crate::AtomicMaybeUninit::compare_exchange) for details.
284 #[inline]
285 unsafe fn atomic_compare_exchange_weak(
286 dst: *mut MaybeUninit<Self>,
287 current: MaybeUninit<Self>,
288 new: MaybeUninit<Self>,
289 success: Ordering,
290 failure: Ordering,
291 ) -> (MaybeUninit<Self>, bool) {
292 // Workaround LLVM pre-20 bug: https://github.com/rust-lang/rust/issues/129585#issuecomment-2360273081
293 #[cfg(not(atomic_maybe_uninit_llvm_20_or_later))]
294 let current = core::hint::black_box(current);
295 #[cfg(not(atomic_maybe_uninit_llvm_20_or_later))]
296 let new = core::hint::black_box(new);
297 // SAFETY: the caller must uphold the safety contract.
298 unsafe { Self::__atomic_compare_exchange_weak_impl(dst, current, new, success, failure) }
299 }
300
301 #[doc(hidden)] // Not public API.
302 #[inline]
303 unsafe fn __atomic_compare_exchange_weak_impl(
304 dst: *mut MaybeUninit<Self>,
305 current: MaybeUninit<Self>,
306 new: MaybeUninit<Self>,
307 success: Ordering,
308 failure: Ordering,
309 ) -> (MaybeUninit<Self>, bool) {
310 // SAFETY: the caller must uphold the safety contract.
311 unsafe { Self::__atomic_compare_exchange_impl(dst, current, new, success, failure) }
312 }
313}