Skip to main content

starnix_rcu/
rcu_atomic.rs

1// Copyright 2026 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 starnix_sync::Mutex;
6use starnix_types::atomic::{AsAtomic, AtomicOperations};
7use std::ops::{Deref, DerefMut};
8use std::sync::atomic::Ordering;
9
10#[derive(Debug)]
11pub struct RcuAtomic<T: AsAtomic> {
12    mutex: Mutex<T>,
13    atomic: T::Atomic,
14}
15
16impl<T: AsAtomic> RcuAtomic<T> {
17    pub fn new(value: T) -> Self {
18        Self { mutex: Mutex::new(value), atomic: T::Atomic::new(value) }
19    }
20
21    /// Read the value from the atomic without taking the lock.
22    pub fn read(&self) -> T {
23        self.atomic.load(Ordering::Relaxed)
24    }
25
26    /// Basic write operation: takes the mutex and updates both the mutex value and the atomic.
27    pub fn write(&self, value: T) {
28        let mut guard = self.mutex.lock();
29        *guard = value;
30        self.atomic.store(value, Ordering::Relaxed);
31    }
32
33    /// Takes the mutex and returns a guard that can be used to read and modify the value.
34    /// Updates are only committed to the atomic when `update` is called on the guard.
35    pub fn copy(&self) -> RcuAtomicGuard<'_, T> {
36        let guard = self.mutex.lock();
37        RcuAtomicGuard { parent: self, guard }
38    }
39}
40
41pub struct RcuAtomicGuard<'a, T: AsAtomic> {
42    parent: &'a RcuAtomic<T>,
43    guard: starnix_sync::MutexGuard<'a, T>,
44}
45
46impl<'a, T: AsAtomic> Deref for RcuAtomicGuard<'a, T> {
47    type Target = T;
48    fn deref(&self) -> &Self::Target {
49        &*self.guard
50    }
51}
52
53impl<'a, T: AsAtomic> DerefMut for RcuAtomicGuard<'a, T> {
54    fn deref_mut(&mut self) -> &mut Self::Target {
55        &mut *self.guard
56    }
57}
58
59impl<'a, T: AsAtomic> RcuAtomicGuard<'a, T> {
60    /// Consumes the guard, updates the atomic in `RcuAtomic` with the current value,
61    /// and drops the mutex guard.
62    pub fn update(self) {
63        let value = *self.guard;
64        self.parent.atomic.store(value, Ordering::Relaxed);
65        // guard dropped here
66    }
67}