use crate::cache_pad::CachePad;
use crate::slot::{Slot, DRAINING, READING};
use crate::variant::sync::atomic::{AtomicPtr, Ordering};
use crate::variant::thread;
#[derive(Debug)]
pub(crate) struct Node<T> {
pub(crate) next: AtomicPtr<CachePad<Node<T>>>,
pub(crate) container: [Slot<T>; NODE_CAPACITY],
}
impl<T> Node<T> {
#[cfg(not(loom))]
pub(crate) const UNINIT: Node<T> = Self {
next: AtomicPtr::new(std::ptr::null_mut()),
container: [Slot::UNINIT; NODE_CAPACITY],
};
#[cfg(loom)]
pub(crate) fn new() -> Self {
Self {
next: AtomicPtr::new(std::ptr::null_mut()),
container: Default::default(),
}
}
pub(crate) fn wait_next(&self) -> *mut CachePad<Self> {
loop {
let next = self.next.load(Ordering::Acquire);
if !next.is_null() {
return next;
}
thread::yield_now();
}
}
pub(crate) unsafe fn drain(node: *mut CachePad<Self>, start: usize) {
for i in start..NODE_CAPACITY - 1 {
let slot = unsafe { (*node).container.get_unchecked(i) };
if slot.state.load(Ordering::Acquire) & READING == 0
&& slot.state.fetch_or(DRAINING, Ordering::AcqRel) & READING == 0
{
return;
}
}
drop(unsafe { Box::from_raw(node) });
}
}
#[cfg(not(loom))]
pub(crate) const NODE_SIZE: usize = 8;
#[cfg(loom)]
pub(crate) const NODE_SIZE: usize = 4;
pub(crate) const NODE_CAPACITY: usize = NODE_SIZE - 1;