use core::marker::PhantomData;
use std::sync::atomic::Ordering::{Acquire, Relaxed, Release};
use crate::ebr_impl::{RawAtomic, RawShared};
use super::super::{unprotected, Guard};
pub(crate) struct Entry {
next: RawAtomic<Entry>,
}
pub(crate) trait IsElement<T> {
fn entry_of(_: &T) -> &Entry;
unsafe fn element_of(_: &Entry) -> &T;
unsafe fn finalize(_: &Entry, _: &Guard);
}
pub(crate) struct List<T, C: IsElement<T> = T> {
head: RawAtomic<Entry>,
_marker: PhantomData<(T, C)>,
}
pub(crate) struct Iter<'g, T, C: IsElement<T>> {
guard: &'g Guard,
pred: &'g RawAtomic<Entry>,
curr: RawShared<'g, Entry>,
head: &'g RawAtomic<Entry>,
_marker: PhantomData<(&'g T, C)>,
}
#[derive(PartialEq, Debug)]
pub(crate) enum IterError {
Stalled,
}
impl Default for Entry {
fn default() -> Self {
Self {
next: RawAtomic::null(),
}
}
}
impl Entry {
pub(crate) unsafe fn delete(&self, guard: &Guard) {
self.next.fetch_or(1, Release, guard);
}
}
impl<T, C: IsElement<T>> List<T, C> {
pub(crate) fn new() -> Self {
Self {
head: RawAtomic::null(),
_marker: PhantomData,
}
}
pub(crate) unsafe fn insert<'g>(&'g self, container: RawShared<'g, T>, guard: &'g Guard) {
let to = &self.head;
let entry: &Entry = C::entry_of(container.deref());
let entry_ptr = RawShared::from(entry as *const _);
let mut next = to.load(Relaxed, guard);
loop {
entry.next.store(next, Relaxed);
match to.compare_exchange_weak(next, entry_ptr, Release, Relaxed, guard) {
Ok(_) => break,
Err(curr) => next = curr,
}
}
}
pub(crate) fn iter<'g>(&'g self, guard: &'g Guard) -> Iter<'g, T, C> {
Iter {
guard,
pred: &self.head,
curr: self.head.load(Acquire, guard),
head: &self.head,
_marker: PhantomData,
}
}
}
impl<T, C: IsElement<T>> Drop for List<T, C> {
fn drop(&mut self) {
unsafe {
let guard = unprotected();
let mut curr = self.head.load(Relaxed, &guard);
while let Some(c) = curr.as_ref() {
let succ = c.next.load(Relaxed, &guard);
assert_eq!(succ.tag(), 1);
C::finalize(curr.deref(), &guard);
curr = succ;
}
}
}
}
impl<'g, T: 'g, C: IsElement<T>> Iterator for Iter<'g, T, C> {
type Item = Result<&'g T, IterError>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(c) = unsafe { self.curr.as_ref() } {
let succ = c.next.load(Acquire, self.guard);
if succ.tag() == 1 {
let succ = succ.with_tag(0);
debug_assert!(self.curr.tag() == 0);
let succ = match self
.pred
.compare_exchange(self.curr, succ, Acquire, Acquire, self.guard)
{
Ok(_) => {
unsafe {
C::finalize(self.curr.deref(), self.guard);
}
succ
}
Err(curr) => {
curr
}
};
if succ.tag() != 0 {
self.pred = self.head;
self.curr = self.head.load(Acquire, self.guard);
return Some(Err(IterError::Stalled));
}
self.curr = succ;
continue;
}
self.pred = &c.next;
self.curr = succ;
return Some(Ok(unsafe { C::element_of(c) }));
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ebr_impl::collector::Collector;
use crossbeam_utils::thread;
use std::sync::Barrier;
impl IsElement<Entry> for Entry {
fn entry_of(entry: &Entry) -> &Entry {
entry
}
unsafe fn element_of(entry: &Entry) -> &Entry {
entry
}
unsafe fn finalize(entry: &Entry, guard: &Guard) {
guard.defer_destroy(RawShared::from(Self::element_of(entry) as *const _));
}
}
#[test]
fn insert() {
let collector = Collector::new();
let handle = collector.register();
let guard = handle.pin();
let l: List<Entry> = List::new();
let e1 = RawShared::from_owned(Entry::default());
let e2 = RawShared::from_owned(Entry::default());
let e3 = RawShared::from_owned(Entry::default());
unsafe {
l.insert(e1, &guard);
l.insert(e2, &guard);
l.insert(e3, &guard);
}
let mut iter = l.iter(&guard);
let maybe_e3 = iter.next();
assert!(maybe_e3.is_some());
assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw());
let maybe_e2 = iter.next();
assert!(maybe_e2.is_some());
assert!(maybe_e2.unwrap().unwrap() as *const Entry == e2.as_raw());
let maybe_e1 = iter.next();
assert!(maybe_e1.is_some());
assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw());
assert!(iter.next().is_none());
unsafe {
e1.as_ref().unwrap().delete(&guard);
e2.as_ref().unwrap().delete(&guard);
e3.as_ref().unwrap().delete(&guard);
}
}
#[test]
fn delete() {
let collector = Collector::new();
let handle = collector.register();
let guard = handle.pin();
let l: List<Entry> = List::new();
let e1 = RawShared::from_owned(Entry::default());
let e2 = RawShared::from_owned(Entry::default());
let e3 = RawShared::from_owned(Entry::default());
unsafe {
l.insert(e1, &guard);
l.insert(e2, &guard);
l.insert(e3, &guard);
e2.as_ref().unwrap().delete(&guard);
}
let mut iter = l.iter(&guard);
let maybe_e3 = iter.next();
assert!(maybe_e3.is_some());
assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw());
let maybe_e1 = iter.next();
assert!(maybe_e1.is_some());
assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw());
assert!(iter.next().is_none());
unsafe {
e1.as_ref().unwrap().delete(&guard);
e3.as_ref().unwrap().delete(&guard);
}
let mut iter = l.iter(&guard);
assert!(iter.next().is_none());
}
const THREADS: usize = 8;
const ITERS: usize = 512;
#[test]
fn insert_delete_multi() {
let collector = Collector::new();
let l: List<Entry> = List::new();
let b = Barrier::new(THREADS);
thread::scope(|s| {
for _ in 0..THREADS {
s.spawn(|_| {
b.wait();
let handle = collector.register();
let guard: Guard = handle.pin();
let mut v = Vec::with_capacity(ITERS);
for _ in 0..ITERS {
let e = RawShared::from_owned(Entry::default());
v.push(e);
unsafe {
l.insert(e, &guard);
}
}
for e in v {
unsafe {
e.as_ref().unwrap().delete(&guard);
}
}
});
}
})
.unwrap();
let handle = collector.register();
let guard = handle.pin();
let mut iter = l.iter(&guard);
assert!(iter.next().is_none());
}
#[test]
fn iter_multi() {
let collector = Collector::new();
let l: List<Entry> = List::new();
let b = Barrier::new(THREADS);
thread::scope(|s| {
for _ in 0..THREADS {
s.spawn(|_| {
b.wait();
let handle = collector.register();
let guard: Guard = handle.pin();
let mut v = Vec::with_capacity(ITERS);
for _ in 0..ITERS {
let e = RawShared::from_owned(Entry::default());
v.push(e);
unsafe {
l.insert(e, &guard);
}
}
let mut iter = l.iter(&guard);
for _ in 0..ITERS {
assert!(iter.next().is_some());
}
for e in v {
unsafe {
e.as_ref().unwrap().delete(&guard);
}
}
});
}
})
.unwrap();
let handle = collector.register();
let guard = handle.pin();
let mut iter = l.iter(&guard);
assert!(iter.next().is_none());
}
}