1use crate::rcu_ptr::RcuPtr;
6use crate::rcu_read_scope::RcuReadScope;
7use crate::state_machine::rcu_drop;
8use std::mem::ManuallyDrop;
9use std::sync::{Arc, Weak};
10
11#[derive(Debug)]
17pub struct RcuWeak<T: Send + Sync + 'static> {
18 ptr: RcuPtr<T>,
19}
20
21impl<T: Send + Sync + 'static> RcuWeak<T> {
22 pub fn new(data: Weak<T>) -> Self {
24 Self { ptr: RcuPtr::new(Self::into_ptr(data)) }
25 }
26
27 pub fn upgrade(&self) -> Option<Arc<T>> {
32 let scope = RcuReadScope::new();
33 let ptr = self.ptr.read(&scope);
34 unsafe { crate::subtle::rcu_ptr_upgrade(ptr) }
37 }
38
39 pub fn to_weak(&self) -> Weak<T> {
41 self.with_weak(&RcuReadScope::new(), |w| w.clone())
42 }
43
44 pub fn ptr_eq(&self, other: &Weak<T>) -> bool {
46 let scope = RcuReadScope::new();
47 let ptr = self.ptr.read(&scope).as_ptr();
48 ptr as *const T == other.as_ptr()
49 }
50
51 pub fn update(&self, data: Weak<T>) {
56 let ptr = Self::into_ptr(data);
57 unsafe { self.replace(ptr) };
59 }
60
61 pub fn strong_count(&self, scope: &RcuReadScope) -> usize {
63 self.with_weak(scope, |w| w.strong_count())
64 }
65
66 fn into_ptr(weak: Weak<T>) -> *mut T {
71 Weak::into_raw(weak) as *mut T
72 }
73
74 unsafe fn replace(&self, ptr: *mut T) {
81 let old_ptr = self.ptr.replace(ptr);
82 if !old_ptr.is_null() {
83 let weak = unsafe { Weak::from_raw(old_ptr) };
84 rcu_drop(weak);
85 }
86 }
87
88 fn with_weak<A>(&self, scope: &RcuReadScope, f: impl FnOnce(&Weak<T>) -> A) -> A {
94 let ptr = self.ptr.read(scope).as_ptr();
95 if ptr.is_null() {
96 f(&Weak::new())
97 } else {
98 unsafe {
103 let weak = ManuallyDrop::new(Weak::from_raw(ptr));
104 f(&*weak)
105 }
106 }
107 }
108}
109
110impl<T: Send + Sync + 'static> Drop for RcuWeak<T> {
111 fn drop(&mut self) {
112 unsafe { self.replace(std::ptr::null_mut()) };
114 }
115}
116
117impl<T: Send + Sync + 'static> Clone for RcuWeak<T> {
118 fn clone(&self) -> Self {
119 Self::new(self.to_weak())
120 }
121}
122
123impl<T: Send + Sync + 'static> From<Weak<T>> for RcuWeak<T> {
124 fn from(weak: Weak<T>) -> Self {
125 Self::new(weak)
126 }
127}
128
129impl<T: Send + Sync + 'static> Default for RcuWeak<T> {
130 fn default() -> Self {
131 Self::new(Weak::new())
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use crate::state_machine::rcu_run_callbacks;
139 use std::sync::atomic::{AtomicUsize, Ordering};
140
141 struct DropCounter {
142 drops: Arc<AtomicUsize>,
143 }
144
145 impl DropCounter {
146 pub fn new() -> Arc<Self> {
147 Arc::new(Self { drops: Arc::new(AtomicUsize::new(0)) })
148 }
149 }
150
151 impl Drop for DropCounter {
152 fn drop(&mut self) {
153 self.drops.fetch_add(1, Ordering::Relaxed);
154 }
155 }
156
157 #[test]
158 fn test_rcu_weak_upgrade() {
159 let object = DropCounter::new();
160 let drops = object.drops.clone();
161
162 let weak = Arc::downgrade(&object);
163 let rcu_weak = RcuWeak::from(weak);
164
165 assert!(rcu_weak.upgrade().is_some());
166 assert_eq!(drops.load(Ordering::Relaxed), 0);
167
168 drop(object);
169 assert!(rcu_weak.upgrade().is_none());
170 assert_eq!(drops.load(Ordering::Relaxed), 1);
171 }
172
173 #[test]
174 fn test_rcu_weak_update() {
175 let object1 = DropCounter::new();
176 let drops1 = object1.drops.clone();
177 let rcu_weak = RcuWeak::from(Arc::downgrade(&object1));
178
179 let object2 = DropCounter::new();
180 let drops2 = object2.drops.clone();
181
182 rcu_weak.update(Arc::downgrade(&object2));
183 assert!(rcu_weak.upgrade().map_or(false, |obj| Arc::ptr_eq(&obj, &object2)));
184
185 rcu_run_callbacks();
188
189 drop(object1);
190 assert_eq!(drops1.load(Ordering::Relaxed), 1);
191
192 drop(object2);
193 assert_eq!(drops2.load(Ordering::Relaxed), 1);
194 }
195
196 #[test]
197 fn test_rcu_weak_ptr_eq() {
198 let object1 = DropCounter::new();
199 let weak1 = Arc::downgrade(&object1);
200 let rcu_weak = RcuWeak::from(weak1.clone());
201
202 let object2 = DropCounter::new();
203 let weak2 = Arc::downgrade(&object2);
204
205 assert!(rcu_weak.ptr_eq(&weak1));
206 assert!(!rcu_weak.ptr_eq(&weak2));
207
208 rcu_weak.update(weak2.clone());
209 assert!(!rcu_weak.ptr_eq(&weak1));
210 assert!(rcu_weak.ptr_eq(&weak2));
211 }
212
213 #[test]
214 fn test_rcu_weak_strong_count() {
215 let scope = RcuReadScope::new();
216 let rcu_weak = RcuWeak::<DropCounter>::default();
217 assert_eq!(rcu_weak.strong_count(&scope), 0);
218
219 let object = DropCounter::new();
220 rcu_weak.update(Arc::downgrade(&object));
221 assert_eq!(rcu_weak.strong_count(&scope), 1);
222
223 drop(object);
224 assert_eq!(rcu_weak.strong_count(&scope), 0);
225 }
226}