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}