maillon 0.1.0

A concurrent intrusive list for building synchronization primitives.
Documentation
use core::sync::atomic::{AtomicU32, Ordering::*};

use crate::sync::parker::Parker;

/// A futex-based [`Parker`] implementation built on the [`atomic_wait`] crate for the supported
/// platforms.
#[derive(Debug)]
pub struct AtomicParker(AtomicU32);

impl AtomicParker {
    const EMPTY: u32 = 0;
    const NOTIFIED: u32 = 1;
    const PARKED: u32 = u32::MAX;

    fn park(&self) {
        if self.0.fetch_sub(1, Acquire) == Self::NOTIFIED {
            return;
        }
        loop {
            atomic_wait::wait(&self.0, Self::PARKED);
            if ((self.0).compare_exchange(Self::NOTIFIED, Self::EMPTY, Acquire, Relaxed)).is_ok() {
                return;
            }
        }
    }
}

// implementation taken from std Parker futex implementation
impl Parker for AtomicParker {
    #[allow(clippy::declare_interior_mutable_const)]
    const INIT: Self = Self(AtomicU32::new(0));

    #[inline]
    unsafe fn park_until<T>(&self, mut notified: impl FnMut() -> Option<T>) -> T {
        loop {
            self.park();
            if let Some(res) = notified() {
                return res;
            }
        }
    }

    #[inline]
    unsafe fn unpark(&self, _parked_state: *mut ()) {
        if self.0.swap(Self::NOTIFIED, Release) == Self::PARKED {
            atomic_wait::wake_one(&self.0);
        }
    }
}