pub(crate) fn available() -> bool {
imp::available() && !failed()
}
pub(crate) fn heavy() -> bool {
#[cfg(test)]
if FORCE_FAIL.get() {
return false;
}
imp::heavy()
}
pub(crate) fn heavy_retried() -> bool {
for attempt in 0..8u32 {
if heavy() {
return true;
}
if attempt < 4 {
(0..64u32 << attempt).for_each(|_| core::hint::spin_loop());
} else {
std::thread::yield_now();
}
}
mark_failed();
false
}
#[cfg(not(test))]
static FAILED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
#[cfg(not(test))]
fn failed() -> bool {
FAILED.load(std::sync::atomic::Ordering::Relaxed)
}
#[cfg(not(test))]
fn mark_failed() {
FAILED.store(true, std::sync::atomic::Ordering::Relaxed);
}
#[cfg(test)]
thread_local! {
static FORCE_FAIL: core::cell::Cell<bool> = const { core::cell::Cell::new(false) };
static FAILED: core::cell::Cell<bool> = const { core::cell::Cell::new(false) };
}
#[cfg(test)]
fn failed() -> bool {
FAILED.get()
}
#[cfg(test)]
fn mark_failed() {
FAILED.set(true);
}
#[cfg(test)]
pub(crate) fn inject_failure(on: bool) {
FORCE_FAIL.set(on);
FAILED.set(false);
}
#[cfg(all(target_os = "linux", not(miri), not(all(loom, test))))]
mod imp {
use std::sync::OnceLock;
fn membarrier(cmd: libc::c_int) -> bool {
unsafe { libc::syscall(libc::SYS_membarrier, cmd, 0, 0) == 0 }
}
pub(super) fn available() -> bool {
static REGISTERED: OnceLock<bool> = OnceLock::new();
*REGISTERED.get_or_init(|| membarrier(libc::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED))
}
pub(super) fn heavy() -> bool {
membarrier(libc::MEMBARRIER_CMD_PRIVATE_EXPEDITED)
}
}
#[cfg(all(windows, not(miri), not(all(loom, test))))]
mod imp {
pub(super) fn available() -> bool {
true
}
pub(super) fn heavy() -> bool {
unsafe { crate::syscore::windows::FlushProcessWriteBuffers() };
true
}
}
#[cfg(any(not(any(target_os = "linux", windows)), miri, all(loom, test)))]
mod imp {
pub(super) fn available() -> bool {
false
}
pub(super) fn heavy() -> bool {
crate::sync::internal::fence(crate::sync::internal::Ordering::SeqCst);
true
}
}
#[cfg(all(test, not(loom)))]
mod tests {
#[test]
fn a_heavy_fence_where_there_is_one_succeeds() {
if super::available() {
assert!(super::heavy());
assert!(super::heavy(), "again");
}
}
}