1use crate::rcu_ptr::RcuPtr;
6use crate::rcu_read_scope::RcuReadScope;
7use crate::state_machine::rcu_drop;
8use crate::subtle::rcu_ptr_upgrade;
9use std::sync::Arc;
10
11#[derive(Debug)]
27pub struct RcuArc<T: Send + Sync + 'static> {
28 ptr: RcuPtr<T>,
29}
30
31impl<T: Send + Sync + 'static> RcuArc<T> {
32 pub fn new(data: impl Into<Option<Arc<T>>>) -> Self {
34 Self { ptr: RcuPtr::new(Self::into_ptr(data.into())) }
35 }
36
37 pub fn upgrade(&self) -> Option<Arc<T>> {
41 let scope = RcuReadScope::new();
42 loop {
43 let ptr = self.ptr.read(&scope);
44 if ptr.is_null() {
46 return None;
47 }
48 if let Some(arc) = unsafe { rcu_ptr_upgrade(ptr) } {
55 return Some(arc);
56 }
57 }
58 }
59
60 pub fn update(&self, data: impl Into<Option<Arc<T>>>) {
65 let ptr = Self::into_ptr(data.into());
66 unsafe { self.replace(ptr) };
68 }
69
70 pub fn is_some(&self) -> bool {
72 self.upgrade().is_some()
73 }
74
75 pub fn is_none(&self) -> bool {
77 self.upgrade().is_none()
78 }
79
80 fn into_ptr(data: Option<Arc<T>>) -> *mut T {
82 match data {
83 Some(arc) => Arc::into_raw(arc) as *mut T,
84 None => std::ptr::null_mut(),
85 }
86 }
87
88 unsafe fn replace(&self, ptr: *mut T) {
94 let old_ptr = self.ptr.replace(ptr);
95 if !old_ptr.is_null() {
96 let old_arc = unsafe { Arc::from_raw(old_ptr) };
99 let weak = Arc::downgrade(&old_arc);
100 drop(old_arc);
101 rcu_drop(weak);
102 }
103 }
104}
105
106impl<T: Send + Sync + 'static> Drop for RcuArc<T> {
107 fn drop(&mut self) {
108 unsafe { self.replace(std::ptr::null_mut()) };
110 }
111}
112
113impl<T: Send + Sync + 'static> Clone for RcuArc<T> {
114 fn clone(&self) -> Self {
115 Self::new(self.upgrade())
116 }
117}
118
119impl<T: Send + Sync + 'static> From<Option<Arc<T>>> for RcuArc<T> {
120 fn from(data: Option<Arc<T>>) -> Self {
121 Self::new(data)
122 }
123}
124
125impl<T: Send + Sync + 'static> From<Arc<T>> for RcuArc<T> {
126 fn from(data: Arc<T>) -> Self {
127 Self::new(Some(data))
128 }
129}
130
131impl<T: Send + Sync + 'static> Default for RcuArc<T> {
132 fn default() -> Self {
133 Self::new(None)
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140 use crate::state_machine::rcu_run_callbacks;
141 use std::sync::atomic::{AtomicUsize, Ordering};
142
143 struct DropCounter {
145 value: usize,
146 drops: Arc<AtomicUsize>,
147 }
148
149 impl DropCounter {
150 pub fn new(value: usize, drops: Arc<AtomicUsize>) -> Arc<Self> {
151 Arc::new(Self { value, drops })
152 }
153 }
154
155 impl Drop for DropCounter {
156 fn drop(&mut self) {
157 self.drops.fetch_add(1, Ordering::Relaxed);
158 }
159 }
160
161 #[test]
162 fn test_arc_update_and_synchronous_drop() {
163 let drops = Arc::new(AtomicUsize::new(0));
165 let arc = RcuArc::new(Some(DropCounter::new(42, drops.clone())));
166
167 assert!(arc.is_some());
168 assert_eq!(arc.upgrade().unwrap().value, 42);
169 assert_eq!(drops.load(Ordering::Relaxed), 0);
170
171 arc.update(Some(DropCounter::new(43, drops.clone())));
172 assert_eq!(arc.upgrade().unwrap().value, 43);
173 assert_eq!(drops.load(Ordering::Relaxed), 1, "Drop must execute synchronously on update");
174
175 arc.update(None);
176 assert!(arc.is_none());
177 assert_eq!(drops.load(Ordering::Relaxed), 2, "Drop must execute synchronously on reset");
178
179 rcu_run_callbacks();
180 assert_eq!(drops.load(Ordering::Relaxed), 2);
181 }
182
183 #[test]
184 fn test_arc_default() {
185 let arc = RcuArc::<DropCounter>::default();
186 assert!(arc.is_none());
187 assert!(arc.upgrade().is_none());
188 }
189
190 #[test]
191 fn test_arc_clone() {
192 let drops = Arc::new(AtomicUsize::new(0));
193 let arc1 = RcuArc::new(Some(DropCounter::new(100, drops.clone())));
194 let arc2 = arc1.clone();
195
196 assert_eq!(arc1.upgrade().unwrap().value, 100);
197 assert_eq!(arc2.upgrade().unwrap().value, 100);
198
199 drop(arc1);
200 assert_eq!(drops.load(Ordering::Relaxed), 0);
202
203 drop(arc2);
204 assert_eq!(drops.load(Ordering::Relaxed), 1);
205 }
206}