async-event 0.2.1

An efficient async condition variable for lock-free algorithms.
Documentation
#[cfg(async_event_loom)]
#[allow(unused_imports)]
pub(crate) mod sync {
    pub(crate) use loom::sync::Mutex;

    pub(crate) mod atomic {
        pub(crate) use loom::sync::atomic::{fence, AtomicBool};
    }
}
#[cfg(not(async_event_loom))]
#[allow(unused_imports)]
pub(crate) mod sync {
    pub(crate) use std::sync::Mutex;

    pub(crate) mod atomic {
        pub(crate) use std::sync::atomic::AtomicBool;

        #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(miri)))]
        #[inline(always)]
        pub(crate) fn fence(order: std::sync::atomic::Ordering) {
            use std::sync::atomic::{compiler_fence, AtomicUsize, Ordering};

            if let Ordering::SeqCst = order {
                // On x86, lock-prefixed RMW instructions are faster than the
                // `mfence` instruction generated by LLVM and still provide the
                // same barrier semantics as a `SeqCst` fence. The below
                // basically reproduces how such fence is compiled on GCC>=11,
                // except that GCC uses the stack pointer as the dummy variable.
                // The event-listener crate uses a similar optimization.
                //
                // The fence could be written with inline assembly, but in
                // practice this results in slightly less optimal code due to
                // the assembly being treated as a black box. The generated
                // assembly confirms that the below RMW is not optimized away,
                // but could it be in theory? Not according to the experts:
                // https://stackoverflow.com/q/58667649
                compiler_fence(Ordering::SeqCst);
                let a = AtomicUsize::new(0);
                let _ = a.fetch_or(0, Ordering::SeqCst);
                compiler_fence(Ordering::SeqCst);
            } else {
                std::sync::atomic::fence(order);
            }
        }
        #[cfg(any(not(any(target_arch = "x86", target_arch = "x86_64")), miri))]
        pub(crate) use std::sync::atomic::fence;
    }
}

#[cfg(async_event_loom)]
pub(crate) mod cell {
    pub(crate) use loom::cell::UnsafeCell;
}
#[cfg(not(async_event_loom))]
pub(crate) mod cell {
    #[derive(Debug)]
    pub(crate) struct UnsafeCell<T>(std::cell::UnsafeCell<T>);

    #[allow(dead_code)]
    impl<T> UnsafeCell<T> {
        #[inline(always)]
        pub(crate) fn new(data: T) -> UnsafeCell<T> {
            UnsafeCell(std::cell::UnsafeCell::new(data))
        }
        #[inline(always)]
        pub(crate) fn with<R>(&self, f: impl FnOnce(*const T) -> R) -> R {
            f(self.0.get())
        }
        #[inline(always)]
        pub(crate) fn with_mut<R>(&self, f: impl FnOnce(*mut T) -> R) -> R {
            f(self.0.get())
        }
    }
}