#![allow(unsafe_code)]
#[cfg(not(all(loom, test)))]
use core::ptr;
use core::ptr::NonNull;
use super::node::Waiter;
#[cfg(not(all(loom, test)))]
use crate::sync::internal::Ordering;
#[cfg(not(all(loom, test)))]
const POOL_CAPACITY: usize = 16;
#[cfg(not(all(loom, test)))]
struct Pooled(NonNull<Waiter>);
#[cfg(not(all(loom, test)))]
unsafe impl Send for Pooled {}
pub(in crate::sync) struct Pool {
#[cfg(not(all(loom, test)))]
ring: core::sync::atomic::AtomicPtr<kovan_queue::array_queue::ArrayQueue<Pooled>>,
}
impl Pool {
pub(in crate::sync) const fn new() -> Self {
Self {
#[cfg(not(all(loom, test)))]
ring: core::sync::atomic::AtomicPtr::new(ptr::null_mut()),
}
}
pub(super) fn take(&self) -> NonNull<Waiter> {
#[cfg(not(all(loom, test)))]
{
let ring = self.ring.load(Ordering::Acquire);
if let Some(Pooled(node)) = unsafe { ring.as_ref() }.and_then(|ring| ring.pop()) {
return node;
}
}
NonNull::from(Box::leak(Box::new(Waiter::new())))
}
pub(super) fn put(&self, node: NonNull<Waiter>) {
unsafe { node.as_ref() }.clear_slots();
#[cfg(not(all(loom, test)))]
let node = match self.ring().push(Pooled(node)) {
Ok(()) => return,
Err(Pooled(node)) => node,
};
#[cfg(all(loom, test))]
unsafe { &mut *node.as_ptr() }.retire();
drop(unsafe { Box::from_raw(node.as_ptr()) });
}
#[cfg(not(all(loom, test)))]
fn ring(&self) -> &kovan_queue::array_queue::ArrayQueue<Pooled> {
let ring = self.ring.load(Ordering::Acquire);
if let Some(ring) = unsafe { ring.as_ref() } {
return ring;
}
let fresh = Box::into_raw(Box::new(kovan_queue::array_queue::ArrayQueue::new(
POOL_CAPACITY,
)));
match self.ring.compare_exchange(
ptr::null_mut(),
fresh,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => unsafe { &*fresh },
Err(winner) => {
drop(unsafe { Box::from_raw(fresh) });
unsafe { &*winner }
}
}
}
}
impl Drop for Pool {
fn drop(&mut self) {
#[cfg(not(all(loom, test)))]
{
let ring = *self.ring.get_mut();
if !ring.is_null() {
let ring = unsafe { Box::from_raw(ring) };
while let Some(Pooled(node)) = ring.pop() {
drop(unsafe { Box::from_raw(node.as_ptr()) });
}
}
}
}
}