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