diff options
Diffstat (limited to 'src/flavors/array.rs')
-rw-r--r-- | src/flavors/array.rs | 74 |
1 files changed, 35 insertions, 39 deletions
diff --git a/src/flavors/array.rs b/src/flavors/array.rs index 871768c..73557d3 100644 --- a/src/flavors/array.rs +++ b/src/flavors/array.rs @@ -9,7 +9,6 @@ //! - <https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub> use std::cell::UnsafeCell; -use std::marker::PhantomData; use std::mem::MaybeUninit; use std::ptr; use std::sync::atomic::{self, AtomicUsize, Ordering}; @@ -33,7 +32,7 @@ struct Slot<T> { /// The token type for the array flavor. #[derive(Debug)] -pub struct ArrayToken { +pub(crate) struct ArrayToken { /// Slot to read from or write to. slot: *const u8, @@ -72,7 +71,7 @@ pub(crate) struct Channel<T> { tail: CachePadded<AtomicUsize>, /// The buffer holding slots. - buffer: *mut Slot<T>, + buffer: Box<[Slot<T>]>, /// The channel capacity. cap: usize, @@ -88,9 +87,6 @@ pub(crate) struct Channel<T> { /// Receivers waiting while the channel is empty and not disconnected. receivers: SyncWaker, - - /// Indicates that dropping a `Channel<T>` may drop values of type `T`. - _marker: PhantomData<T>, } impl<T> Channel<T> { @@ -109,18 +105,15 @@ impl<T> Channel<T> { // Allocate a buffer of `cap` slots initialized // with stamps. - let buffer = { - let boxed: Box<[Slot<T>]> = (0..cap) - .map(|i| { - // Set the stamp to `{ lap: 0, mark: 0, index: i }`. - Slot { - stamp: AtomicUsize::new(i), - msg: UnsafeCell::new(MaybeUninit::uninit()), - } - }) - .collect(); - Box::into_raw(boxed) as *mut Slot<T> - }; + let buffer: Box<[Slot<T>]> = (0..cap) + .map(|i| { + // Set the stamp to `{ lap: 0, mark: 0, index: i }`. + Slot { + stamp: AtomicUsize::new(i), + msg: UnsafeCell::new(MaybeUninit::uninit()), + } + }) + .collect(); Channel { buffer, @@ -131,7 +124,6 @@ impl<T> Channel<T> { tail: CachePadded::new(AtomicUsize::new(tail)), senders: SyncWaker::new(), receivers: SyncWaker::new(), - _marker: PhantomData, } } @@ -163,7 +155,8 @@ impl<T> Channel<T> { let lap = tail & !(self.one_lap - 1); // Inspect the corresponding slot. - let slot = unsafe { &*self.buffer.add(index) }; + debug_assert!(index < self.buffer.len()); + let slot = unsafe { self.buffer.get_unchecked(index) }; let stamp = slot.stamp.load(Ordering::Acquire); // If the tail and the stamp match, we may attempt to push. @@ -245,7 +238,8 @@ impl<T> Channel<T> { let lap = head & !(self.one_lap - 1); // Inspect the corresponding slot. - let slot = unsafe { &*self.buffer.add(index) }; + debug_assert!(index < self.buffer.len()); + let slot = unsafe { self.buffer.get_unchecked(index) }; let stamp = slot.stamp.load(Ordering::Acquire); // If the the stamp is ahead of the head by 1, we may attempt to pop. @@ -475,7 +469,6 @@ impl<T> Channel<T> { } /// Returns the capacity of the channel. - #[allow(clippy::unnecessary_wraps)] // This is intentional. pub(crate) fn capacity(&self) -> Option<usize> { Some(self.cap) } @@ -528,10 +521,24 @@ impl<T> Channel<T> { impl<T> Drop for Channel<T> { fn drop(&mut self) { // Get the index of the head. - let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1); + let head = *self.head.get_mut(); + let tail = *self.tail.get_mut(); + + let hix = head & (self.mark_bit - 1); + let tix = tail & (self.mark_bit - 1); + + let len = if hix < tix { + tix - hix + } else if hix > tix { + self.cap - hix + tix + } else if (tail & !self.mark_bit) == head { + 0 + } else { + self.cap + }; // Loop over all slots that hold a message and drop them. - for i in 0..self.len() { + for i in 0..len { // Compute the index of the next slot holding a message. let index = if hix + i < self.cap { hix + i @@ -540,23 +547,12 @@ impl<T> Drop for Channel<T> { }; unsafe { - let p = { - let slot = &mut *self.buffer.add(index); - let msg = &mut *slot.msg.get(); - msg.as_mut_ptr() - }; - p.drop_in_place(); + debug_assert!(index < self.buffer.len()); + let slot = self.buffer.get_unchecked_mut(index); + let msg = &mut *slot.msg.get(); + msg.as_mut_ptr().drop_in_place(); } } - - // Finally, deallocate the buffer, but don't run any destructors. - unsafe { - // Create a slice from the buffer to make - // a fat pointer. Then, use Box::from_raw - // to deallocate it. - let ptr = std::slice::from_raw_parts_mut(self.buffer, self.cap) as *mut [Slot<T>]; - Box::from_raw(ptr); - } } } |