use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicU8, AtomicU64, Ordering};
use crate::bench_harness::{BenchQueue, BenchQueueOps, LogQueue, LogQueueOps, LogRecord};
const CAPACITY: usize = 256;
const MASK: usize = CAPACITY - 1;
const EMPTY: u8 = 0;
const WRITING: u8 = 1;
const FULL: u8 = 2;
const READING: u8 = 3;
struct Slot<T> {
state: AtomicU8,
value: UnsafeCell<MaybeUninit<T>>,
}
impl<T> Slot<T> {
fn new() -> Self {
Self {
state: AtomicU8::new(EMPTY),
value: UnsafeCell::new(MaybeUninit::uninit()),
}
}
}
pub struct NaiveFaaQueue<T> {
ring: Box<[Slot<T>]>,
head: AtomicU64,
tail: AtomicU64,
}
unsafe impl<T: Send> Send for NaiveFaaQueue<T> {}
unsafe impl<T: Send> Sync for NaiveFaaQueue<T> {}
impl<T> NaiveFaaQueue<T> {
pub fn new() -> Self {
let ring = (0..CAPACITY).map(|_| Slot::new()).collect();
Self {
ring,
head: AtomicU64::new(0),
tail: AtomicU64::new(0),
}
}
pub fn push(&self, value: T) {
let pos = self.tail.fetch_add(1, Ordering::Relaxed);
let slot = &self.ring[pos as usize & MASK];
while slot
.state
.compare_exchange_weak(EMPTY, WRITING, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
std::hint::spin_loop();
}
unsafe {
(*slot.value.get()).write(value);
}
slot.state.store(FULL, Ordering::Release);
}
pub fn try_pop(&self) -> Option<T> {
if self.tail.load(Ordering::Relaxed) <= self.head.load(Ordering::Relaxed) {
return None;
}
let pos = self.head.fetch_add(1, Ordering::Relaxed);
let slot = &self.ring[pos as usize & MASK];
while slot
.state
.compare_exchange_weak(FULL, READING, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
std::hint::spin_loop();
}
let value = unsafe { (*slot.value.get()).assume_init_read() };
slot.state.store(EMPTY, Ordering::Release);
Some(value)
}
}
impl<T> Default for NaiveFaaQueue<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Drop for NaiveFaaQueue<T> {
fn drop(&mut self) {
for slot in self.ring.iter_mut() {
if *slot.state.get_mut() == FULL {
unsafe {
slot.value.get_mut().assume_init_drop();
}
}
}
}
}
impl BenchQueueOps for NaiveFaaQueue<u64> {
fn try_send_value(&self, value: u64) -> bool {
self.push(value);
true
}
fn try_recv_value(&self) -> Option<u64> {
self.try_pop()
}
fn bounded_capacity(&self) -> Option<usize> {
Some(CAPACITY)
}
}
impl BenchQueue for NaiveFaaQueue<u64> {
fn new_queue() -> std::sync::Arc<Self> {
std::sync::Arc::new(Self::new())
}
}
impl LogQueueOps for NaiveFaaQueue<LogRecord> {
fn send_log(&self, record: LogRecord) {
self.push(record);
}
fn try_recv_log(&self) -> Option<LogRecord> {
self.try_pop()
}
}
impl LogQueue for NaiveFaaQueue<LogRecord> {
fn new_log_queue() -> std::sync::Arc<Self> {
std::sync::Arc::new(Self::new())
}
}