Skip to main content

fuchsia_rcu/
rcu_box.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
5use crate::rcu_ptr::{RcuPtr, RcuReadGuard};
6use crate::rcu_read_scope::RcuReadScope;
7use crate::state_machine::rcu_drop;
8
9use crate::rcu_droppable::RcuDroppable;
10
11/// An RCU (Read-Copy-Update) wrapper around a `Box`.
12///
13/// The Box can be dereferenced from multiple threads concurrently without blocking.
14/// When the Box is replaced, reads may continue to see the old Box pointer for some period of time.
15#[derive(Debug)]
16pub struct RcuBox<T: RcuDroppable + Sync> {
17    ptr: RcuPtr<T>,
18}
19
20impl<T: RcuDroppable + Sync> RcuBox<T> {
21    /// Create a new RCU wrapped Box from a value.
22    pub fn new(data: T) -> Self {
23        Self::from(Box::new(data))
24    }
25
26    /// Read the value of the wrapped Box.
27    ///
28    /// The object referenced by the Box will remain valid until the `RcuReadGuard` is dropped.
29    /// However, another thread running concurrently might see a different object.
30    pub fn read(&self) -> RcuReadGuard<T> {
31        self.ptr.get()
32    }
33
34    /// Returns a reference to the value of the wrapped Box.
35    ///
36    /// The object referenced by the Box will remain valid until the `RcuReadScope` is dropped.
37    /// However, another thread running concurrently might see a different object.
38    pub fn as_ref<'a>(&self, scope: &'a RcuReadScope) -> &'a T {
39        self.ptr.read(scope).as_ref().unwrap()
40    }
41
42    /// Write a new Boxed value to the RCU wrapper.
43    ///
44    /// Concurrent readers may continue to see the old boxed object until the RCU state machine has
45    /// made sufficient progress to ensure that no concurrent readers are holding read guards.
46    pub fn update(&self, data: T) {
47        let ptr = Box::into_raw(Box::new(data));
48        // SAFETY: We can pass `Box::into_raw` to `Self::replace`.
49        unsafe { self.replace(ptr) };
50    }
51
52    /// Replace the Box pointer in the RCU wrapper with a new pointer.
53    ///
54    /// # Safety
55    ///
56    /// The pointer must have been created by `Box::into_raw` or from `std::ptr::null_mut`.
57    unsafe fn replace(&self, ptr: *mut T) {
58        let old_ptr = self.ptr.replace(ptr);
59        let object = unsafe { Box::from_raw(old_ptr) };
60        rcu_drop(object);
61    }
62}
63
64impl<T: Clone + RcuDroppable + Sync> RcuBox<T> {
65    /// Returns a clone of the value of the wrapped Box.
66    ///
67    /// The clone is detached from any RCU read scope.
68    pub fn cloned(&self) -> T {
69        self.as_ref(&RcuReadScope::new()).clone()
70    }
71}
72
73impl<T: RcuDroppable + Sync> Drop for RcuBox<T> {
74    fn drop(&mut self) {
75        // SAFETY: We can pass `std::ptr::null_mut` to `Self::replace`.
76        unsafe { self.replace(std::ptr::null_mut()) };
77    }
78}
79
80impl<T: Default + RcuDroppable + Sync> Default for RcuBox<T> {
81    fn default() -> Self {
82        Self::new(T::default())
83    }
84}
85
86impl<T: Clone + RcuDroppable + Sync> Clone for RcuBox<T> {
87    fn clone(&self) -> Self {
88        let value = self.read();
89        Self::new(value.clone())
90    }
91}
92
93impl<T: RcuDroppable + Sync> From<Box<T>> for RcuBox<T> {
94    fn from(value: Box<T>) -> Self {
95        Self { ptr: RcuPtr::new(Box::into_raw(value)) }
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use crate::state_machine::rcu_run_callbacks;
103    use std::ops::Deref;
104
105    #[test]
106    fn test_rcu_cell() {
107        let value = RcuBox::new(42);
108        assert_eq!(value.read().deref(), &42);
109    }
110
111    #[test]
112    fn test_rcu_cell_set_deferred() {
113        let value = RcuBox::new(42);
114        value.update(43);
115        assert_eq!(value.read().deref(), &43);
116        rcu_run_callbacks();
117    }
118
119    #[test]
120    fn test_rcu_cell_drop() {
121        let value = RcuBox::new(42);
122        drop(value);
123    }
124}