blob: 2b0187280086dcd44db2614914d7c59862cac24d [file] [log] [blame]
pub use core::sync::atomic::{compiler_fence, fence, Ordering};
macro_rules! atomic_int {
($int_type:ident,$atomic_type:ident, $cfg:ident) => {
#[cfg(not($cfg))]
pub use core::sync::atomic::$atomic_type;
#[cfg($cfg)]
#[repr(transparent)]
pub struct $atomic_type {
inner: core::cell::UnsafeCell<$int_type>,
}
#[cfg($cfg)]
unsafe impl Send for $atomic_type {}
#[cfg($cfg)]
unsafe impl Sync for $atomic_type {}
#[cfg(all($cfg, not(missing_refunwindsafe)))]
impl core::panic::RefUnwindSafe for $atomic_type {}
#[cfg($cfg)]
impl Default for $atomic_type {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
#[cfg($cfg)]
impl From<$int_type> for $atomic_type {
#[inline]
fn from(v: $int_type) -> Self {
Self::new(v)
}
}
#[cfg($cfg)]
impl core::fmt::Debug for $atomic_type {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
}
}
#[cfg($cfg)]
impl $atomic_type {
pub const fn new(v: $int_type) -> Self {
Self {
inner: core::cell::UnsafeCell::new(v),
}
}
pub fn into_inner(self) -> $int_type {
self.inner.into_inner()
}
pub fn get_mut(&mut self) -> &mut $int_type {
self.inner.get_mut()
}
pub fn load(&self, _order: Ordering) -> $int_type {
return critical_section::with(|_| unsafe { *self.inner.get() });
}
pub fn store(&self, val: $int_type, _order: Ordering) {
return critical_section::with(|_| unsafe { *self.inner.get() = val });
}
pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
self.op(order, |_| val)
}
pub fn compare_exchange(
&self,
current: $int_type,
new: $int_type,
success: Ordering,
failure: Ordering,
) -> Result<$int_type, $int_type> {
self.compare_exchange_weak(current, new, success, failure)
}
pub fn compare_exchange_weak(
&self,
current: $int_type,
new: $int_type,
_success: Ordering,
_failure: Ordering,
) -> Result<$int_type, $int_type> {
critical_section::with(|_| {
let val = unsafe { &mut *self.inner.get() };
let old = *val;
if old == current {
*val = new;
Ok(old)
} else {
Err(old)
}
})
}
pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
self.op(order, |old| old.wrapping_add(val))
}
pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
self.op(order, |old| old.wrapping_sub(val))
}
pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
self.op(order, |old| old & val)
}
pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
self.op(order, |old| !(old & val))
}
pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
self.op(order, |old| old | val)
}
pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
self.op(order, |old| old ^ val)
}
pub fn fetch_update<F>(
&self,
_set_order: Ordering,
_fetch_order: Ordering,
mut f: F,
) -> Result<$int_type, $int_type>
where
F: FnMut($int_type) -> Option<$int_type>,
{
critical_section::with(|_| {
let val = unsafe { &mut *self.inner.get() };
let old = *val;
if let Some(new) = f(old) {
*val = new;
Ok(old)
} else {
Err(old)
}
})
}
pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
self.op(order, |old| old.max(val))
}
pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
self.op(order, |old| old.min(val))
}
fn op(&self, _order: Ordering, f: impl FnOnce($int_type) -> $int_type) -> $int_type {
critical_section::with(|_| {
let val = unsafe { &mut *self.inner.get() };
let old = *val;
*val = f(old);
old
})
}
}
};
}
atomic_int!(u8, AtomicU8, polyfill_u8);
atomic_int!(u16, AtomicU16, polyfill_u16);
atomic_int!(u32, AtomicU32, polyfill_u32);
atomic_int!(u64, AtomicU64, polyfill_u64);
atomic_int!(usize, AtomicUsize, polyfill_usize);
atomic_int!(i8, AtomicI8, polyfill_i8);
atomic_int!(i16, AtomicI16, polyfill_i16);
atomic_int!(i32, AtomicI32, polyfill_i32);
atomic_int!(i64, AtomicI64, polyfill_i64);
atomic_int!(isize, AtomicIsize, polyfill_isize);
#[cfg(not(polyfill_bool))]
pub use core::sync::atomic::AtomicBool;
#[cfg(polyfill_bool)]
#[repr(transparent)]
pub struct AtomicBool {
inner: core::cell::UnsafeCell<bool>,
}
#[cfg(polyfill_bool)]
impl Default for AtomicBool {
/// Creates an `AtomicBool` initialized to `false`.
#[inline]
fn default() -> Self {
Self::new(false)
}
}
#[cfg(polyfill_bool)]
impl From<bool> for AtomicBool {
#[inline]
fn from(v: bool) -> Self {
Self::new(v)
}
}
#[cfg(polyfill_bool)]
impl core::fmt::Debug for AtomicBool {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
}
}
#[cfg(polyfill_bool)]
unsafe impl Send for AtomicBool {}
#[cfg(polyfill_bool)]
unsafe impl Sync for AtomicBool {}
#[cfg(all(polyfill_bool, not(missing_refunwindsafe)))]
impl core::panic::RefUnwindSafe for AtomicBool {}
#[cfg(polyfill_bool)]
impl AtomicBool {
pub const fn new(v: bool) -> AtomicBool {
Self {
inner: core::cell::UnsafeCell::new(v),
}
}
pub fn into_inner(self) -> bool {
self.inner.into_inner()
}
pub fn get_mut(&mut self) -> &mut bool {
self.inner.get_mut()
}
pub fn load(&self, _order: Ordering) -> bool {
return critical_section::with(|_| unsafe { *self.inner.get() });
}
pub fn store(&self, val: bool, _order: Ordering) {
return critical_section::with(|_| unsafe { *self.inner.get() = val });
}
pub fn swap(&self, val: bool, order: Ordering) -> bool {
self.op(order, |_| val)
}
pub fn compare_exchange(
&self,
current: bool,
new: bool,
success: Ordering,
failure: Ordering,
) -> Result<bool, bool> {
self.compare_exchange_weak(current, new, success, failure)
}
pub fn compare_exchange_weak(
&self,
current: bool,
new: bool,
_success: Ordering,
_failure: Ordering,
) -> Result<bool, bool> {
critical_section::with(|_| {
let val = unsafe { &mut *self.inner.get() };
let old = *val;
if old == current {
*val = new;
Ok(old)
} else {
Err(old)
}
})
}
pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
self.op(order, |old| old & val)
}
pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
self.op(order, |old| !(old & val))
}
pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
self.op(order, |old| old | val)
}
pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
self.op(order, |old| old ^ val)
}
pub fn fetch_update<F>(
&self,
_set_order: Ordering,
_fetch_order: Ordering,
mut f: F,
) -> Result<bool, bool>
where
F: FnMut(bool) -> Option<bool>,
{
critical_section::with(|_| {
let val = unsafe { &mut *self.inner.get() };
let old = *val;
if let Some(new) = f(old) {
*val = new;
Ok(old)
} else {
Err(old)
}
})
}
pub fn fetch_max(&self, val: bool, order: Ordering) -> bool {
self.op(order, |old| old.max(val))
}
pub fn fetch_min(&self, val: bool, order: Ordering) -> bool {
self.op(order, |old| old.min(val))
}
fn op(&self, _order: Ordering, f: impl FnOnce(bool) -> bool) -> bool {
critical_section::with(|_| {
let val = unsafe { &mut *self.inner.get() };
let old = *val;
*val = f(old);
old
})
}
}
#[cfg(not(polyfill_ptr))]
pub use core::sync::atomic::AtomicPtr;
#[cfg(polyfill_ptr)]
#[repr(transparent)]
pub struct AtomicPtr<T> {
inner: core::cell::UnsafeCell<*mut T>,
}
#[cfg(polyfill_ptr)]
impl<T> Default for AtomicPtr<T> {
/// Creates a null `AtomicPtr<T>`.
#[inline]
fn default() -> Self {
Self::new(core::ptr::null_mut())
}
}
#[cfg(polyfill_ptr)]
impl<T> From<*mut T> for AtomicPtr<T> {
#[inline]
fn from(v: *mut T) -> Self {
Self::new(v)
}
}
#[cfg(polyfill_ptr)]
impl<T> core::fmt::Debug for AtomicPtr<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
}
}
#[cfg(polyfill_ptr)]
impl<T> core::fmt::Pointer for AtomicPtr<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Pointer::fmt(&self.load(Ordering::SeqCst), f)
}
}
#[cfg(polyfill_ptr)]
unsafe impl<T> Sync for AtomicPtr<T> {}
#[cfg(polyfill_ptr)]
unsafe impl<T> Send for AtomicPtr<T> {}
#[cfg(all(polyfill_ptr, not(missing_refunwindsafe)))]
impl<T> core::panic::RefUnwindSafe for AtomicPtr<T> {}
#[cfg(polyfill_ptr)]
impl<T> AtomicPtr<T> {
pub const fn new(v: *mut T) -> AtomicPtr<T> {
Self {
inner: core::cell::UnsafeCell::new(v),
}
}
pub fn into_inner(self) -> *mut T {
self.inner.into_inner()
}
pub fn get_mut(&mut self) -> &mut *mut T {
self.inner.get_mut()
}
pub fn load(&self, _order: Ordering) -> *mut T {
return critical_section::with(|_| unsafe { *self.inner.get() });
}
pub fn store(&self, val: *mut T, _order: Ordering) {
return critical_section::with(|_| unsafe { *self.inner.get() = val });
}
pub fn swap(&self, val: *mut T, order: Ordering) -> *mut T {
self.op(order, |_| val)
}
pub fn compare_exchange(
&self,
current: *mut T,
new: *mut T,
success: Ordering,
failure: Ordering,
) -> Result<*mut T, *mut T> {
self.compare_exchange_weak(current, new, success, failure)
}
pub fn compare_exchange_weak(
&self,
current: *mut T,
new: *mut T,
_success: Ordering,
_failure: Ordering,
) -> Result<*mut T, *mut T> {
critical_section::with(|_| {
let val = unsafe { &mut *self.inner.get() };
let old = *val;
if old == current {
*val = new;
Ok(old)
} else {
Err(old)
}
})
}
pub fn fetch_update<F>(
&self,
_set_order: Ordering,
_fetch_order: Ordering,
mut f: F,
) -> Result<*mut T, *mut T>
where
F: FnMut(*mut T) -> Option<*mut T>,
{
critical_section::with(|_| {
let val = unsafe { &mut *self.inner.get() };
let old = *val;
if let Some(new) = f(old) {
*val = new;
Ok(old)
} else {
Err(old)
}
})
}
fn op(&self, _order: Ordering, f: impl FnOnce(*mut T) -> *mut T) -> *mut T {
critical_section::with(|_| {
let val = unsafe { &mut *self.inner.get() };
let old = *val;
*val = f(old);
old
})
}
}