use std::sync::atomic::Ordering;
use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared};
use crate::bench_harness::{BenchQueue, BenchQueueOps, LogQueue, LogQueueOps, LogRecord};
struct Node<T> {
data: Option<T>,
next: Atomic<Node<T>>,
}
pub struct MsQueue<T> {
head: Atomic<Node<T>>,
tail: Atomic<Node<T>>,
}
unsafe impl<T: Send> Send for MsQueue<T> {}
unsafe impl<T: Send> Sync for MsQueue<T> {}
impl<T> MsQueue<T> {
pub fn new() -> Self {
let sentinel = Owned::new(Node {
data: None,
next: Atomic::null(),
});
let guard = epoch::pin();
let sentinel = sentinel.into_shared(&guard);
Self {
head: Atomic::from(sentinel),
tail: Atomic::from(sentinel),
}
}
pub fn push(&self, value: T) {
let new_node = Owned::new(Node {
data: Some(value),
next: Atomic::null(),
});
let guard = &epoch::pin();
let mut new_node = new_node;
loop {
let tail = self.tail.load(Ordering::Acquire, guard);
let tail_ref = unsafe { tail.deref() };
let next = tail_ref.next.load(Ordering::Acquire, guard);
if next.is_null() {
match tail_ref.next.compare_exchange(
Shared::null(),
new_node,
Ordering::Release,
Ordering::Relaxed,
guard,
) {
Ok(new_node) => {
let _ = self.tail.compare_exchange(
tail,
new_node,
Ordering::Release,
Ordering::Relaxed,
guard,
);
return;
}
Err(err) => {
new_node = err.new;
}
}
} else {
let _ = self.tail.compare_exchange(
tail,
next,
Ordering::Release,
Ordering::Relaxed,
guard,
);
}
}
}
pub fn try_pop(&self) -> Option<T> {
let guard = &epoch::pin();
loop {
let head = self.head.load(Ordering::Acquire, guard);
let head_ref = unsafe { head.deref() };
let next = head_ref.next.load(Ordering::Acquire, guard);
let next_ref = unsafe { next.as_ref() }?;
if self
.head
.compare_exchange(head, next, Ordering::Release, Ordering::Relaxed, guard)
.is_ok()
{
let value = unsafe {
let next_mut = &next_ref.data as *const Option<T> as *mut Option<T>;
(*next_mut).take()
};
unsafe {
guard.defer_destroy(head);
}
return value;
}
}
}
}
impl<T> Default for MsQueue<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Drop for MsQueue<T> {
fn drop(&mut self) {
while self.try_pop().is_some() {}
unsafe {
let guard = epoch::unprotected();
let sentinel = self.head.load(Ordering::Relaxed, guard);
if !sentinel.is_null() {
drop(sentinel.into_owned());
}
}
}
}
impl BenchQueueOps for MsQueue<u64> {
fn try_send_value(&self, value: u64) -> bool {
self.push(value);
true
}
fn try_recv_value(&self) -> Option<u64> {
self.try_pop()
}
}
impl BenchQueue for MsQueue<u64> {
fn new_queue() -> std::sync::Arc<Self> {
std::sync::Arc::new(Self::new())
}
}
impl LogQueueOps for MsQueue<LogRecord> {
fn send_log(&self, record: LogRecord) {
self.push(record);
}
fn try_recv_log(&self) -> Option<LogRecord> {
self.try_pop()
}
}
impl LogQueue for MsQueue<LogRecord> {
fn new_log_queue() -> std::sync::Arc<Self> {
std::sync::Arc::new(Self::new())
}
}