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