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