Skip to main content

fuchsia_rcu_collections/
rcu_list.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![warn(unsafe_op_in_unsafe_fn)]
6
7use fuchsia_rcu::subtle::{RcuPtr, RcuPtrRef};
8use fuchsia_rcu::{RcuReadScope, rcu_drop};
9
10use crate::rcu_intrusive_list::{Link, RcuIntrusiveList, RcuIntrusiveListCursor, RcuListAdapter};
11
12/// An `RcuList` is a doubly-linked list that supports concurrent access via
13/// read-copy-update (RCU) synchronization.
14///
15/// An `RcuList` can be safely read by multiple readers, even while a writer
16/// is modifying the list. To read from the list, you will need to enter an
17/// `RcuReadScope`.
18///
19/// To modify the list, you will need to use some external synchronization,
20/// such as a `Mutex`, to exclude concurrent writers.
21#[derive(Debug)]
22pub struct RcuList<T: Send + Sync + 'static, A: RcuListAdapter<T>> {
23    list: RcuIntrusiveList<T, A>,
24}
25
26impl<T: Send + Sync + 'static, A: RcuListAdapter<T>> Default for RcuList<T, A> {
27    fn default() -> Self {
28        Self { list: RcuIntrusiveList::default() }
29    }
30}
31
32impl<T: Send + Sync + 'static, A: RcuListAdapter<T>> RcuList<T, A> {
33    /// Creates a new list with the given head and tail.
34    pub fn new(head: RcuPtr<Link>, tail: RcuPtr<Link>) -> Self {
35        Self { list: RcuIntrusiveList::new(head, tail) }
36    }
37
38    /// Pushes a new element to the front of the list.
39    ///
40    /// # Safety
41    ///
42    /// Requires external synchronization to exclude concurrent writers.
43    pub unsafe fn push_front<'a>(&self, scope: &'a RcuReadScope, data: T) -> RcuPtrRef<'a, T> {
44        let node = alloc(scope, data);
45        // SAFETY: Our caller promises to exclude concurrent writers.
46        unsafe {
47            self.list.push_front(scope, node);
48        }
49        node
50    }
51
52    /// Pushes a new element to the back of the list.
53    ///
54    /// # Safety
55    ///
56    /// Requires external synchronization to exclude concurrent writers.
57    pub unsafe fn push_back<'a>(&self, scope: &'a RcuReadScope, data: T) -> RcuPtrRef<'a, T> {
58        let node = alloc(scope, data);
59        // SAFETY: Our caller promises to exclude concurrent writers.
60        unsafe {
61            self.list.push_back(scope, node);
62        }
63        node
64    }
65
66    /// Appends another list to the end of this list.
67    ///
68    /// # Safety
69    ///
70    /// Requires external synchronization to exclude concurrent writers.
71    pub unsafe fn append(&self, scope: &RcuReadScope, other: Self) {
72        // SAFETY: Our caller promises to exclude concurrent writers.
73        unsafe {
74            let items = other.list.split_off(scope, 0);
75            self.list.append(scope, items);
76        }
77    }
78
79    /// Splits the list into two lists at the given position.
80    ///
81    /// If the given position is past the end of the list, returns an empty list.
82    ///
83    /// # Safety
84    ///
85    /// Requires external synchronization to exclude concurrent writers.
86    pub unsafe fn split_off(&self, scope: &RcuReadScope, pos: usize) -> Self {
87        // SAFETY: Our caller promises to exclude concurrent writers.
88        Self { list: unsafe { self.list.split_off(scope, pos) } }
89    }
90
91    /// Removes all elements from the list.
92    ///
93    /// Concurrent readers may continue to see the old value of the list until the RCU state machine
94    /// has made sufficient progress to ensure that no concurrent readers are holding read guards.
95    ///
96    /// # Safety
97    ///
98    /// Requires external synchronization to exclude concurrent writers.
99    pub unsafe fn clear(&self) {
100        let scope = RcuReadScope::new();
101        // SAFETY: Our caller promises to exclude concurrent writers.
102        unsafe { self.list.clear(&scope, deferred_dealloc) };
103    }
104
105    #[cfg(test)]
106    fn is_empty(&self) -> bool {
107        let scope = RcuReadScope::new();
108        self.list.is_empty(&scope)
109    }
110
111    /// Returns a cursor that can be used to traverse and modify the list.
112    ///
113    /// Concurrent readers may continue to see the old value of the list until the RCU state machine
114    /// has made sufficient progress to ensure that no concurrent readers are holding read guards.
115    pub fn cursor<'a>(&'a self, scope: &'a RcuReadScope) -> RcuListCursor<'a, T, A> {
116        RcuListCursor { cursor: self.list.cursor(scope) }
117    }
118
119    /// Returns an iterator over the elements in the list.
120    pub fn iter<'a>(&self, scope: &'a RcuReadScope) -> impl Iterator<Item = &'a T> {
121        self.list.iter(scope)
122    }
123}
124
125/// Allocates a new node.
126///
127/// The node must be deallocated using `deferred_dealloc`.
128fn alloc<T>(scope: &RcuReadScope, data: T) -> RcuPtrRef<'_, T> {
129    let ptr = Box::into_raw(Box::new(data));
130    // SAFETY: All nodes must be deallocated using `deferred_dealloc`, which defers their
131    // deallocation until all in-flight read operations have completed.
132    unsafe { RcuPtrRef::new(scope, ptr) }
133}
134
135/// Deallocates a node once all in-flight read operations have completed.
136///
137/// The node must have been allocated using `alloc`.
138fn deferred_dealloc<T>(node: RcuPtrRef<'_, T>)
139where
140    T: Send + Sync + 'static,
141{
142    // SAFETY: The node was allocated using `alloc`.
143    let value = unsafe { Box::from_raw(node.as_mut_ptr()) };
144    rcu_drop(value);
145}
146
147pub struct RcuListCursor<'a, T: Send + Sync + 'static, A: RcuListAdapter<T>> {
148    cursor: RcuIntrusiveListCursor<'a, T, A>,
149}
150
151impl<'a, T: Send + Sync + 'static, A: RcuListAdapter<T>> RcuListCursor<'a, T, A> {
152    /// Returns the element at the current cursor position.
153    pub fn current(&self) -> Option<&T> {
154        self.cursor.current()
155    }
156
157    /// Advances the cursor to the next element in the list.
158    pub fn advance(&mut self) {
159        self.cursor.advance();
160    }
161
162    /// Removes the element at the current cursor position.
163    ///
164    /// After calling `remove`, the cursor will be positioned at the next element in the list.
165    ///
166    /// Concurrent readers may continue to see this entry in the list until the RCU state machine
167    /// has made sufficient progress to ensure that no concurrent readers are holding read guards.
168    ///
169    /// # Safety
170    ///
171    /// Requires external synchronization to exclude concurrent writers.
172    pub unsafe fn remove(&mut self) -> RcuPtrRef<'a, T> {
173        let removed = unsafe { self.cursor.remove() };
174        deferred_dealloc(removed);
175        removed
176    }
177}
178
179impl<T: Send + Sync + 'static, A: RcuListAdapter<T>> Drop for RcuList<T, A> {
180    fn drop(&mut self) {
181        // SAFETY: The list is being dropped, so there are no concurrent readers.
182        unsafe { self.clear() };
183    }
184}
185
186#[cfg(test)]
187mod tests {
188    use crate::rcu_intrusive_list::{RcuListAdapter, rcu_list_adapter};
189
190    use super::*;
191    use fuchsia_rcu::rcu_synchronize;
192
193    #[derive(Debug)]
194    struct TestNode {
195        value: i64,
196        link: Link,
197    }
198
199    impl TestNode {
200        fn new(value: i64) -> Self {
201            Self { value, link: Default::default() }
202        }
203    }
204
205    impl RcuListAdapter<TestNode> for TestNode {
206        rcu_list_adapter!(TestNode, link);
207    }
208
209    #[test]
210    fn test_rcu_list_push_front() {
211        {
212            let list = RcuList::<TestNode, TestNode>::default();
213            let scope = RcuReadScope::new();
214            unsafe {
215                list.push_front(&scope, TestNode::new(1));
216                list.push_front(&scope, TestNode::new(2));
217                list.push_front(&scope, TestNode::new(3));
218            }
219
220            let mut cursor = list.cursor(&scope);
221            assert_eq!(cursor.current().map(|node| node.value), Some(3));
222            cursor.advance();
223            assert_eq!(cursor.current().map(|node| node.value), Some(2));
224            cursor.advance();
225            assert_eq!(cursor.current().map(|node| node.value), Some(1));
226            cursor.advance();
227            assert_eq!(cursor.current().map(|node| node.value), None);
228        }
229        rcu_synchronize();
230    }
231
232    #[test]
233    fn test_rcu_list_push_back() {
234        {
235            let list = RcuList::<TestNode, TestNode>::default();
236            let scope = RcuReadScope::new();
237            unsafe {
238                list.push_back(&scope, TestNode::new(1));
239                list.push_back(&scope, TestNode::new(2));
240                list.push_back(&scope, TestNode::new(3));
241            }
242
243            let mut cursor = list.cursor(&scope);
244            assert_eq!(cursor.current().map(|node| node.value), Some(1));
245            cursor.advance();
246            assert_eq!(cursor.current().map(|node| node.value), Some(2));
247            cursor.advance();
248            assert_eq!(cursor.current().map(|node| node.value), Some(3));
249            cursor.advance();
250            assert_eq!(cursor.current().map(|node| node.value), None);
251        }
252        rcu_synchronize();
253    }
254
255    #[test]
256    fn test_rcu_list_clear() {
257        {
258            let list = RcuList::<TestNode, TestNode>::default();
259            let scope = RcuReadScope::new();
260            unsafe {
261                list.push_back(&scope, TestNode::new(1));
262                list.push_back(&scope, TestNode::new(2));
263                list.push_back(&scope, TestNode::new(3));
264            }
265
266            unsafe { list.clear() };
267
268            let mut iter = list.iter(&scope);
269            assert_eq!(iter.next().map(|node| node.value), None);
270        }
271
272        rcu_synchronize();
273    }
274
275    #[test]
276    fn test_rcu_list_drop_clears_objects() {
277        use std::sync::Arc;
278        use std::sync::atomic::{AtomicUsize, Ordering};
279
280        #[derive(Debug)]
281        struct DropCounter {
282            _id: usize,
283            counter: Arc<AtomicUsize>,
284            link: Link,
285        }
286
287        impl RcuListAdapter<DropCounter> for DropCounter {
288            rcu_list_adapter!(DropCounter, link);
289        }
290
291        impl Drop for DropCounter {
292            fn drop(&mut self) {
293                self.counter.fetch_add(1, Ordering::SeqCst);
294            }
295        }
296
297        let drop_count = Arc::new(AtomicUsize::new(0));
298        {
299            let list = RcuList::<DropCounter, DropCounter>::default();
300            let scope = RcuReadScope::new();
301            unsafe {
302                list.push_back(
303                    &scope,
304                    DropCounter {
305                        _id: 1,
306                        counter: Arc::clone(&drop_count),
307                        link: Default::default(),
308                    },
309                );
310                list.push_back(
311                    &scope,
312                    DropCounter {
313                        _id: 2,
314                        counter: Arc::clone(&drop_count),
315                        link: Default::default(),
316                    },
317                );
318                list.push_back(
319                    &scope,
320                    DropCounter {
321                        _id: 3,
322                        counter: Arc::clone(&drop_count),
323                        link: Default::default(),
324                    },
325                );
326            }
327            assert_eq!(drop_count.load(Ordering::SeqCst), 0);
328        }
329
330        rcu_synchronize();
331
332        // The list is dropped here, so the contained objects should also be dropped.
333        assert_eq!(drop_count.load(Ordering::SeqCst), 3);
334    }
335
336    #[test]
337    fn test_rcu_list_iter() {
338        {
339            let list = RcuList::<TestNode, TestNode>::default();
340            let scope = RcuReadScope::new();
341            unsafe {
342                list.push_back(&scope, TestNode::new(1));
343                list.push_back(&scope, TestNode::new(2));
344                list.push_back(&scope, TestNode::new(3));
345            }
346
347            let mut iter = list.iter(&scope);
348            assert_eq!(iter.next().map(|node| node.value), Some(1));
349            assert_eq!(iter.next().map(|node| node.value), Some(2));
350            assert_eq!(iter.next().map(|node| node.value), Some(3));
351            assert_eq!(iter.next().map(|node| node.value), None);
352        }
353
354        rcu_synchronize();
355    }
356
357    #[test]
358    fn test_rcu_list_remove() {
359        {
360            let list = RcuList::<TestNode, TestNode>::default();
361            let scope = RcuReadScope::new();
362            unsafe {
363                list.push_back(&scope, TestNode::new(1));
364                list.push_back(&scope, TestNode::new(2));
365                list.push_back(&scope, TestNode::new(3));
366            }
367
368            let mut cursor = list.cursor(&scope);
369            cursor.advance(); // current is 2
370            assert_eq!(cursor.current().map(|node| node.value), Some(2));
371            unsafe { cursor.remove() };
372
373            let mut iter = list.iter(&scope);
374            assert_eq!(iter.next().map(|node| node.value), Some(1));
375            assert_eq!(iter.next().map(|node| node.value), Some(3));
376            assert_eq!(iter.next().map(|node| node.value), None);
377
378            // Test removing head
379            let mut cursor = list.cursor(&scope);
380            unsafe { cursor.remove() };
381
382            let mut iter = list.iter(&scope);
383            assert_eq!(iter.next().map(|node| node.value), Some(3));
384            assert_eq!(iter.next().map(|node| node.value), None);
385
386            // Test removing tail
387            let mut cursor = list.cursor(&scope);
388            unsafe { cursor.remove() };
389
390            let mut iter = list.iter(&scope);
391            assert_eq!(iter.next().map(|node| node.value), None);
392        }
393
394        rcu_synchronize();
395    }
396
397    #[test]
398    fn test_rcu_list_remove_all() {
399        {
400            let list = RcuList::<TestNode, TestNode>::default();
401            let scope = RcuReadScope::new();
402            unsafe {
403                list.push_back(&scope, TestNode::new(1));
404                list.push_back(&scope, TestNode::new(2));
405                list.push_back(&scope, TestNode::new(3));
406            }
407
408            let mut cursor = list.cursor(&scope);
409            while cursor.current().is_some() {
410                unsafe { cursor.remove() };
411            }
412
413            assert_eq!(list.iter(&scope).next().map(|node| node.value), None);
414        }
415
416        rcu_synchronize();
417    }
418
419    #[test]
420    fn test_rcu_list_append() {
421        {
422            let list1 = RcuList::<TestNode, TestNode>::default();
423            let scope = RcuReadScope::new();
424            unsafe {
425                list1.push_back(&scope, TestNode::new(1));
426                list1.push_back(&scope, TestNode::new(2));
427            }
428
429            let list2 = RcuList::<TestNode, TestNode>::default();
430            unsafe {
431                list2.push_back(&scope, TestNode::new(3));
432                list2.push_back(&scope, TestNode::new(4));
433            }
434
435            unsafe { list1.append(&scope, list2) };
436
437            let mut iter = list1.iter(&scope);
438            assert_eq!(iter.next().map(|node| node.value), Some(1));
439            assert_eq!(iter.next().map(|node| node.value), Some(2));
440            assert_eq!(iter.next().map(|node| node.value), Some(3));
441            assert_eq!(iter.next().map(|node| node.value), Some(4));
442            assert_eq!(iter.next().map(|node| node.value), None);
443        }
444
445        rcu_synchronize();
446    }
447
448    #[test]
449    fn test_rcu_list_append_empty() {
450        // Append to an empty list.
451        {
452            let list1 = RcuList::<TestNode, TestNode>::default();
453            let list2 = RcuList::<TestNode, TestNode>::default();
454            let scope = RcuReadScope::new();
455            unsafe {
456                list2.push_back(&scope, TestNode::new(1));
457                list2.push_back(&scope, TestNode::new(2));
458            }
459            unsafe { list1.append(&scope, list2) };
460
461            let mut iter = list1.iter(&scope);
462            assert_eq!(iter.next().map(|node| node.value), Some(1));
463            assert_eq!(iter.next().map(|node| node.value), Some(2));
464            assert_eq!(iter.next().map(|node| node.value), None);
465        }
466        rcu_synchronize();
467
468        // Append an empty list.
469        {
470            let list1 = RcuList::<TestNode, TestNode>::default();
471            let scope = RcuReadScope::new();
472            unsafe {
473                list1.push_back(&scope, TestNode::new(1));
474                list1.push_back(&scope, TestNode::new(2));
475            }
476            let list2 = RcuList::<TestNode, TestNode>::default();
477            unsafe { list1.append(&scope, list2) };
478
479            let mut iter = list1.iter(&scope);
480            assert_eq!(iter.next().map(|node| node.value), Some(1));
481            assert_eq!(iter.next().map(|node| node.value), Some(2));
482            assert_eq!(iter.next().map(|node| node.value), None);
483        }
484        rcu_synchronize();
485    }
486
487    #[test]
488    fn test_rcu_list_is_empty() {
489        {
490            let list = RcuList::<TestNode, TestNode>::default();
491            let scope = RcuReadScope::new();
492            assert!(list.is_empty());
493
494            unsafe {
495                list.push_back(&scope, TestNode::new(1));
496            }
497            assert!(!list.is_empty());
498
499            unsafe {
500                list.clear();
501            }
502            assert!(list.is_empty());
503        }
504
505        rcu_synchronize();
506    }
507
508    #[test]
509    fn test_rcu_list_split_off() {
510        // Split at the beginning.
511        {
512            let list = RcuList::<TestNode, TestNode>::default();
513            let scope = RcuReadScope::new();
514            unsafe {
515                list.push_back(&scope, TestNode::new(1));
516                list.push_back(&scope, TestNode::new(2));
517                list.push_back(&scope, TestNode::new(3));
518            }
519
520            let new_list = unsafe { list.split_off(&scope, 0) };
521
522            assert!(list.is_empty());
523            let mut new_iter = new_list.iter(&scope);
524            assert_eq!(new_iter.next().map(|node| node.value), Some(1));
525            assert_eq!(new_iter.next().map(|node| node.value), Some(2));
526            assert_eq!(new_iter.next().map(|node| node.value), Some(3));
527            assert_eq!(new_iter.next().map(|node| node.value), None);
528        }
529        rcu_synchronize();
530
531        // Split in the middle.
532        {
533            let list = RcuList::<TestNode, TestNode>::default();
534            let scope = RcuReadScope::new();
535            unsafe {
536                list.push_back(&scope, TestNode::new(1));
537                list.push_back(&scope, TestNode::new(2));
538                list.push_back(&scope, TestNode::new(3));
539                list.push_back(&scope, TestNode::new(4));
540            }
541
542            let new_list = unsafe { list.split_off(&scope, 2) };
543
544            let mut iter = list.iter(&scope);
545            assert_eq!(iter.next().map(|node| node.value), Some(1));
546            assert_eq!(iter.next().map(|node| node.value), Some(2));
547            assert_eq!(iter.next().map(|node| node.value), None);
548
549            let mut new_iter = new_list.iter(&scope);
550            assert_eq!(new_iter.next().map(|node| node.value), Some(3));
551            assert_eq!(new_iter.next().map(|node| node.value), Some(4));
552            assert_eq!(new_iter.next().map(|node| node.value), None);
553        }
554        rcu_synchronize();
555
556        // Split at the last element.
557        {
558            let list = RcuList::<TestNode, TestNode>::default();
559            let scope = RcuReadScope::new();
560            unsafe {
561                list.push_back(&scope, TestNode::new(1));
562                list.push_back(&scope, TestNode::new(2));
563                list.push_back(&scope, TestNode::new(3));
564            }
565
566            let new_list = unsafe { list.split_off(&scope, 2) };
567
568            let mut iter = list.iter(&scope);
569            assert_eq!(iter.next().map(|node| node.value), Some(1));
570            assert_eq!(iter.next().map(|node| node.value), Some(2));
571            assert_eq!(iter.next().map(|node| node.value), None);
572
573            let mut new_iter = new_list.iter(&scope);
574            assert_eq!(new_iter.next().map(|node| node.value), Some(3));
575            assert_eq!(new_iter.next().map(|node| node.value), None);
576        }
577        rcu_synchronize();
578
579        // Split one past the last element.
580        {
581            let list = RcuList::<TestNode, TestNode>::default();
582            let scope = RcuReadScope::new();
583            unsafe {
584                list.push_back(&scope, TestNode::new(1));
585                list.push_back(&scope, TestNode::new(2));
586                list.push_back(&scope, TestNode::new(3));
587            }
588
589            let new_list = unsafe { list.split_off(&scope, 3) };
590
591            let mut iter = list.iter(&scope);
592            assert_eq!(iter.next().map(|node| node.value), Some(1));
593            assert_eq!(iter.next().map(|node| node.value), Some(2));
594            assert_eq!(iter.next().map(|node| node.value), Some(3));
595            assert_eq!(iter.next().map(|node| node.value), None);
596
597            assert!(new_list.is_empty());
598        }
599        rcu_synchronize();
600
601        // Split far past the end of the list.
602        {
603            let list = RcuList::<TestNode, TestNode>::default();
604            let scope = RcuReadScope::new();
605            unsafe {
606                list.push_back(&scope, TestNode::new(1));
607                list.push_back(&scope, TestNode::new(2));
608                list.push_back(&scope, TestNode::new(3));
609            }
610
611            let new_list = unsafe { list.split_off(&scope, 10) };
612
613            let mut iter = list.iter(&scope);
614            assert_eq!(iter.next().map(|node| node.value), Some(1));
615            assert_eq!(iter.next().map(|node| node.value), Some(2));
616            assert_eq!(iter.next().map(|node| node.value), Some(3));
617            assert_eq!(iter.next().map(|node| node.value), None);
618
619            assert!(new_list.is_empty());
620        }
621        rcu_synchronize();
622    }
623}