fuchsia_rcu/
rcu_option_arc.rs1use crate::rcu_ptr::{RcuPtr, RcuReadGuard};
6use crate::state_machine::rcu_drop;
7use std::sync::Arc;
8
9#[derive(Debug)]
15pub struct RcuOptionArc<T: Send + Sync + 'static> {
16 ptr: RcuPtr<T>,
17}
18
19impl<T: Send + Sync + 'static> RcuOptionArc<T> {
20 pub fn new(data: Option<Arc<T>>) -> Self {
22 Self { ptr: RcuPtr::new(Self::into_ptr(data)) }
23 }
24
25 pub fn read(&self) -> Option<RcuReadGuard<T>> {
30 self.ptr.maybe_get()
31 }
32
33 pub fn update(&self, data: Option<Arc<T>>) {
38 let ptr = Self::into_ptr(data);
39 unsafe { self.replace(ptr) };
41 }
42
43 pub fn to_option_arc(&self) -> Option<Arc<T>> {
48 let guard = self.read()?;
49 let ptr = guard.as_ptr();
50 unsafe {
53 Arc::increment_strong_count(ptr);
54 Some(Arc::from_raw(ptr))
55 }
56 }
57
58 fn into_ptr(data: Option<Arc<T>>) -> *mut T {
63 match data {
64 Some(arc) => Arc::into_raw(arc) as *mut T,
65 None => std::ptr::null_mut(),
66 }
67 }
68
69 unsafe fn replace(&self, ptr: *mut T) {
75 let old_ptr = self.ptr.replace(ptr);
76 if !old_ptr.is_null() {
77 let arc = unsafe { Arc::from_raw(old_ptr) };
78 rcu_drop(arc);
79 }
80 }
81}
82
83impl<T: Send + Sync + 'static> Drop for RcuOptionArc<T> {
84 fn drop(&mut self) {
85 unsafe { self.replace(std::ptr::null_mut()) };
87 }
88}
89
90impl<T: Send + Sync + 'static> Clone for RcuOptionArc<T> {
91 fn clone(&self) -> Self {
92 Self::new(self.to_option_arc())
93 }
94}
95
96impl<T: Send + Sync + 'static> From<Option<Arc<T>>> for RcuOptionArc<T> {
97 fn from(data: Option<Arc<T>>) -> Self {
98 Self::new(data)
99 }
100}
101
102impl<T: Send + Sync + 'static> Default for RcuOptionArc<T> {
103 fn default() -> Self {
104 Self::new(None)
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::state_machine::rcu_synchronize;
112 use std::sync::atomic::{AtomicUsize, Ordering};
113
114 struct DropCounter {
115 value: usize,
116 drops: Arc<AtomicUsize>,
117 }
118
119 impl DropCounter {
120 pub fn new(value: usize) -> Arc<Self> {
121 Arc::new(Self { value, drops: Arc::new(AtomicUsize::new(0)) })
122 }
123 }
124
125 impl Drop for DropCounter {
126 fn drop(&mut self) {
127 self.drops.fetch_add(1, Ordering::Relaxed);
128 }
129 }
130
131 #[test]
132 fn test_rcu_option_arc() {
133 let object = DropCounter::new(42);
134 let drops = object.drops.clone();
135
136 let arc = RcuOptionArc::from(Some(object));
137 assert_eq!(arc.read().unwrap().value, 42);
138 assert_eq!(drops.load(Ordering::Relaxed), 0);
139 arc.update(Some(DropCounter::new(43)));
140 assert_eq!(arc.read().unwrap().value, 43);
141 assert_eq!(drops.load(Ordering::Relaxed), 0);
142
143 rcu_synchronize();
144 assert_eq!(drops.load(Ordering::Relaxed), 1);
145 }
146
147 #[test]
148 fn test_rcu_option_arc_none() {
149 let object = DropCounter::new(42);
150 let drops = object.drops.clone();
151
152 let arc = RcuOptionArc::from(Some(object));
153 assert_eq!(arc.read().unwrap().value, 42);
154 assert_eq!(drops.load(Ordering::Relaxed), 0);
155
156 arc.update(None);
157 assert!(arc.read().is_none());
158 assert_eq!(drops.load(Ordering::Relaxed), 0);
159
160 rcu_synchronize();
161 assert_eq!(drops.load(Ordering::Relaxed), 1);
162 }
163
164 #[test]
165 fn test_rcu_option_arc_default() {
166 let arc: RcuOptionArc<DropCounter> = RcuOptionArc::default();
167 assert!(arc.read().is_none());
168 }
169
170 #[test]
171 fn test_rcu_option_arc_to_option_arc_none() {
172 let arc: RcuOptionArc<DropCounter> = RcuOptionArc::default();
173 assert!(arc.to_option_arc().is_none());
174 }
175}