#[cfg(not(portable_atomic_no_asm))]
use core::arch::asm;
#[cfg(not(portable_atomic_disable_fiq))]
macro_rules! if_disable_fiq {
($tt:tt) => {
""
};
}
#[cfg(portable_atomic_disable_fiq)]
macro_rules! if_disable_fiq {
($tt:tt) => {
$tt
};
}
#[derive(Clone, Copy)]
pub(super) struct State(u32);
#[inline]
#[instruction_set(arm::a32)]
pub(super) fn disable() -> State {
let cpsr: u32;
unsafe {
asm!(
"mrs {prev}, cpsr",
"orr {new}, {prev}, 0x80", if_disable_fiq!("orr {new}, {new}, 0x40"), "msr cpsr_c, {new}",
prev = out(reg) cpsr,
new = out(reg) _,
options(nostack, preserves_flags),
);
}
State(cpsr)
}
#[inline]
#[instruction_set(arm::a32)]
pub(super) unsafe fn restore(State(cpsr): State) {
unsafe {
asm!("msr cpsr_c, {0}", in(reg) cpsr, options(nostack));
}
}
pub(crate) mod atomic {
#[cfg(not(portable_atomic_no_asm))]
use core::arch::asm;
use core::{cell::UnsafeCell, sync::atomic::Ordering};
#[repr(transparent)]
pub(crate) struct AtomicBool {
v: UnsafeCell<u8>,
}
impl AtomicBool {
#[inline]
pub(crate) fn load(&self, order: Ordering) -> bool {
unsafe { u8::atomic_load(self.v.get(), order) != 0 }
}
#[inline]
pub(crate) fn store(&self, val: bool, order: Ordering) {
unsafe {
u8::atomic_store(self.v.get(), val as u8, order);
}
}
}
#[repr(transparent)]
pub(crate) struct AtomicPtr<T> {
p: UnsafeCell<*mut T>,
}
impl<T> AtomicPtr<T> {
#[inline]
pub(crate) fn load(&self, order: Ordering) -> *mut T {
unsafe { usize::atomic_load(self.p.get() as *mut usize, order) as *mut T }
}
#[inline]
pub(crate) fn store(&self, ptr: *mut T, order: Ordering) {
unsafe {
usize::atomic_store(self.p.get() as *mut usize, ptr as usize, order);
}
}
}
macro_rules! atomic_int {
($int_type:ident, $atomic_type:ident, $asm_suffix:expr) => {
#[repr(transparent)]
pub(crate) struct $atomic_type {
v: UnsafeCell<$int_type>,
}
impl $atomic_type {
#[inline]
pub(crate) fn load(&self, order: Ordering) -> $int_type {
unsafe { $int_type::atomic_load(self.v.get(), order) }
}
#[inline]
pub(crate) fn store(&self, val: $int_type, order: Ordering) {
unsafe {
$int_type::atomic_store(self.v.get(), val, order);
}
}
}
impl AtomicOperations for $int_type {
#[inline]
unsafe fn atomic_load(src: *const Self, order: Ordering) -> Self {
unsafe {
let out;
match order {
Ordering::Relaxed => {
asm!(
concat!("ldr", $asm_suffix, " {out}, [{src}]"),
src = in(reg) src,
out = lateout(reg) out,
options(nostack, preserves_flags, readonly),
);
}
Ordering::Acquire | Ordering::SeqCst => {
asm!(
concat!("ldr", $asm_suffix, " {out}, [{src}]"),
src = in(reg) src,
out = lateout(reg) out,
options(nostack, preserves_flags),
);
}
_ => unreachable!("{:?}", order),
}
out
}
}
#[inline]
unsafe fn atomic_store(dst: *mut Self, val: Self, _order: Ordering) {
unsafe {
asm!(
concat!("str", $asm_suffix, " {val}, [{dst}]"),
dst = in(reg) dst,
val = in(reg) val,
options(nostack, preserves_flags),
);
}
}
}
};
}
atomic_int!(i8, AtomicI8, "b");
atomic_int!(u8, AtomicU8, "b");
atomic_int!(i16, AtomicI16, "h");
atomic_int!(u16, AtomicU16, "h");
atomic_int!(i32, AtomicI32, "");
atomic_int!(u32, AtomicU32, "");
atomic_int!(isize, AtomicIsize, "");
atomic_int!(usize, AtomicUsize, "");
trait AtomicOperations: Sized {
unsafe fn atomic_load(src: *const Self, order: Ordering) -> Self;
unsafe fn atomic_store(dst: *mut Self, val: Self, order: Ordering);
}
}