use core::{mem, sync::atomic::Ordering};
const KUSER_MEMORY_BARRIER: usize = 0xFFFF0FA0;
#[inline]
fn __kuser_memory_barrier() {
unsafe {
let f: extern "C" fn() =
mem::transmute(crate::utils::ptr::with_exposed_provenance::<()>(KUSER_MEMORY_BARRIER));
f();
}
}
#[cfg_attr(doc, allow(dead_code))]
#[inline]
#[cfg_attr(any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri), track_caller)]
pub fn fence(order: Ordering) {
match order {
Ordering::Relaxed => panic!("there is no such thing as a relaxed fence"),
_ => __kuser_memory_barrier(),
}
}
cfg_core_atomic!({
use super::core_atomic::{
AtomicI8, AtomicI16, AtomicI32, AtomicIsize, AtomicPtr, AtomicU8, AtomicU16, AtomicU32,
AtomicUsize,
};
macro_rules! atomic {
($([$($generics:tt)*])? $atomic_type:ident, $value_type:ty) => {
impl $(<$($generics)*>)? $atomic_type $(<$($generics)*>)? {
#[inline]
#[cfg_attr(
any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
track_caller
)]
pub(crate) fn load(&self, order: Ordering) -> $value_type {
crate::utils::assert_load_ordering(order);
match order {
Ordering::Relaxed => self.inner.load(Ordering::Relaxed),
Ordering::Acquire | Ordering::SeqCst => {
let out = self.inner.load(Ordering::Relaxed);
__kuser_memory_barrier();
out
}
_ => unreachable!(),
}
}
#[inline]
#[cfg_attr(
any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
track_caller
)]
pub(crate) fn store(&self, val: $value_type, order: Ordering) {
crate::utils::assert_store_ordering(order);
match order {
Ordering::Relaxed => self.inner.store(val, Ordering::Relaxed),
Ordering::Release => {
__kuser_memory_barrier();
self.inner.store(val, Ordering::Relaxed);
}
Ordering::SeqCst => {
__kuser_memory_barrier();
self.inner.store(val, Ordering::Relaxed);
__kuser_memory_barrier();
}
_ => unreachable!(),
}
}
}
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(not(portable_atomic_no_atomic_cas))
)]
#[cfg_attr(
not(portable_atomic_no_cfg_target_has_atomic),
cfg(target_has_atomic = "ptr")
)]
impl $(<$($generics)*>)? $atomic_type $(<$($generics)*>)? {
#[inline]
#[cfg_attr(
any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
track_caller
)]
pub(crate) fn compare_exchange(
&self,
current: $value_type,
new: $value_type,
success: Ordering,
failure: Ordering,
) -> Result<$value_type, $value_type> {
crate::utils::assert_compare_exchange_ordering(success, failure); #[cfg(portable_atomic_no_stronger_failure_ordering)]
let success = crate::utils::upgrade_success_ordering(success, failure);
let res = self.inner.compare_exchange(current, new, success, failure);
if failure != Ordering::Relaxed && res.is_err() {
__kuser_memory_barrier();
}
res
}
#[inline]
#[cfg_attr(
any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
track_caller
)]
pub(crate) fn compare_exchange_weak(
&self,
current: $value_type,
new: $value_type,
success: Ordering,
failure: Ordering,
) -> Result<$value_type, $value_type> {
crate::utils::assert_compare_exchange_ordering(success, failure); #[cfg(portable_atomic_no_stronger_failure_ordering)]
let success = crate::utils::upgrade_success_ordering(success, failure);
let res = self.inner.compare_exchange_weak(current, new, success, failure);
if failure != Ordering::Relaxed && res.is_err() {
__kuser_memory_barrier();
}
res
}
}
};
}
atomic!(AtomicI8, i8);
atomic!(AtomicU8, u8);
atomic!(AtomicI16, i16);
atomic!(AtomicU16, u16);
atomic!(AtomicI32, i32);
atomic!(AtomicU32, u32);
atomic!(AtomicIsize, isize);
atomic!(AtomicUsize, usize);
atomic!([T] AtomicPtr, *mut T);
});
#[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg(not(portable_atomic_no_atomic_64)))]
#[cfg_attr(
not(portable_atomic_no_cfg_target_has_atomic),
cfg(any(
target_has_atomic = "64",
not(any(target_pointer_width = "16", target_pointer_width = "32")),
))
)]
items!({
use super::core_atomic::{AtomicI64, AtomicU64};
macro_rules! atomic_int {
($atomic_type:ident, $int_type:ident) => {
impl $atomic_type {
#[inline]
#[cfg_attr(
any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
track_caller
)]
pub(crate) fn load(&self, order: Ordering) -> $int_type {
crate::utils::assert_load_ordering(order); self.inner.load(order)
}
#[inline]
#[cfg_attr(
any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
track_caller
)]
pub(crate) fn store(&self, val: $int_type, order: Ordering) {
crate::utils::assert_store_ordering(order); self.inner.store(val, order);
}
}
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(not(portable_atomic_no_atomic_cas))
)]
#[cfg_attr(
not(portable_atomic_no_cfg_target_has_atomic),
cfg(target_has_atomic = "ptr")
)]
impl $atomic_type {
#[inline]
#[cfg_attr(
any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
track_caller
)]
pub(crate) fn compare_exchange(
&self,
current: $int_type,
new: $int_type,
success: Ordering,
failure: Ordering,
) -> Result<$int_type, $int_type> {
crate::utils::assert_compare_exchange_ordering(success, failure); #[cfg(portable_atomic_no_stronger_failure_ordering)]
let success = crate::utils::upgrade_success_ordering(success, failure);
self.inner.compare_exchange(current, new, success, failure)
}
#[inline]
#[cfg_attr(
any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
track_caller
)]
pub(crate) fn compare_exchange_weak(
&self,
current: $int_type,
new: $int_type,
success: Ordering,
failure: Ordering,
) -> Result<$int_type, $int_type> {
crate::utils::assert_compare_exchange_ordering(success, failure); #[cfg(portable_atomic_no_stronger_failure_ordering)]
let success = crate::utils::upgrade_success_ordering(success, failure);
self.inner.compare_exchange_weak(current, new, success, failure)
}
}
};
}
atomic_int!(AtomicI64, i64);
atomic_int!(AtomicU64, u64);
});