rcu_cell/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3
4extern crate alloc;
5
6mod link;
7mod rcu_cell;
8mod rcu_weak;
9
10pub use rcu_cell::RcuCell;
11pub use rcu_weak::RcuWeak;
12
13// we only support 64-bit platform
14const _: () = assert!(usize::MAX.count_ones() == 64);
15const _: () = assert!(core::mem::size_of::<*const ()>() == 8);
16
17use alloc::sync::Arc;
18
19pub trait ArcPointer<T> {
20    fn as_ptr(&self) -> *const T;
21    fn into_raw(self) -> *const T;
22    /// # Safety
23    /// you must ensure the pointer is valid
24    unsafe fn from_raw(ptr: *const T) -> Self;
25}
26
27impl<T> ArcPointer<T> for Option<Arc<T>> {
28    fn as_ptr(&self) -> *const T {
29        match self {
30            Some(v) => Arc::as_ptr(v),
31            None => core::ptr::null(),
32        }
33    }
34
35    fn into_raw(self) -> *const T {
36        match self {
37            Some(v) => Arc::into_raw(v),
38            None => core::ptr::null(),
39        }
40    }
41
42    unsafe fn from_raw(ptr: *const T) -> Self {
43        (!ptr.is_null()).then(|| Arc::from_raw(ptr))
44    }
45}
46
47#[cfg(test)]
48mod test {
49    use super::RcuCell;
50    use alloc::sync::Arc;
51    use core::sync::atomic::{AtomicUsize, Ordering};
52
53    #[test]
54    fn test_default() {
55        let x = RcuCell::<u32>::default();
56        assert!(x.read().is_none());
57    }
58
59    #[test]
60    fn simple_drop() {
61        static REF: AtomicUsize = AtomicUsize::new(0);
62        struct Foo(usize);
63        impl Foo {
64            fn new(data: usize) -> Self {
65                REF.fetch_add(data, Ordering::Relaxed);
66                Foo(data)
67            }
68        }
69        impl Drop for Foo {
70            fn drop(&mut self) {
71                REF.fetch_sub(self.0, Ordering::Relaxed);
72            }
73        }
74        let a = RcuCell::new(Foo::new(10));
75        let b = a.read().unwrap();
76        assert_eq!(REF.load(Ordering::Relaxed), 10);
77        drop(b);
78        assert_eq!(REF.load(Ordering::Relaxed), 10);
79        drop(a);
80        assert_eq!(REF.load(Ordering::Relaxed), 0);
81    }
82
83    #[test]
84    fn single_thread() {
85        let t = RcuCell::new(Some(10));
86        let x = t.read();
87        let y = t.read();
88        t.take();
89        let z = t.read();
90        let a = z.clone();
91        drop(t); // t can be dropped before reader
92        assert_eq!(x.map(|v| *v), Some(10));
93        assert_eq!(y.map(|v| *v), Some(10));
94        assert_eq!(z.map(|v| *v), None);
95        assert_eq!(a.map(|v| *v), None);
96    }
97
98    #[test]
99    fn single_thread_clone() {
100        let t = Arc::new(RcuCell::new(Some(10)));
101        let t1 = t.clone();
102        assert_eq!(t1.read().map(|v| *v), Some(10));
103        t1.write(5);
104        assert_eq!(t.read().map(|v| *v), Some(5));
105    }
106
107    #[test]
108    fn test_rcu_update() {
109        let t = RcuCell::new(Some(10));
110        let old = t.update(|v| v.map(|x| *x + 1));
111        assert_eq!(t.read().map(|v| *v), Some(11));
112        assert_eq!(old.map(|v| *v), Some(10));
113        let old = t.update(|v| match v {
114            Some(x) if *x == 11 => None,
115            _ => Some(42),
116        });
117        assert!(t.read().is_none());
118        assert_eq!(old.map(|v| *v), Some(11));
119    }
120
121    #[test]
122    fn test_is_none() {
123        let t = RcuCell::new(10);
124        assert!(!t.is_none());
125        t.take();
126        assert!(t.is_none());
127    }
128
129    #[test]
130    fn test_clone_rcu_cell() {
131        let t = Arc::new(RcuCell::new(Some(10)));
132        let t1 = t.clone();
133        let t2 = t.clone();
134        let t3 = t.clone();
135        t1.write(11);
136        drop(t1);
137        assert_eq!(t.read().map(|v| *v), Some(11));
138        t2.write(12);
139        drop(t2);
140        assert_eq!(t.read().map(|v| *v), Some(12));
141        t3.write(13);
142        drop(t3);
143        assert_eq!(t.read().map(|v| *v), Some(13));
144    }
145
146    #[test]
147    fn test_rcu_reader() {
148        let t = Arc::new(RcuCell::new(10));
149        let t1 = t.clone();
150        let t2 = t.clone();
151        let t3 = t.clone();
152        let d1 = t1.read().unwrap();
153        let d3 = t3.read().unwrap();
154        t1.write(11);
155        let d2 = t2.read().unwrap();
156        assert_ne!(d1, d2);
157        assert_eq!(d1, d3);
158        assert_ne!(d2, d3);
159    }
160
161    #[test]
162    fn test_rcu_take() {
163        let t = Arc::new(RcuCell::new(10));
164        let t1 = t.clone();
165        let t2 = t.clone();
166        let d1 = t1.take().unwrap();
167        assert_eq!(*d1, 10);
168        assert_eq!(t1.read(), None);
169        let d2 = t2.write(42);
170        assert!(d2.is_none());
171        let d3 = t2.read().unwrap();
172        assert_eq!(*d3, 42);
173    }
174
175    #[test]
176    fn test_arc_eq() {
177        let t = RcuCell::new(10);
178        let v = t.read().unwrap();
179        assert!(t.arc_eq(&v));
180        t.write(11);
181        assert!(!t.arc_eq(&v));
182        let t1 = RcuCell::from(v.clone());
183        assert!(t1.arc_eq(&v));
184        let v2 = t.write(v);
185        let t2 = RcuCell::from(v2.clone());
186        assert!(RcuCell::ptr_eq(&t, &t1));
187        assert!(t2.arc_eq(v2.as_ref().unwrap()));
188    }
189
190    #[test]
191    fn cas_test() {
192        use super::ArcPointer;
193        use Ordering::SeqCst;
194
195        let a = RcuCell::new(1234);
196
197        let curr = a.read().as_ptr();
198        let res1 = unsafe { a.compare_exchange(curr, None, SeqCst, SeqCst) }.unwrap();
199        assert_eq!(res1, curr);
200        assert!(a.is_none());
201        let res2 = unsafe { a.compare_exchange(res1, Some(&Arc::new(5678)), SeqCst, SeqCst) };
202        assert!(res2.is_err());
203
204        let null = core::ptr::null();
205        let res2 = unsafe { a.compare_exchange(null, Some(&Arc::new(5678)), SeqCst, SeqCst) };
206        assert!(res2.is_ok());
207        assert_eq!(a.read().map(|v| *v), Some(5678));
208    }
209}