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