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 self.to_weak().upgrade()
33 }
34
35 pub fn to_weak(&self) -> Weak<T> {
37 let scope = RcuReadScope::new();
38 let ptr = self.ptr.read(&scope).as_ptr();
39 if ptr.is_null() {
40 Weak::new()
41 } else {
42 unsafe {
47 let weak = ManuallyDrop::new(Weak::from_raw(ptr));
48 (*weak).clone()
49 }
50 }
51 }
52
53 pub fn ptr_eq(&self, other: &Weak<T>) -> bool {
55 let scope = RcuReadScope::new();
56 let ptr = self.ptr.read(&scope).as_ptr();
57 ptr as *const T == other.as_ptr()
58 }
59
60 pub fn update(&self, data: Weak<T>) {
65 let ptr = Self::into_ptr(data);
66 unsafe { self.replace(ptr) };
68 }
69
70 fn into_ptr(weak: Weak<T>) -> *mut T {
75 Weak::into_raw(weak) as *mut T
76 }
77
78 unsafe fn replace(&self, ptr: *mut T) {
85 let old_ptr = self.ptr.replace(ptr);
86 if !old_ptr.is_null() {
87 let weak = unsafe { Weak::from_raw(old_ptr) };
88 rcu_drop(weak);
89 }
90 }
91}
92
93impl<T: Send + Sync + 'static> Drop for RcuWeak<T> {
94 fn drop(&mut self) {
95 unsafe { self.replace(std::ptr::null_mut()) };
97 }
98}
99
100impl<T: Send + Sync + 'static> Clone for RcuWeak<T> {
101 fn clone(&self) -> Self {
102 Self::new(self.to_weak())
103 }
104}
105
106impl<T: Send + Sync + 'static> From<Weak<T>> for RcuWeak<T> {
107 fn from(weak: Weak<T>) -> Self {
108 Self::new(weak)
109 }
110}
111
112impl<T: Send + Sync + 'static> Default for RcuWeak<T> {
113 fn default() -> Self {
114 Self::new(Weak::new())
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use crate::state_machine::rcu_synchronize;
122 use std::sync::atomic::{AtomicUsize, Ordering};
123
124 struct DropCounter {
125 drops: Arc<AtomicUsize>,
126 }
127
128 impl DropCounter {
129 pub fn new() -> Arc<Self> {
130 Arc::new(Self { 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_weak_upgrade() {
142 let object = DropCounter::new();
143 let drops = object.drops.clone();
144
145 let weak = Arc::downgrade(&object);
146 let rcu_weak = RcuWeak::from(weak);
147
148 assert!(rcu_weak.upgrade().is_some());
149 assert_eq!(drops.load(Ordering::Relaxed), 0);
150
151 drop(object);
152 assert!(rcu_weak.upgrade().is_none());
153 assert_eq!(drops.load(Ordering::Relaxed), 1);
154 }
155
156 #[test]
157 fn test_rcu_weak_update() {
158 let object1 = DropCounter::new();
159 let drops1 = object1.drops.clone();
160 let rcu_weak = RcuWeak::from(Arc::downgrade(&object1));
161
162 let object2 = DropCounter::new();
163 let drops2 = object2.drops.clone();
164
165 rcu_weak.update(Arc::downgrade(&object2));
166 assert!(rcu_weak.upgrade().map_or(false, |obj| Arc::ptr_eq(&obj, &object2)));
167
168 rcu_synchronize();
171
172 drop(object1);
173 assert_eq!(drops1.load(Ordering::Relaxed), 1);
174
175 drop(object2);
176 assert_eq!(drops2.load(Ordering::Relaxed), 1);
177 }
178
179 #[test]
180 fn test_rcu_weak_ptr_eq() {
181 let object1 = DropCounter::new();
182 let weak1 = Arc::downgrade(&object1);
183 let rcu_weak = RcuWeak::from(weak1.clone());
184
185 let object2 = DropCounter::new();
186 let weak2 = Arc::downgrade(&object2);
187
188 assert!(rcu_weak.ptr_eq(&weak1));
189 assert!(!rcu_weak.ptr_eq(&weak2));
190
191 rcu_weak.update(weak2.clone());
192 assert!(!rcu_weak.ptr_eq(&weak1));
193 assert!(rcu_weak.ptr_eq(&weak2));
194 }
195}