urcu/collections/list/container.rs
1use std::marker::PhantomData;
2use std::ops::Deref;
3use std::ptr::NonNull;
4use std::sync::{Arc, Mutex};
5
6use anyhow::{bail, Result};
7
8use crate::collections::list::iterator::Iter;
9use crate::collections::list::raw::{RawIter, RawList, RawNode};
10use crate::collections::list::reference::Ref;
11use crate::rcu::default::RcuDefaultFlavor;
12use crate::rcu::flavor::RcuFlavor;
13use crate::rcu::guard::RcuGuard;
14use crate::utility::*;
15
16/// Defines a RCU doubly linked list.
17///
18/// This linked list supports multiple concurrents readers at any time, but only a single
19/// writer at a time. The list uses an internal lock for writing operations.
20///
21/// # Limitations
22///
23/// ##### Mutable References
24///
25/// Because there might always be readers borrowing a node's data, it is impossible
26/// to get a mutable references to the data inside the linked list. You should design
27/// the type stored in the list with [interior mutabillity] that can be shared between
28/// threads.
29///
30/// [interior mutabillity]: https://doc.rust-lang.org/reference/interior-mutability.html
31///
32/// ##### List Length
33///
34/// Because a writer might concurrently modify the list, the amount of node might change
35/// at any moment. To prevent user error (e.g. allocate an array for each node), there is
36/// no `.len()` method.
37///
38/// # Safety
39///
40/// It is safe to send an `Arc<RcuList<T>>` to a non-registered RCU thread. A non-registered
41/// thread may drop an `RcuList<T>` without calling any RCU primitives since lifetime rules
42/// prevent any other thread from accessing a RCU reference.
43pub struct RcuList<T, F = RcuDefaultFlavor> {
44 raw: RawList<T>,
45 mutex: Mutex<()>,
46 _unsend: PhantomUnsend<F>,
47 _unsync: PhantomUnsync<F>,
48}
49
50impl<T, F> RcuList<T, F>
51where
52 F: RcuFlavor,
53{
54 /// Creates a new RCU linked list.
55 pub fn new() -> Arc<Self> {
56 let mut list = Arc::new(RcuList {
57 // SAFETY: Initialisation is properly called.
58 raw: unsafe { RawList::new() },
59 mutex: Default::default(),
60 _unsend: PhantomData,
61 _unsync: PhantomData,
62 });
63
64 // SAFETY: Initialisation occurs when raw list is in a stable memory location.
65 // SAFETY: All the nodes are removed upon dropping.
66 unsafe { Arc::<Self>::get_mut(&mut list).unwrap().raw.init() };
67
68 list
69 }
70
71 /// Returns `true` if the list contains an element equal to the given value.
72 pub fn contains<G>(&self, x: &T, guard: &G) -> bool
73 where
74 T: PartialEq,
75 G: RcuGuard<Flavor = F>,
76 {
77 self.iter_forward(guard).any(|item| item == x)
78 }
79
80 fn with_mutex<C, R>(&self, callback: C) -> Result<R>
81 where
82 C: FnOnce() -> R,
83 {
84 match self.mutex.lock() {
85 Err(_) => bail!("mutex of the list has been poisoned"),
86 Ok(guard) => {
87 let result = callback();
88 drop(guard);
89 Ok(result)
90 }
91 }
92 }
93
94 /// Adds an element to the back of a list.
95 ///
96 /// #### Note
97 ///
98 /// This operation may block.
99 pub fn push_back(&self, data: T) -> Result<()> {
100 self.with_mutex(|| {
101 // SAFETY: There is mutual exclusion between writers.
102 unsafe {
103 let node = RawNode::new(data);
104 self.raw.insert_back(node);
105 }
106 })
107 }
108
109 /// Adds an element to the front of a list.
110 ///
111 /// #### Note
112 ///
113 /// This operation may block.
114 pub fn push_front(&self, data: T) -> Result<()> {
115 self.with_mutex(|| {
116 // SAFETY: There is mutual exclusion between writers.
117 unsafe {
118 let node = RawNode::new(data);
119 self.raw.insert_front(node);
120 }
121 })
122 }
123
124 /// Removes an element from the back of a list.
125 ///
126 /// #### Note
127 ///
128 /// This operation may block.
129 pub fn pop_back(&self) -> Result<Option<Ref<T, F>>>
130 where
131 T: Send,
132 {
133 self.with_mutex(|| {
134 // SAFETY: There is mutual exclusion between writers.
135 // SAFETY: The RCU grace period is enforced using `Ref<T, F>`.
136 let node = unsafe { self.raw.remove_back() };
137
138 NonNull::new(node).map(Ref::new)
139 })
140 }
141
142 /// Removes an element from the fron of a list.
143 ///
144 /// #### Note
145 ///
146 /// This operation may block.
147 pub fn pop_front(&self) -> Result<Option<Ref<T, F>>>
148 where
149 T: Send,
150 {
151 self.with_mutex(|| {
152 // SAFETY: There is mutual exclusion between writers.
153 // SAFETY: The RCU grace period is enforced using `Ref<T, F>`.
154 let node = unsafe { self.raw.remove_front() };
155
156 NonNull::new(node).map(Ref::new)
157 })
158 }
159
160 /// Returns `true` if the list is empty.
161 ///
162 /// #### Note
163 ///
164 /// * This operation computes linearly in *O*(*1*) time.
165 pub fn is_empty(&self) -> bool {
166 self.raw.empty()
167 }
168
169 /// Provides a reference to the back element, or `None` if the list is empty.
170 pub fn back<'me, 'guard, G>(&'me self, guard: &'guard G) -> Option<&'guard T>
171 where
172 'me: 'guard,
173 G: RcuGuard<Flavor = F>,
174 {
175 let _ = guard;
176
177 // SAFETY: The RCU critical section is enforced.
178 // SAFETY: The node pointer can be converted to a reference.
179 unsafe { self.raw.get_back().as_ref() }.map(|r| r.deref())
180 }
181
182 /// Provides a reference to the front element, or `None` if the list is empty.
183 pub fn front<'me, 'guard, G>(&'me self, guard: &'guard G) -> Option<&'guard T>
184 where
185 'me: 'guard,
186 G: RcuGuard<Flavor = F>,
187 {
188 let _ = guard;
189
190 // SAFETY: The RCU critical section is enforced.
191 // SAFETY: The node pointer can be converted to a reference.
192 unsafe { self.raw.get_front().as_ref() }.map(|r| r.deref())
193 }
194
195 /// Returns an iterator over the list.
196 ///
197 /// The iterator yields all items from back to front.
198 pub fn iter_forward<'me, 'guard, G>(&'me self, guard: &'guard G) -> Iter<'guard, T, G, true>
199 where
200 'me: 'guard,
201 G: RcuGuard<Flavor = F>,
202 {
203 // SAFETY: The RCU critical section is enforced.
204 Iter::new(unsafe { RawIter::<T, true>::from_back(&self.raw) }, guard)
205 }
206
207 /// Returns an iterator over the list.
208 ///
209 /// The iterator yields all items from front to back.
210 pub fn iter_reverse<'me, 'guard, G>(&'me self, guard: &'guard G) -> Iter<'guard, T, G, false>
211 where
212 'me: 'guard,
213 G: RcuGuard,
214 {
215 // SAFETY: The RCU critical section is enforced.
216 Iter::new(unsafe { RawIter::<T, false>::from_front(&self.raw) }, guard)
217 }
218}
219
220/// #### Safety
221///
222/// An [`RcuList`] can be used to send `T` to another thread.
223unsafe impl<T, F> Send for RcuList<T, F>
224where
225 T: Send,
226 F: RcuFlavor,
227{
228}
229
230/// #### Safety
231///
232/// An [`RcuList`] can be used to share `T` between threads.
233unsafe impl<T, F> Sync for RcuList<T, F>
234where
235 T: Sync,
236 F: RcuFlavor,
237{
238}
239
240impl<T, F> Drop for RcuList<T, F> {
241 fn drop(&mut self) {
242 // SAFETY: The RCU grace period is not needed because there are no other readers.
243 while let Some(mut ptr) = NonNull::new(unsafe { self.raw.remove_back() }) {
244 drop(unsafe { Box::from_raw(ptr.as_mut()) });
245 }
246 }
247}