use std::marker::PhantomData;
use std::ptr::{self, NonNull};
use crate::sync::{
Arc, AtomicPtr, AtomicUsize,
Ordering::{Acquire, Relaxed, Release, SeqCst},
UnsafeCell, fence,
};
use crate::utils::CachePadded;
const INITIAL_CAPACITY: usize = 64;
pub(crate) unsafe trait Element: Send {
fn into_raw(self) -> NonNull<()>;
unsafe fn from_raw(ptr: NonNull<()>) -> Self;
}
unsafe impl<T: Send> Element for Box<T> {
fn into_raw(self) -> NonNull<()> {
NonNull::from(Box::leak(self)).cast()
}
unsafe fn from_raw(ptr: NonNull<()>) -> Self {
unsafe { Box::from_raw(ptr.cast::<T>().as_ptr()) }
}
}
struct Buffer {
slots: Box<[AtomicPtr<()>]>,
mask: usize,
}
impl Buffer {
#[allow(clippy::unnecessary_box_returns)]
fn new(capacity: usize) -> Box<Self> {
debug_assert!(capacity.is_power_of_two());
Box::new(Self {
slots: (0..capacity)
.map(|_| AtomicPtr::new(ptr::null_mut()))
.collect(),
mask: capacity - 1,
})
}
fn capacity(&self) -> usize {
self.mask + 1
}
fn slot(&self, index: usize) -> &AtomicPtr<()> {
&self.slots[index & self.mask]
}
}
struct Inner<E: Element> {
top: CachePadded<AtomicUsize>,
bottom: CachePadded<AtomicUsize>,
buffer: CachePadded<AtomicPtr<Buffer>>,
retired: UnsafeCell<Vec<*mut Buffer>>,
_elements: PhantomData<E>,
}
unsafe impl<E: Element> Send for Inner<E> {}
unsafe impl<E: Element> Sync for Inner<E> {}
#[inline]
fn distance(bottom: usize, top: usize) -> isize {
bottom.wrapping_sub(top) as isize
}
impl<E: Element> Inner<E> {
fn with_capacity(capacity: usize, start: usize) -> Self {
Self {
top: CachePadded::new(AtomicUsize::new(start)),
bottom: CachePadded::new(AtomicUsize::new(start)),
buffer: CachePadded::new(AtomicPtr::new(Box::into_raw(Buffer::new(
capacity.next_power_of_two(),
)))),
retired: UnsafeCell::new(Vec::new()),
_elements: PhantomData,
}
}
unsafe fn owner_buffer(&self) -> &Buffer {
unsafe { &*self.buffer.load(Relaxed) }
}
fn push(&self, element: E) {
let b = self.bottom.load(Relaxed);
let t = self.top.load(Acquire);
let mut buffer = unsafe { self.owner_buffer() };
if distance(b, t) >= buffer.capacity() as isize {
buffer = unsafe { self.grow(t, b) };
}
buffer.slot(b).store(element.into_raw().as_ptr(), Relaxed);
self.bottom.store(b.wrapping_add(1), Release);
}
fn pop(&self) -> Option<E> {
let b = self.bottom.load(Relaxed).wrapping_sub(1);
let buffer = unsafe { self.owner_buffer() };
self.bottom.store(b, Release);
#[cfg(not(parkring_mutant = "deque_no_pop_fence"))]
fence(SeqCst);
let t = self.top.load(Relaxed);
let len = distance(b, t);
if len < 0 {
self.bottom.store(b.wrapping_add(1), Release);
return None;
}
let ptr = buffer.slot(b).load(Relaxed);
if len > 0 {
return Some(unsafe { E::from_raw(NonNull::new_unchecked(ptr)) });
}
let won = self
.top
.compare_exchange(t, t.wrapping_add(1), SeqCst, Relaxed)
.is_ok();
self.bottom.store(b.wrapping_add(1), Release);
won.then(|| unsafe { E::from_raw(NonNull::new_unchecked(ptr)) })
}
fn steal(&self) -> Steal<E> {
let t = self.top.load(Acquire);
#[cfg(not(parkring_mutant = "deque_no_steal_fence"))]
fence(SeqCst);
let b = self.bottom.load(Acquire);
if distance(b, t) <= 0 {
return Steal::Empty;
}
let buffer = unsafe { &*self.buffer.load(Acquire) };
let ptr = buffer.slot(t).load(Relaxed);
if self
.top
.compare_exchange(t, t.wrapping_add(1), SeqCst, Relaxed)
.is_err()
{
return Steal::Retry;
}
Steal::Success(unsafe { E::from_raw(NonNull::new(ptr).expect("stole an empty slot")) })
}
#[cold]
unsafe fn grow(&self, t: usize, b: usize) -> &Buffer {
let old = unsafe { self.owner_buffer() };
let new = Buffer::new(old.capacity() * 2);
let mut i = t;
while i != b {
new.slot(i).store(old.slot(i).load(Relaxed), Relaxed);
i = i.wrapping_add(1);
}
let old_ptr = self.buffer.swap(Box::into_raw(new), Release);
self.retired
.with_mut(|retired| unsafe { (*retired).push(old_ptr) });
unsafe { self.owner_buffer() }
}
fn len(&self) -> usize {
let b = self.bottom.load(Acquire);
let t = self.top.load(Acquire);
distance(b, t).max(0).unsigned_abs()
}
}
impl<E: Element> Drop for Inner<E> {
fn drop(&mut self) {
let b = self.bottom.load(Relaxed);
let t = self.top.load(Relaxed);
let buffer = unsafe { Box::from_raw(self.buffer.load(Relaxed)) };
let mut i = t;
while distance(b, i) > 0 {
let ptr = buffer.slot(i).load(Relaxed);
drop(unsafe { E::from_raw(NonNull::new_unchecked(ptr)) });
i = i.wrapping_add(1);
}
self.retired.with_mut(|retired| {
let retired = unsafe { &mut *retired };
for old in retired.drain(..) {
drop(unsafe { Box::from_raw(old) });
}
});
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Steal<T> {
Empty,
Success(T),
Retry,
}
impl<T> Steal<T> {
pub fn success(self) -> Option<T> {
match self {
Self::Success(v) => Some(v),
_ => None,
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}
pub fn is_retry(&self) -> bool {
matches!(self, Self::Retry)
}
fn map<U>(self, f: impl FnOnce(T) -> U) -> Steal<U> {
match self {
Self::Empty => Steal::Empty,
Self::Success(v) => Steal::Success(f(v)),
Self::Retry => Steal::Retry,
}
}
}
pub(crate) struct RawWorker<E: Element> {
inner: Arc<Inner<E>>,
_not_sync: PhantomData<std::cell::Cell<()>>,
}
pub(crate) struct RawStealer<E: Element> {
inner: Arc<Inner<E>>,
}
impl<E: Element> RawWorker<E> {
pub(crate) fn new() -> Self {
Self::with_capacity_and_start(INITIAL_CAPACITY, 0)
}
fn with_capacity_and_start(capacity: usize, start: usize) -> Self {
Self {
inner: Arc::new(Inner::with_capacity(capacity.max(1), start)),
_not_sync: PhantomData,
}
}
pub(crate) fn stealer(&self) -> RawStealer<E> {
RawStealer {
inner: Arc::clone(&self.inner),
}
}
pub(crate) fn push(&self, element: E) {
self.inner.push(element);
}
pub(crate) fn pop(&self) -> Option<E> {
self.inner.pop()
}
pub(crate) fn len(&self) -> usize {
self.inner.len()
}
}
impl<E: Element> RawStealer<E> {
pub(crate) fn steal(&self) -> Steal<E> {
self.inner.steal()
}
pub(crate) fn is_empty(&self) -> bool {
self.inner.len() == 0
}
}
impl<E: Element> Clone for RawStealer<E> {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
}
}
}
pub struct Worker<T: Send> {
raw: RawWorker<Box<T>>,
}
pub struct Stealer<T: Send> {
raw: RawStealer<Box<T>>,
}
impl<T: Send> Worker<T> {
#[must_use]
pub fn new() -> Self {
Self {
raw: RawWorker::new(),
}
}
#[doc(hidden)]
#[must_use]
pub fn with_capacity_and_start(capacity: usize, start: usize) -> Self {
Self {
raw: RawWorker::with_capacity_and_start(capacity, start),
}
}
#[must_use]
pub fn stealer(&self) -> Stealer<T> {
Stealer {
raw: self.raw.stealer(),
}
}
pub fn push(&self, value: T) {
self.raw.push(Box::new(value));
}
#[must_use]
pub fn pop(&self) -> Option<T> {
self.raw.pop().map(|b| *b)
}
#[must_use]
pub fn len(&self) -> usize {
self.raw.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<T: Send> Default for Worker<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Send> Stealer<T> {
#[must_use]
pub fn steal(&self) -> Steal<T> {
self.raw.steal().map(|b| *b)
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.raw.is_empty()
}
}
impl<T: Send> Clone for Stealer<T> {
fn clone(&self) -> Self {
Self {
raw: self.raw.clone(),
}
}
}
impl<T: Send> std::fmt::Debug for Worker<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Worker")
.field("len", &self.len())
.finish_non_exhaustive()
}
}
impl<T: Send> std::fmt::Debug for Stealer<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Stealer").finish_non_exhaustive()
}
}
#[cfg(all(test, loom))]
mod loom_tests;
#[cfg(all(test, not(loom)))]
mod tests {
use super::*;
#[test]
fn owner_is_lifo_and_thief_is_fifo() {
let w = Worker::new();
let s = w.stealer();
for i in 0..5 {
w.push(i);
}
assert_eq!(s.steal(), Steal::Success(0));
assert_eq!(w.pop(), Some(4));
assert_eq!(s.steal(), Steal::Success(1));
assert_eq!(w.pop(), Some(3));
assert_eq!(w.pop(), Some(2));
assert_eq!(w.pop(), None);
assert_eq!(s.steal(), Steal::Empty);
}
#[test]
fn grows_and_keeps_order() {
let w = Worker::with_capacity_and_start(1, 0);
let s = w.stealer();
for i in 0..1000 {
w.push(i);
}
for i in 0..500 {
assert_eq!(s.steal(), Steal::Success(i));
}
for i in (500..1000).rev() {
assert_eq!(w.pop(), Some(i));
}
assert!(w.is_empty());
}
#[test]
fn indices_wrap_around() {
let w = Worker::with_capacity_and_start(2, usize::MAX - 3);
let s = w.stealer();
for round in 0..20 {
for i in 0..10 {
w.push(round * 100 + i);
}
assert_eq!(s.steal(), Steal::Success(round * 100));
for i in (1..10).rev() {
assert_eq!(w.pop(), Some(round * 100 + i));
}
assert_eq!(w.pop(), None);
}
}
#[test]
fn zero_sized_values_work() {
let w = Worker::new();
let s = w.stealer();
for _ in 0..100 {
w.push(());
}
assert_eq!(s.steal(), Steal::Success(()));
assert_eq!(w.len(), 99);
}
}