use haphazard::*;
use std::sync::atomic::Ordering;
use std::sync::atomic::{AtomicPtr, AtomicUsize};
#[derive(Default, Debug)]
pub struct Count {
ctors: AtomicUsize,
dtors: AtomicUsize,
_retires: AtomicUsize,
}
#[cfg(miri)]
extern "Rust" {
fn miri_static_root(ptr: *const u8);
}
impl Count {
pub fn test_local() -> &'static Count {
let ptr = Box::leak(Box::new(Self::default()));
#[cfg(miri)]
unsafe {
miri_static_root(ptr as *const _ as *const u8);
}
ptr
}
pub fn ctors(&self) -> usize {
self.ctors.load(Ordering::SeqCst)
}
pub fn dtors(&self) -> usize {
self.dtors.load(Ordering::SeqCst)
}
}
pub struct Node {
count: &'static Count,
val: usize,
next: AtomicPtr<Node>,
}
impl Node {
pub fn new(count: &'static Count, val: usize, next: *mut Node) -> Self {
count.ctors.fetch_add(1, Ordering::AcqRel);
Self {
count,
val,
next: AtomicPtr::new(next),
}
}
pub fn value(&self) -> usize {
self.val
}
pub fn next(&self) -> *const Node {
self.next.load(Ordering::Acquire)
}
}
impl Drop for Node {
fn drop(&mut self) {
self.count.dtors.fetch_add(1, Ordering::AcqRel);
}
}
#[test]
fn basic_objects() {
let count = Count::test_local();
let domain = unique_domain!();
let mut num = 0;
{
num += 1;
let obj = Node::new(count, 0, std::ptr::null_mut());
let x = Box::into_raw(Box::new(obj));
unsafe { domain.retire_ptr::<_, Box<_>>(x) };
}
assert_eq!(num, count.ctors());
domain.cleanup();
assert_eq!(num, count.dtors());
}
#[test]
fn basic_holders() {
{
let _h = HazardPointer::new();
}
{
let _h = HazardPointer::many::<2>();
}
}
#[test]
fn basic_protection() {
let count = Count::test_local();
let domain = unique_domain!();
let obj = Node::new(count, 0, std::ptr::null_mut());
let obj = Box::into_raw(Box::new(obj));
let mut h = HazardPointer::new_in_domain(&domain);
h.protect_raw(obj);
unsafe { domain.retire_ptr::<_, Box<_>>(obj) };
assert_eq!(1, count.ctors());
domain.cleanup();
assert_eq!(0, count.dtors());
h.reset_protection();
domain.cleanup();
assert_eq!(1, count.dtors());
}
#[test]
fn move_test() {
let count = Count::test_local();
let domain = unique_domain!();
for i in 0..100 {
let obj = Node::new(count, i, std::ptr::null_mut());
let x = Box::into_raw(Box::new(obj));
let mut hptr0 = HazardPointer::new_in_domain(&domain);
hptr0.protect_raw(x);
unsafe { domain.retire_ptr::<_, Box<_>>(x) };
let hptr1 = hptr0;
let hptr1 = hptr1;
let mut hptr2;
hptr2 = hptr1;
assert_eq!(unsafe { &*x }.val, i);
hptr2.reset_protection();
}
domain.cleanup();
}
#[test]
fn array() {
let count = Count::test_local();
let domain = unique_domain!();
for i in 0..100 {
let obj = Node::new(count, i, std::ptr::null_mut());
let x = Box::into_raw(Box::new(obj));
let mut hptr = HazardPointer::many_in_domain::<3>(&domain);
let hptr = hptr.as_refs();
hptr[2].protect_raw(x);
unsafe { domain.retire_ptr::<_, Box<_>>(x) };
assert_eq!(unsafe { &*x }.val, i);
hptr[2].reset_protection();
}
domain.cleanup();
}
#[test]
fn array_part_of_cleanup() {
let count = Count::test_local();
let domain = unique_domain!();
{
let _h = HazardPointer::many_in_domain::<2>(&domain);
}
{
let mut h = HazardPointer::many_in_domain::<2>(&domain);
let p0 = Node::new(count, 0, std::ptr::null_mut());
let p0 = Box::into_raw(Box::new(p0));
let p1 = Node::new(count, 0, std::ptr::null_mut());
let p1 = Box::into_raw(Box::new(p1));
let h = h.as_refs();
h[0].protect_raw(p0);
h[1].protect_raw(p1);
unsafe { domain.retire_ptr::<_, Box<_>>(p0) };
unsafe { domain.retire_ptr::<_, Box<_>>(p1) };
}
assert_eq!(2, count.ctors());
domain.cleanup();
assert_eq!(2, count.dtors());
}