use core::sync::atomic;
use crossbeam_utils::CachePadded;
use std::sync::atomic::{AtomicBool, Ordering};
cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "android"))] {
mod linux;
use linux::MembarrierImpl;
} else if #[cfg(target_os = "freebsd")] {
mod freebsd;
use freebsd::MembarrierImpl;
} else {
compile_error!(concat!("Unsupported platform. This is a bug in ", env!("CARGO_CRATE_NAME"), " crate, please report it!"));
}
}
static MEMBARRIER_SUPPORTED: CachePadded<AtomicBool> = CachePadded::new(AtomicBool::new(false));
#[cfg(not(test))] ctor::declarative::ctor! {
#[ctor]
unsafe fn check_membarrier_support() {
if <MembarrierImpl as Membarrier>::is_supported() {
MEMBARRIER_SUPPORTED.store(true, Ordering::SeqCst);
} else {
<MembarrierImpl as Membarrier>::init_fallback_barrier();
}
}
}
pub(crate) trait Membarrier {
#[cfg_attr(test, allow(dead_code))] fn is_supported() -> bool;
#[inline(always)]
#[cfg_attr(test, allow(dead_code))] fn init_fallback_barrier() {}
#[track_caller]
fn barrier();
#[inline(always)]
#[track_caller]
fn fallback_barrier() {
atomic::fence(Ordering::SeqCst);
}
}
pub(super) struct BarrierImpl;
impl crate::Barrier for BarrierImpl {
#[inline(always)]
fn light() {
#[cfg(not(all(
any(target_os = "linux", target_os = "android"),
any(target_arch = "x86", target_arch = "x86_64")
)))]
if !MEMBARRIER_SUPPORTED.load(Ordering::Relaxed) {
crate::cold();
atomic::fence(Ordering::SeqCst);
}
atomic::compiler_fence(Ordering::SeqCst);
}
#[inline]
#[track_caller]
fn heavy() {
if MEMBARRIER_SUPPORTED.load(Ordering::SeqCst) {
<MembarrierImpl as Membarrier>::barrier();
} else {
crate::cold();
<MembarrierImpl as Membarrier>::fallback_barrier();
}
}
#[inline(always)]
fn is_supported() -> bool {
MEMBARRIER_SUPPORTED.load(Ordering::Relaxed)
}
}