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}