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