]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | use crate::sync::atomic::{AtomicUsize, Ordering}; |
2 | use crate::sync::mpsc::channel; | |
064997fb | 3 | use crate::sync::{Arc, RwLock, RwLockReadGuard, TryLockError}; |
1b1a35ee XL |
4 | use crate::thread; |
5 | use rand::{self, Rng}; | |
6 | ||
7 | #[derive(Eq, PartialEq, Debug)] | |
8 | struct NonCopy(i32); | |
9 | ||
10 | #[test] | |
11 | fn smoke() { | |
12 | let l = RwLock::new(()); | |
13 | drop(l.read().unwrap()); | |
14 | drop(l.write().unwrap()); | |
15 | drop((l.read().unwrap(), l.read().unwrap())); | |
16 | drop(l.write().unwrap()); | |
17 | } | |
18 | ||
19 | #[test] | |
20 | fn frob() { | |
21 | const N: u32 = 10; | |
f2b60f7d | 22 | const M: usize = if cfg!(miri) { 100 } else { 1000 }; |
1b1a35ee XL |
23 | |
24 | let r = Arc::new(RwLock::new(())); | |
25 | ||
26 | let (tx, rx) = channel::<()>(); | |
27 | for _ in 0..N { | |
28 | let tx = tx.clone(); | |
29 | let r = r.clone(); | |
30 | thread::spawn(move || { | |
31 | let mut rng = rand::thread_rng(); | |
32 | for _ in 0..M { | |
33 | if rng.gen_bool(1.0 / (N as f64)) { | |
34 | drop(r.write().unwrap()); | |
35 | } else { | |
36 | drop(r.read().unwrap()); | |
37 | } | |
38 | } | |
39 | drop(tx); | |
40 | }); | |
41 | } | |
42 | drop(tx); | |
43 | let _ = rx.recv(); | |
44 | } | |
45 | ||
46 | #[test] | |
47 | fn test_rw_arc_poison_wr() { | |
48 | let arc = Arc::new(RwLock::new(1)); | |
49 | let arc2 = arc.clone(); | |
50 | let _: Result<(), _> = thread::spawn(move || { | |
51 | let _lock = arc2.write().unwrap(); | |
52 | panic!(); | |
53 | }) | |
54 | .join(); | |
55 | assert!(arc.read().is_err()); | |
56 | } | |
57 | ||
58 | #[test] | |
59 | fn test_rw_arc_poison_ww() { | |
60 | let arc = Arc::new(RwLock::new(1)); | |
61 | assert!(!arc.is_poisoned()); | |
62 | let arc2 = arc.clone(); | |
63 | let _: Result<(), _> = thread::spawn(move || { | |
64 | let _lock = arc2.write().unwrap(); | |
65 | panic!(); | |
66 | }) | |
67 | .join(); | |
68 | assert!(arc.write().is_err()); | |
69 | assert!(arc.is_poisoned()); | |
70 | } | |
71 | ||
72 | #[test] | |
73 | fn test_rw_arc_no_poison_rr() { | |
74 | let arc = Arc::new(RwLock::new(1)); | |
75 | let arc2 = arc.clone(); | |
76 | let _: Result<(), _> = thread::spawn(move || { | |
77 | let _lock = arc2.read().unwrap(); | |
78 | panic!(); | |
79 | }) | |
80 | .join(); | |
81 | let lock = arc.read().unwrap(); | |
82 | assert_eq!(*lock, 1); | |
83 | } | |
84 | #[test] | |
85 | fn test_rw_arc_no_poison_rw() { | |
86 | let arc = Arc::new(RwLock::new(1)); | |
87 | let arc2 = arc.clone(); | |
88 | let _: Result<(), _> = thread::spawn(move || { | |
89 | let _lock = arc2.read().unwrap(); | |
90 | panic!() | |
91 | }) | |
92 | .join(); | |
93 | let lock = arc.write().unwrap(); | |
94 | assert_eq!(*lock, 1); | |
95 | } | |
96 | ||
97 | #[test] | |
98 | fn test_rw_arc() { | |
99 | let arc = Arc::new(RwLock::new(0)); | |
100 | let arc2 = arc.clone(); | |
101 | let (tx, rx) = channel(); | |
102 | ||
103 | thread::spawn(move || { | |
104 | let mut lock = arc2.write().unwrap(); | |
105 | for _ in 0..10 { | |
106 | let tmp = *lock; | |
107 | *lock = -1; | |
108 | thread::yield_now(); | |
109 | *lock = tmp + 1; | |
110 | } | |
111 | tx.send(()).unwrap(); | |
112 | }); | |
113 | ||
114 | // Readers try to catch the writer in the act | |
115 | let mut children = Vec::new(); | |
116 | for _ in 0..5 { | |
117 | let arc3 = arc.clone(); | |
118 | children.push(thread::spawn(move || { | |
119 | let lock = arc3.read().unwrap(); | |
120 | assert!(*lock >= 0); | |
121 | })); | |
122 | } | |
123 | ||
124 | // Wait for children to pass their asserts | |
125 | for r in children { | |
126 | assert!(r.join().is_ok()); | |
127 | } | |
128 | ||
129 | // Wait for writer to finish | |
130 | rx.recv().unwrap(); | |
131 | let lock = arc.read().unwrap(); | |
132 | assert_eq!(*lock, 10); | |
133 | } | |
134 | ||
135 | #[test] | |
136 | fn test_rw_arc_access_in_unwind() { | |
137 | let arc = Arc::new(RwLock::new(1)); | |
138 | let arc2 = arc.clone(); | |
139 | let _ = thread::spawn(move || -> () { | |
140 | struct Unwinder { | |
141 | i: Arc<RwLock<isize>>, | |
142 | } | |
143 | impl Drop for Unwinder { | |
144 | fn drop(&mut self) { | |
145 | let mut lock = self.i.write().unwrap(); | |
146 | *lock += 1; | |
147 | } | |
148 | } | |
149 | let _u = Unwinder { i: arc2 }; | |
150 | panic!(); | |
151 | }) | |
152 | .join(); | |
153 | let lock = arc.read().unwrap(); | |
154 | assert_eq!(*lock, 2); | |
155 | } | |
156 | ||
157 | #[test] | |
158 | fn test_rwlock_unsized() { | |
159 | let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); | |
160 | { | |
161 | let b = &mut *rw.write().unwrap(); | |
162 | b[0] = 4; | |
163 | b[2] = 5; | |
164 | } | |
165 | let comp: &[i32] = &[4, 2, 5]; | |
166 | assert_eq!(&*rw.read().unwrap(), comp); | |
167 | } | |
168 | ||
169 | #[test] | |
170 | fn test_rwlock_try_write() { | |
171 | let lock = RwLock::new(0isize); | |
172 | let read_guard = lock.read().unwrap(); | |
173 | ||
174 | let write_result = lock.try_write(); | |
175 | match write_result { | |
176 | Err(TryLockError::WouldBlock) => (), | |
177 | Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"), | |
178 | Err(_) => assert!(false, "unexpected error"), | |
179 | } | |
180 | ||
181 | drop(read_guard); | |
182 | } | |
183 | ||
184 | #[test] | |
185 | fn test_into_inner() { | |
186 | let m = RwLock::new(NonCopy(10)); | |
187 | assert_eq!(m.into_inner().unwrap(), NonCopy(10)); | |
188 | } | |
189 | ||
190 | #[test] | |
191 | fn test_into_inner_drop() { | |
192 | struct Foo(Arc<AtomicUsize>); | |
193 | impl Drop for Foo { | |
194 | fn drop(&mut self) { | |
195 | self.0.fetch_add(1, Ordering::SeqCst); | |
196 | } | |
197 | } | |
198 | let num_drops = Arc::new(AtomicUsize::new(0)); | |
199 | let m = RwLock::new(Foo(num_drops.clone())); | |
200 | assert_eq!(num_drops.load(Ordering::SeqCst), 0); | |
201 | { | |
202 | let _inner = m.into_inner().unwrap(); | |
203 | assert_eq!(num_drops.load(Ordering::SeqCst), 0); | |
204 | } | |
205 | assert_eq!(num_drops.load(Ordering::SeqCst), 1); | |
206 | } | |
207 | ||
208 | #[test] | |
209 | fn test_into_inner_poison() { | |
210 | let m = Arc::new(RwLock::new(NonCopy(10))); | |
211 | let m2 = m.clone(); | |
212 | let _ = thread::spawn(move || { | |
213 | let _lock = m2.write().unwrap(); | |
214 | panic!("test panic in inner thread to poison RwLock"); | |
215 | }) | |
216 | .join(); | |
217 | ||
218 | assert!(m.is_poisoned()); | |
219 | match Arc::try_unwrap(m).unwrap().into_inner() { | |
220 | Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), | |
5e7ed085 | 221 | Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {x:?}"), |
1b1a35ee XL |
222 | } |
223 | } | |
224 | ||
225 | #[test] | |
226 | fn test_get_mut() { | |
227 | let mut m = RwLock::new(NonCopy(10)); | |
228 | *m.get_mut().unwrap() = NonCopy(20); | |
229 | assert_eq!(m.into_inner().unwrap(), NonCopy(20)); | |
230 | } | |
231 | ||
232 | #[test] | |
233 | fn test_get_mut_poison() { | |
234 | let m = Arc::new(RwLock::new(NonCopy(10))); | |
235 | let m2 = m.clone(); | |
236 | let _ = thread::spawn(move || { | |
237 | let _lock = m2.write().unwrap(); | |
238 | panic!("test panic in inner thread to poison RwLock"); | |
239 | }) | |
240 | .join(); | |
241 | ||
242 | assert!(m.is_poisoned()); | |
243 | match Arc::try_unwrap(m).unwrap().get_mut() { | |
244 | Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), | |
5e7ed085 | 245 | Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"), |
1b1a35ee XL |
246 | } |
247 | } | |
064997fb FG |
248 | |
249 | #[test] | |
250 | fn test_read_guard_covariance() { | |
251 | fn do_stuff<'a>(_: RwLockReadGuard<'_, &'a i32>, _: &'a i32) {} | |
252 | let j: i32 = 5; | |
253 | let lock = RwLock::new(&j); | |
254 | { | |
255 | let i = 6; | |
256 | do_stuff(lock.read().unwrap(), &i); | |
257 | } | |
258 | drop(lock); | |
259 | } |