• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 Amanieu d'Antras
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7 
8 use crate::raw_rwlock::RawRwLock;
9 
10 /// A reader-writer lock
11 ///
12 /// This type of lock allows a number of readers or at most one writer at any
13 /// point in time. The write portion of this lock typically allows modification
14 /// of the underlying data (exclusive access) and the read portion of this lock
15 /// typically allows for read-only access (shared access).
16 ///
17 /// This lock uses a task-fair locking policy which avoids both reader and
18 /// writer starvation. This means that readers trying to acquire the lock will
19 /// block even if the lock is unlocked when there are writers waiting to acquire
20 /// the lock. Because of this, attempts to recursively acquire a read lock
21 /// within a single thread may result in a deadlock.
22 ///
23 /// The type parameter `T` represents the data that this lock protects. It is
24 /// required that `T` satisfies `Send` to be shared across threads and `Sync` to
25 /// allow concurrent access through readers. The RAII guards returned from the
26 /// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
27 /// to allow access to the contained of the lock.
28 ///
29 /// # Fairness
30 ///
31 /// A typical unfair lock can often end up in a situation where a single thread
32 /// quickly acquires and releases the same lock in succession, which can starve
33 /// other threads waiting to acquire the rwlock. While this improves throughput
34 /// because it doesn't force a context switch when a thread tries to re-acquire
35 /// a rwlock it has just released, this can starve other threads.
36 ///
37 /// This rwlock uses [eventual fairness](https://trac.webkit.org/changeset/203350)
38 /// to ensure that the lock will be fair on average without sacrificing
39 /// throughput. This is done by forcing a fair unlock on average every 0.5ms,
40 /// which will force the lock to go to the next thread waiting for the rwlock.
41 ///
42 /// Additionally, any critical section longer than 1ms will always use a fair
43 /// unlock, which has a negligible impact on throughput considering the length
44 /// of the critical section.
45 ///
46 /// You can also force a fair unlock by calling `RwLockReadGuard::unlock_fair`
47 /// or `RwLockWriteGuard::unlock_fair` when unlocking a mutex instead of simply
48 /// dropping the guard.
49 ///
50 /// # Differences from the standard library `RwLock`
51 ///
52 /// - Supports atomically downgrading a write lock into a read lock.
53 /// - Task-fair locking policy instead of an unspecified platform default.
54 /// - No poisoning, the lock is released normally on panic.
55 /// - Only requires 1 word of space, whereas the standard library boxes the
56 ///   `RwLock` due to platform limitations.
57 /// - Can be statically constructed.
58 /// - Does not require any drop glue when dropped.
59 /// - Inline fast path for the uncontended case.
60 /// - Efficient handling of micro-contention using adaptive spinning.
61 /// - Allows raw locking & unlocking without a guard.
62 /// - Supports eventual fairness so that the rwlock is fair on average.
63 /// - Optionally allows making the rwlock fair by calling
64 ///   `RwLockReadGuard::unlock_fair` and `RwLockWriteGuard::unlock_fair`.
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use parking_lot::RwLock;
70 ///
71 /// let lock = RwLock::new(5);
72 ///
73 /// // many reader locks can be held at once
74 /// {
75 ///     let r1 = lock.read();
76 ///     let r2 = lock.read();
77 ///     assert_eq!(*r1, 5);
78 ///     assert_eq!(*r2, 5);
79 /// } // read locks are dropped at this point
80 ///
81 /// // only one write lock may be held, however
82 /// {
83 ///     let mut w = lock.write();
84 ///     *w += 1;
85 ///     assert_eq!(*w, 6);
86 /// } // write lock is dropped here
87 /// ```
88 pub type RwLock<T> = lock_api::RwLock<RawRwLock, T>;
89 
90 /// Creates a new instance of an `RwLock<T>` which is unlocked.
91 ///
92 /// This allows creating a `RwLock<T>` in a constant context on stable Rust.
const_rwlock<T>(val: T) -> RwLock<T>93 pub const fn const_rwlock<T>(val: T) -> RwLock<T> {
94     RwLock::const_new(<RawRwLock as lock_api::RawRwLock>::INIT, val)
95 }
96 
97 /// RAII structure used to release the shared read access of a lock when
98 /// dropped.
99 pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>;
100 
101 /// RAII structure used to release the exclusive write access of a lock when
102 /// dropped.
103 pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>;
104 
105 /// An RAII read lock guard returned by `RwLockReadGuard::map`, which can point to a
106 /// subfield of the protected data.
107 ///
108 /// The main difference between `MappedRwLockReadGuard` and `RwLockReadGuard` is that the
109 /// former doesn't support temporarily unlocking and re-locking, since that
110 /// could introduce soundness issues if the locked object is modified by another
111 /// thread.
112 pub type MappedRwLockReadGuard<'a, T> = lock_api::MappedRwLockReadGuard<'a, RawRwLock, T>;
113 
114 /// An RAII write lock guard returned by `RwLockWriteGuard::map`, which can point to a
115 /// subfield of the protected data.
116 ///
117 /// The main difference between `MappedRwLockWriteGuard` and `RwLockWriteGuard` is that the
118 /// former doesn't support temporarily unlocking and re-locking, since that
119 /// could introduce soundness issues if the locked object is modified by another
120 /// thread.
121 pub type MappedRwLockWriteGuard<'a, T> = lock_api::MappedRwLockWriteGuard<'a, RawRwLock, T>;
122 
123 /// RAII structure used to release the upgradable read access of a lock when
124 /// dropped.
125 pub type RwLockUpgradableReadGuard<'a, T> = lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>;
126 
127 #[cfg(test)]
128 mod tests {
129     use crate::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard};
130     use rand::Rng;
131     use std::sync::atomic::{AtomicUsize, Ordering};
132     use std::sync::mpsc::channel;
133     use std::sync::Arc;
134     use std::thread;
135     use std::time::Duration;
136 
137     #[cfg(feature = "serde")]
138     use bincode::{deserialize, serialize};
139 
140     #[derive(Eq, PartialEq, Debug)]
141     struct NonCopy(i32);
142 
143     #[test]
smoke()144     fn smoke() {
145         let l = RwLock::new(());
146         drop(l.read());
147         drop(l.write());
148         drop(l.upgradable_read());
149         drop((l.read(), l.read()));
150         drop((l.read(), l.upgradable_read()));
151         drop(l.write());
152     }
153 
154     #[test]
frob()155     fn frob() {
156         const N: u32 = 10;
157         const M: u32 = 1000;
158 
159         let r = Arc::new(RwLock::new(()));
160 
161         let (tx, rx) = channel::<()>();
162         for _ in 0..N {
163             let tx = tx.clone();
164             let r = r.clone();
165             thread::spawn(move || {
166                 let mut rng = rand::thread_rng();
167                 for _ in 0..M {
168                     if rng.gen_bool(1.0 / N as f64) {
169                         drop(r.write());
170                     } else {
171                         drop(r.read());
172                     }
173                 }
174                 drop(tx);
175             });
176         }
177         drop(tx);
178         let _ = rx.recv();
179     }
180 
181     #[test]
test_rw_arc_no_poison_wr()182     fn test_rw_arc_no_poison_wr() {
183         let arc = Arc::new(RwLock::new(1));
184         let arc2 = arc.clone();
185         let _: Result<(), _> = thread::spawn(move || {
186             let _lock = arc2.write();
187             panic!();
188         })
189         .join();
190         let lock = arc.read();
191         assert_eq!(*lock, 1);
192     }
193 
194     #[test]
test_rw_arc_no_poison_ww()195     fn test_rw_arc_no_poison_ww() {
196         let arc = Arc::new(RwLock::new(1));
197         let arc2 = arc.clone();
198         let _: Result<(), _> = thread::spawn(move || {
199             let _lock = arc2.write();
200             panic!();
201         })
202         .join();
203         let lock = arc.write();
204         assert_eq!(*lock, 1);
205     }
206 
207     #[test]
test_rw_arc_no_poison_rr()208     fn test_rw_arc_no_poison_rr() {
209         let arc = Arc::new(RwLock::new(1));
210         let arc2 = arc.clone();
211         let _: Result<(), _> = thread::spawn(move || {
212             let _lock = arc2.read();
213             panic!();
214         })
215         .join();
216         let lock = arc.read();
217         assert_eq!(*lock, 1);
218     }
219 
220     #[test]
test_rw_arc_no_poison_rw()221     fn test_rw_arc_no_poison_rw() {
222         let arc = Arc::new(RwLock::new(1));
223         let arc2 = arc.clone();
224         let _: Result<(), _> = thread::spawn(move || {
225             let _lock = arc2.read();
226             panic!()
227         })
228         .join();
229         let lock = arc.write();
230         assert_eq!(*lock, 1);
231     }
232 
233     #[test]
test_ruw_arc()234     fn test_ruw_arc() {
235         let arc = Arc::new(RwLock::new(0));
236         let arc2 = arc.clone();
237         let (tx, rx) = channel();
238 
239         thread::spawn(move || {
240             for _ in 0..10 {
241                 let mut lock = arc2.write();
242                 let tmp = *lock;
243                 *lock = -1;
244                 thread::yield_now();
245                 *lock = tmp + 1;
246             }
247             tx.send(()).unwrap();
248         });
249 
250         let mut children = Vec::new();
251 
252         // Upgradable readers try to catch the writer in the act and also
253         // try to touch the value
254         for _ in 0..5 {
255             let arc3 = arc.clone();
256             children.push(thread::spawn(move || {
257                 let lock = arc3.upgradable_read();
258                 let tmp = *lock;
259                 assert!(tmp >= 0);
260                 thread::yield_now();
261                 let mut lock = RwLockUpgradableReadGuard::upgrade(lock);
262                 assert_eq!(tmp, *lock);
263                 *lock = -1;
264                 thread::yield_now();
265                 *lock = tmp + 1;
266             }));
267         }
268 
269         // Readers try to catch the writers in the act
270         for _ in 0..5 {
271             let arc4 = arc.clone();
272             children.push(thread::spawn(move || {
273                 let lock = arc4.read();
274                 assert!(*lock >= 0);
275             }));
276         }
277 
278         // Wait for children to pass their asserts
279         for r in children {
280             assert!(r.join().is_ok());
281         }
282 
283         // Wait for writer to finish
284         rx.recv().unwrap();
285         let lock = arc.read();
286         assert_eq!(*lock, 15);
287     }
288 
289     #[test]
test_rw_arc()290     fn test_rw_arc() {
291         let arc = Arc::new(RwLock::new(0));
292         let arc2 = arc.clone();
293         let (tx, rx) = channel();
294 
295         thread::spawn(move || {
296             let mut lock = arc2.write();
297             for _ in 0..10 {
298                 let tmp = *lock;
299                 *lock = -1;
300                 thread::yield_now();
301                 *lock = tmp + 1;
302             }
303             tx.send(()).unwrap();
304         });
305 
306         // Readers try to catch the writer in the act
307         let mut children = Vec::new();
308         for _ in 0..5 {
309             let arc3 = arc.clone();
310             children.push(thread::spawn(move || {
311                 let lock = arc3.read();
312                 assert!(*lock >= 0);
313             }));
314         }
315 
316         // Wait for children to pass their asserts
317         for r in children {
318             assert!(r.join().is_ok());
319         }
320 
321         // Wait for writer to finish
322         rx.recv().unwrap();
323         let lock = arc.read();
324         assert_eq!(*lock, 10);
325     }
326 
327     #[test]
test_rw_arc_access_in_unwind()328     fn test_rw_arc_access_in_unwind() {
329         let arc = Arc::new(RwLock::new(1));
330         let arc2 = arc.clone();
331         let _ = thread::spawn(move || {
332             struct Unwinder {
333                 i: Arc<RwLock<isize>>,
334             }
335             impl Drop for Unwinder {
336                 fn drop(&mut self) {
337                     let mut lock = self.i.write();
338                     *lock += 1;
339                 }
340             }
341             let _u = Unwinder { i: arc2 };
342             panic!();
343         })
344         .join();
345         let lock = arc.read();
346         assert_eq!(*lock, 2);
347     }
348 
349     #[test]
test_rwlock_unsized()350     fn test_rwlock_unsized() {
351         let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
352         {
353             let b = &mut *rw.write();
354             b[0] = 4;
355             b[2] = 5;
356         }
357         let comp: &[i32] = &[4, 2, 5];
358         assert_eq!(&*rw.read(), comp);
359     }
360 
361     #[test]
test_rwlock_try_read()362     fn test_rwlock_try_read() {
363         let lock = RwLock::new(0isize);
364         {
365             let read_guard = lock.read();
366 
367             let read_result = lock.try_read();
368             assert!(
369                 read_result.is_some(),
370                 "try_read should succeed while read_guard is in scope"
371             );
372 
373             drop(read_guard);
374         }
375         {
376             let upgrade_guard = lock.upgradable_read();
377 
378             let read_result = lock.try_read();
379             assert!(
380                 read_result.is_some(),
381                 "try_read should succeed while upgrade_guard is in scope"
382             );
383 
384             drop(upgrade_guard);
385         }
386         {
387             let write_guard = lock.write();
388 
389             let read_result = lock.try_read();
390             assert!(
391                 read_result.is_none(),
392                 "try_read should fail while write_guard is in scope"
393             );
394 
395             drop(write_guard);
396         }
397     }
398 
399     #[test]
test_rwlock_try_write()400     fn test_rwlock_try_write() {
401         let lock = RwLock::new(0isize);
402         {
403             let read_guard = lock.read();
404 
405             let write_result = lock.try_write();
406             assert!(
407                 write_result.is_none(),
408                 "try_write should fail while read_guard is in scope"
409             );
410             assert!(lock.is_locked());
411             assert!(!lock.is_locked_exclusive());
412 
413             drop(read_guard);
414         }
415         {
416             let upgrade_guard = lock.upgradable_read();
417 
418             let write_result = lock.try_write();
419             assert!(
420                 write_result.is_none(),
421                 "try_write should fail while upgrade_guard is in scope"
422             );
423             assert!(lock.is_locked());
424             assert!(!lock.is_locked_exclusive());
425 
426             drop(upgrade_guard);
427         }
428         {
429             let write_guard = lock.write();
430 
431             let write_result = lock.try_write();
432             assert!(
433                 write_result.is_none(),
434                 "try_write should fail while write_guard is in scope"
435             );
436             assert!(lock.is_locked());
437             assert!(lock.is_locked_exclusive());
438 
439             drop(write_guard);
440         }
441     }
442 
443     #[test]
test_rwlock_try_upgrade()444     fn test_rwlock_try_upgrade() {
445         let lock = RwLock::new(0isize);
446         {
447             let read_guard = lock.read();
448 
449             let upgrade_result = lock.try_upgradable_read();
450             assert!(
451                 upgrade_result.is_some(),
452                 "try_upgradable_read should succeed while read_guard is in scope"
453             );
454 
455             drop(read_guard);
456         }
457         {
458             let upgrade_guard = lock.upgradable_read();
459 
460             let upgrade_result = lock.try_upgradable_read();
461             assert!(
462                 upgrade_result.is_none(),
463                 "try_upgradable_read should fail while upgrade_guard is in scope"
464             );
465 
466             drop(upgrade_guard);
467         }
468         {
469             let write_guard = lock.write();
470 
471             let upgrade_result = lock.try_upgradable_read();
472             assert!(
473                 upgrade_result.is_none(),
474                 "try_upgradable should fail while write_guard is in scope"
475             );
476 
477             drop(write_guard);
478         }
479     }
480 
481     #[test]
test_into_inner()482     fn test_into_inner() {
483         let m = RwLock::new(NonCopy(10));
484         assert_eq!(m.into_inner(), NonCopy(10));
485     }
486 
487     #[test]
test_into_inner_drop()488     fn test_into_inner_drop() {
489         struct Foo(Arc<AtomicUsize>);
490         impl Drop for Foo {
491             fn drop(&mut self) {
492                 self.0.fetch_add(1, Ordering::SeqCst);
493             }
494         }
495         let num_drops = Arc::new(AtomicUsize::new(0));
496         let m = RwLock::new(Foo(num_drops.clone()));
497         assert_eq!(num_drops.load(Ordering::SeqCst), 0);
498         {
499             let _inner = m.into_inner();
500             assert_eq!(num_drops.load(Ordering::SeqCst), 0);
501         }
502         assert_eq!(num_drops.load(Ordering::SeqCst), 1);
503     }
504 
505     #[test]
test_get_mut()506     fn test_get_mut() {
507         let mut m = RwLock::new(NonCopy(10));
508         *m.get_mut() = NonCopy(20);
509         assert_eq!(m.into_inner(), NonCopy(20));
510     }
511 
512     #[test]
test_rwlockguard_sync()513     fn test_rwlockguard_sync() {
514         fn sync<T: Sync>(_: T) {}
515 
516         let rwlock = RwLock::new(());
517         sync(rwlock.read());
518         sync(rwlock.write());
519     }
520 
521     #[test]
test_rwlock_downgrade()522     fn test_rwlock_downgrade() {
523         let x = Arc::new(RwLock::new(0));
524         let mut handles = Vec::new();
525         for _ in 0..8 {
526             let x = x.clone();
527             handles.push(thread::spawn(move || {
528                 for _ in 0..100 {
529                     let mut writer = x.write();
530                     *writer += 1;
531                     let cur_val = *writer;
532                     let reader = RwLockWriteGuard::downgrade(writer);
533                     assert_eq!(cur_val, *reader);
534                 }
535             }));
536         }
537         for handle in handles {
538             handle.join().unwrap()
539         }
540         assert_eq!(*x.read(), 800);
541     }
542 
543     #[test]
test_rwlock_recursive()544     fn test_rwlock_recursive() {
545         let arc = Arc::new(RwLock::new(1));
546         let arc2 = arc.clone();
547         let lock1 = arc.read();
548         let t = thread::spawn(move || {
549             let _lock = arc2.write();
550         });
551 
552         if cfg!(not(all(target_env = "sgx", target_vendor = "fortanix"))) {
553             thread::sleep(Duration::from_millis(100));
554         } else {
555             // FIXME: https://github.com/fortanix/rust-sgx/issues/31
556             for _ in 0..100 {
557                 thread::yield_now();
558             }
559         }
560 
561         // A normal read would block here since there is a pending writer
562         let lock2 = arc.read_recursive();
563 
564         // Unblock the thread and join it.
565         drop(lock1);
566         drop(lock2);
567         t.join().unwrap();
568     }
569 
570     #[test]
test_rwlock_debug()571     fn test_rwlock_debug() {
572         let x = RwLock::new(vec![0u8, 10]);
573 
574         assert_eq!(format!("{:?}", x), "RwLock { data: [0, 10] }");
575         let _lock = x.write();
576         assert_eq!(format!("{:?}", x), "RwLock { data: <locked> }");
577     }
578 
579     #[test]
test_clone()580     fn test_clone() {
581         let rwlock = RwLock::new(Arc::new(1));
582         let a = rwlock.read_recursive();
583         let b = a.clone();
584         assert_eq!(Arc::strong_count(&b), 2);
585     }
586 
587     #[cfg(feature = "serde")]
588     #[test]
test_serde()589     fn test_serde() {
590         let contents: Vec<u8> = vec![0, 1, 2];
591         let mutex = RwLock::new(contents.clone());
592 
593         let serialized = serialize(&mutex).unwrap();
594         let deserialized: RwLock<Vec<u8>> = deserialize(&serialized).unwrap();
595 
596         assert_eq!(*(mutex.read()), *(deserialized.read()));
597         assert_eq!(contents, *(deserialized.read()));
598     }
599 
600     #[test]
test_issue_203()601     fn test_issue_203() {
602         struct Bar(RwLock<()>);
603 
604         impl Drop for Bar {
605             fn drop(&mut self) {
606                 let _n = self.0.write();
607             }
608         }
609 
610         thread_local! {
611             static B: Bar = Bar(RwLock::new(()));
612         }
613 
614         thread::spawn(|| {
615             B.with(|_| ());
616 
617             let a = RwLock::new(());
618             let _a = a.read();
619         })
620         .join()
621         .unwrap();
622     }
623 
624     #[test]
test_rw_write_is_locked()625     fn test_rw_write_is_locked() {
626         let lock = RwLock::new(0isize);
627         {
628             let _read_guard = lock.read();
629 
630             assert!(lock.is_locked());
631             assert!(!lock.is_locked_exclusive());
632         }
633 
634         {
635             let _write_guard = lock.write();
636 
637             assert!(lock.is_locked());
638             assert!(lock.is_locked_exclusive());
639         }
640     }
641 
642     #[test]
643     #[cfg(feature = "arc_lock")]
test_issue_430()644     fn test_issue_430() {
645         let lock = std::sync::Arc::new(RwLock::new(0));
646 
647         let mut rl = lock.upgradable_read_arc();
648 
649         rl.with_upgraded(|_| {
650             println!("lock upgrade");
651         });
652 
653         rl.with_upgraded(|_| {
654             println!("lock upgrade");
655         });
656 
657         drop(lock);
658     }
659 }
660