1use crate::rcu_ptr::{RcuPtr, RcuReadGuard};
6use crate::state_machine::rcu_drop;
7use std::sync::Arc;
8
9#[derive(Debug)]
15pub struct RcuArc<T: Send + Sync + 'static> {
16 ptr: RcuPtr<T>,
17}
18
19impl<T: Send + Sync + 'static> RcuArc<T> {
20 pub fn new(data: Arc<T>) -> Self {
22 Self { ptr: RcuPtr::new(Self::into_ptr(data)) }
23 }
24
25 pub fn read(&self) -> RcuReadGuard<T> {
30 self.ptr.get()
31 }
32
33 pub fn update(&self, data: Arc<T>) {
38 let ptr = Self::into_ptr(data);
39 unsafe { self.replace(ptr) };
41 }
42
43 pub fn to_arc(&self) -> Arc<T> {
48 let guard = self.read();
49 let ptr = guard.as_ptr();
50 unsafe {
53 Arc::increment_strong_count(ptr);
54 Arc::from_raw(ptr)
55 }
56 }
57
58 fn into_ptr(data: Arc<T>) -> *mut T {
63 Arc::into_raw(data) as *mut T
64 }
65
66 unsafe fn replace(&self, ptr: *mut T) {
72 let old_ptr = self.ptr.replace(ptr);
73 let arc = unsafe { Arc::from_raw(old_ptr) };
74 rcu_drop(arc);
75 }
76}
77
78impl<T: Send + Sync + 'static> Drop for RcuArc<T> {
79 fn drop(&mut self) {
80 unsafe { self.replace(std::ptr::null_mut()) };
82 }
83}
84
85impl<T: Send + Sync + 'static> Clone for RcuArc<T> {
86 fn clone(&self) -> Self {
87 Self::new(self.to_arc())
88 }
89}
90
91impl<T: Send + Sync + 'static> From<Arc<T>> for RcuArc<T> {
92 fn from(data: Arc<T>) -> Self {
93 Self::new(data)
94 }
95}
96
97impl<T: Default + Send + Sync + 'static> Default for RcuArc<T> {
98 fn default() -> Self {
99 Self::new(Arc::new(T::default()))
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use crate::state_machine::rcu_synchronize;
107 use std::sync::atomic::{AtomicUsize, Ordering};
108
109 struct DropCounter {
110 value: usize,
111 drops: Arc<AtomicUsize>,
112 }
113
114 impl DropCounter {
115 pub fn new(value: usize) -> Arc<Self> {
116 Arc::new(Self { value, drops: Arc::new(AtomicUsize::new(0)) })
117 }
118 }
119
120 impl Drop for DropCounter {
121 fn drop(&mut self) {
122 self.drops.fetch_add(1, Ordering::Relaxed);
123 }
124 }
125
126 #[test]
127 fn test_rcu_arc_update() {
128 let object = DropCounter::new(42);
129 let drops = object.drops.clone();
130
131 let arc = RcuArc::from(object);
132 assert_eq!(arc.read().value, 42);
133 assert_eq!(drops.load(Ordering::Relaxed), 0);
134 arc.update(DropCounter::new(43));
135 assert_eq!(arc.read().value, 43);
136 assert_eq!(drops.load(Ordering::Relaxed), 0);
137
138 rcu_synchronize();
139 assert_eq!(drops.load(Ordering::Relaxed), 1);
140 }
141}