Skip to main content

urcu/collections/queue/
container.rs

1use std::marker::PhantomData;
2use std::ptr::NonNull;
3use std::sync::Arc;
4
5use crate::collections::queue::raw::{RawNode, RawQueue};
6use crate::collections::queue::reference::Ref;
7use crate::rcu::default::RcuDefaultFlavor;
8use crate::rcu::flavor::RcuFlavor;
9use crate::rcu::guard::RcuGuard;
10use crate::utility::*;
11
12/// Defines a RCU wait-free queue.
13///
14/// This queue supports multiple concurrents readers and writers. It is guaranteed to
15/// never block on a call.
16///
17/// # Limitations
18///
19/// ##### References
20///
21/// This queue currently do not offer a way to peek the back or front of the queue. It is
22/// also currently not possible to iterate over the queue. Because of this, it is impossible
23/// to get any sort of references. The only way to get data is to remove it from the queue
24/// with [`RcuQueue::pop`].
25///
26/// # Safety
27///
28/// It is safe to send an `Arc<RcuQueue<T>>` to a non-registered RCU thread. A non-registered
29/// thread may drop an `RcuQueue<T>` without calling any RCU primitives since lifetime rules
30/// prevent any other thread from accessing a RCU reference.
31pub struct RcuQueue<T, F = RcuDefaultFlavor> {
32    raw: RawQueue<T, F>,
33    _unsend: PhantomUnsend,
34    _unsync: PhantomUnsync,
35}
36
37impl<T, F> RcuQueue<T, F>
38where
39    F: RcuFlavor,
40{
41    /// Creates a new RCU queue.
42    pub fn new() -> Arc<Self> {
43        let mut queue = Arc::new(RcuQueue {
44            // SAFETY: Initialisation is properly called.
45            raw: unsafe { RawQueue::new() },
46            _unsend: PhantomData,
47            _unsync: PhantomData,
48        });
49
50        // SAFETY: Initialisation occurs when raw queue is in a stable memory location.
51        // SAFETY: All the nodes are removed upon dropping.
52        unsafe { Arc::<Self>::get_mut(&mut queue).unwrap().raw.init() };
53
54        queue
55    }
56
57    /// Adds an element to the back of queue.
58    pub fn push<G>(&self, data: T, _guard: &G)
59    where
60        T: Send,
61        G: RcuGuard<Flavor = F>,
62    {
63        let node = RawNode::new(data);
64
65        // SAFETY: The RCU read-lock is taken.
66        unsafe { self.raw.enqueue(node) };
67    }
68
69    /// Removes an element to the front of the queue, if any.
70    pub fn pop<G>(&self, _guard: &G) -> Option<Ref<T, F>>
71    where
72        T: Send,
73        G: RcuGuard<Flavor = F>,
74    {
75        // SAFETY: The RCU read-lock is taken.
76        // SAFETY: The RCU grace period is enforced using `Ref<T, F>`.
77        NonNull::new(unsafe { self.raw.dequeue() }).map(Ref::<T, F>::new)
78    }
79}
80
81/// #### Safety
82///
83/// An [`RcuQueue`] can be used to send `T` to another thread.
84unsafe impl<T, F> Send for RcuQueue<T, F>
85where
86    T: Send,
87    F: RcuFlavor,
88{
89}
90
91/// #### Safety
92///
93/// An [`RcuQueue`] can be used to share `T` between threads.
94unsafe impl<T, F> Sync for RcuQueue<T, F>
95where
96    T: Sync,
97    F: RcuFlavor,
98{
99}
100
101impl<T, F> Drop for RcuQueue<T, F> {
102    fn drop(&mut self) {
103        // SAFETY: The RCU read-lock is not needed there are no other writers.
104        // SAFETY: The RCU grace period is not needed there are no other readers.
105        for ptr in unsafe { self.raw.dequeue_all() } {
106            // SAFETY: The pointer is always non-null and valid.
107            drop(unsafe { Box::from_raw(ptr) });
108        }
109    }
110}