lamlock 0.2.0

MCS-style flat-combining mutex with panic-awareness
Documentation
use core::{
    ptr::NonNull,
    sync::atomic::{AtomicU32, Ordering},
};

#[repr(transparent)]
pub struct Futex(AtomicU32);

impl core::ops::Deref for Futex {
    type Target = AtomicU32;

    #[inline(always)]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl Futex {
    #[inline(always)]
    pub const fn new(value: u32) -> Self {
        Self(AtomicU32::new(value))
    }

    #[inline(always)]
    pub fn wait(this: NonNull<Self>, value: u32) {
        #[cfg(not(miri))]
        while unsafe { this.as_ref().load(Ordering::Acquire) == value } {
            while let Err(rustix::io::Errno::INTR) = rustix::thread::futex::wait(
                unsafe { &this.as_ref().0 },
                rustix::thread::futex::Flags::PRIVATE,
                value,
                None,
            ) {
                core::hint::spin_loop();
            }
        }

        #[cfg(miri)]
        while unsafe { this.as_ref().load(Ordering::Acquire) == value } {
            core::hint::spin_loop();
        }
    }

    #[inline(always)]
    pub fn notify(this: NonNull<Self>, new_val: u32, #[allow(unused)] old_val: u32) {
        #[cfg(not(miri))]
        if unsafe { this.as_ref().swap(new_val, Ordering::AcqRel) == old_val } {
            let _ = rustix::thread::futex::wake(
                unsafe { &this.as_ref().0 },
                rustix::thread::futex::Flags::PRIVATE,
                1,
            );
        }

        #[cfg(miri)]
        unsafe {
            this.as_ref().store(new_val, Ordering::Release);
        }
    }
}