1use crate::rcu_ptr::{RcuPtr, RcuReadGuard};
6use crate::rcu_read_scope::RcuReadScope;
7use crate::state_machine::rcu_drop;
8use crate::subtle::RcuPtrRef;
9use std::sync::Arc;
10
11#[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 update_swap<'a>(&self, scope: &'a RcuReadScope, data: Arc<T>) -> Arc<T> {
57 let ptr = Self::into_ptr(data);
58 unsafe { self.replace_swap(scope, ptr) }
60 }
61
62 pub fn to_arc(&self) -> Arc<T> {
67 let scope = RcuReadScope::new();
68 let ptr = self.ptr.read(&scope);
69 unsafe { rcu_ptr_to_arc(ptr) }
72 }
73
74 fn into_ptr(data: Arc<T>) -> *mut T {
79 Arc::into_raw(data) as *mut T
80 }
81
82 unsafe fn replace(&self, ptr: *mut T) {
88 let old_ptr = self.ptr.replace(ptr);
89 let arc = unsafe { Arc::from_raw(old_ptr) };
90 rcu_drop(arc);
91 }
92
93 unsafe fn replace_swap<'a>(&self, scope: &'a RcuReadScope, ptr: *mut T) -> Arc<T> {
100 let old_ptr_ref = self.ptr.swap(scope, ptr);
101 let rcu_arc = unsafe { Arc::from_raw(old_ptr_ref.as_ptr()) };
103 let old_arc = rcu_arc.clone();
104 rcu_drop(rcu_arc);
105 old_arc
106 }
107}
108
109impl<T: Send + Sync + 'static> Drop for RcuArc<T> {
110 fn drop(&mut self) {
111 unsafe { self.replace(std::ptr::null_mut()) };
113 }
114}
115
116impl<T: Send + Sync + 'static> Clone for RcuArc<T> {
117 fn clone(&self) -> Self {
118 Self::new(self.to_arc())
119 }
120}
121
122impl<T: Send + Sync + 'static> From<Arc<T>> for RcuArc<T> {
123 fn from(data: Arc<T>) -> Self {
124 Self::new(data)
125 }
126}
127
128impl<T: Default + Send + Sync + 'static> Default for RcuArc<T> {
129 fn default() -> Self {
130 Self::new(Arc::new(T::default()))
131 }
132}
133
134pub unsafe fn rcu_ptr_to_arc<'a, T>(ptr: RcuPtrRef<'a, T>) -> Arc<T> {
140 let raw_ptr = ptr.as_ptr();
141 unsafe {
142 Arc::increment_strong_count(raw_ptr);
143 Arc::from_raw(raw_ptr)
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use crate::state_machine::rcu_synchronize;
151 use std::sync::atomic::{AtomicUsize, Ordering};
152
153 struct DropCounter {
154 value: usize,
155 drops: Arc<AtomicUsize>,
156 }
157
158 impl DropCounter {
159 pub fn new(value: usize) -> Arc<Self> {
160 Arc::new(Self { value, drops: Arc::new(AtomicUsize::new(0)) })
161 }
162 }
163
164 impl Drop for DropCounter {
165 fn drop(&mut self) {
166 self.drops.fetch_add(1, Ordering::Relaxed);
167 }
168 }
169
170 #[test]
171 fn test_rcu_arc_update() {
172 let object = DropCounter::new(42);
173 let drops = object.drops.clone();
174
175 let arc = RcuArc::from(object);
176 assert_eq!(arc.read().value, 42);
177 assert_eq!(drops.load(Ordering::Relaxed), 0);
178 arc.update(DropCounter::new(43));
179 assert_eq!(arc.read().value, 43);
180 assert_eq!(drops.load(Ordering::Relaxed), 0);
181
182 rcu_synchronize();
183 assert_eq!(drops.load(Ordering::Relaxed), 1);
184 }
185
186 #[test]
187 fn test_rcu_arc_update_swap() {
188 let object = DropCounter::new(42);
189 let drops = object.drops.clone();
190
191 let arc = RcuArc::from(object);
192 {
193 let scope = RcuReadScope::new();
194 let old_object = arc.update_swap(&scope, DropCounter::new(43));
195 assert_eq!(old_object.value, 42);
196 assert_eq!(arc.read().value, 43);
197 assert_eq!(drops.load(Ordering::Relaxed), 0);
198 }
199
200 rcu_synchronize();
201 assert_eq!(drops.load(Ordering::Relaxed), 1);
202 }
203}