use core::cell::UnsafeCell;
use core::sync::atomic::{AtomicPtr, AtomicUsize};
pub(crate) type DestructorFn = unsafe fn(*mut RetiredNode);
pub(crate) const INVPTR: usize = !0x0000_0000_0000_0000_usize;
pub(crate) const REFC_PROTECT: usize = 1_usize << 63;
#[inline]
pub(crate) fn rnode_mark(ptr: *mut RetiredNode) -> *mut RetiredNode {
(ptr as usize ^ 1) as *mut RetiredNode
}
#[inline]
pub(crate) fn is_rnode(ptr: *const RetiredNode) -> bool {
(ptr as usize) & 1 != 0
}
#[inline]
pub(crate) fn rnode_unmask(ptr: *mut RetiredNode) -> *mut RetiredNode {
(ptr as usize ^ 1) as *mut RetiredNode
}
#[repr(C, align(8))]
pub struct RetiredNode {
pub(crate) next: AtomicPtr<RetiredNode>,
pub(crate) batch_link: AtomicPtr<RetiredNode>,
pub(crate) refs_or_next: AtomicUsize,
pub(crate) birth_epoch: UnsafeCell<u64>,
pub(crate) destructor: UnsafeCell<Option<DestructorFn>>,
}
impl RetiredNode {
pub fn new() -> Self {
Self {
next: AtomicPtr::new(core::ptr::null_mut()),
batch_link: AtomicPtr::new(core::ptr::null_mut()),
refs_or_next: AtomicUsize::new(0),
birth_epoch: UnsafeCell::new(crate::slot::global().get_epoch()),
destructor: UnsafeCell::new(None),
}
}
#[inline]
pub(crate) fn birth_epoch(&self) -> u64 {
unsafe { *self.birth_epoch.get() }
}
#[inline]
pub(crate) fn set_birth_epoch(&self, epoch: u64) {
unsafe { *self.birth_epoch.get() = epoch }
}
#[inline]
pub(crate) fn destructor(&self) -> Option<DestructorFn> {
unsafe { *self.destructor.get() }
}
#[inline]
pub(crate) fn set_destructor(&self, d: Option<DestructorFn>) {
unsafe { *self.destructor.get() = d }
}
#[inline]
pub(crate) fn batch_next(&self) -> *mut RetiredNode {
self.refs_or_next
.load(core::sync::atomic::Ordering::Relaxed) as *mut RetiredNode
}
#[inline]
pub(crate) fn set_batch_next(&self, next: *mut RetiredNode) {
self.refs_or_next
.store(next as usize, core::sync::atomic::Ordering::Relaxed);
}
#[inline]
pub(crate) fn set_slot_info(&self, tid: usize, index: usize) {
let packed = (tid << 16) | index;
self.next.store(
packed as *mut RetiredNode,
core::sync::atomic::Ordering::Relaxed,
);
}
#[inline]
pub(crate) fn get_slot_info(&self) -> (usize, usize) {
let packed = self.next.load(core::sync::atomic::Ordering::Relaxed) as usize;
(packed >> 16, packed & 0xFFFF)
}
}
impl Default for RetiredNode {
fn default() -> Self {
Self::new()
}
}
unsafe impl Send for RetiredNode {}
unsafe impl Sync for RetiredNode {}