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.
78use crate::raw_rwlock::RawRwLock;
9use lock_api;
1011/// A reader-writer lock
12///
13/// This type of lock allows a number of readers or at most one writer at any
14/// point in time. The write portion of this lock typically allows modification
15/// of the underlying data (exclusive access) and the read portion of this lock
16/// typically allows for read-only access (shared access).
17///
18/// This lock uses a task-fair locking policy which avoids both reader and
19/// writer starvation. This means that readers trying to acquire the lock will
20/// block even if the lock is unlocked when there are writers waiting to acquire
21/// the lock. Because of this, attempts to recursively acquire a read lock
22/// within a single thread may result in a deadlock.
23///
24/// The type parameter `T` represents the data that this lock protects. It is
25/// required that `T` satisfies `Send` to be shared across threads and `Sync` to
26/// allow concurrent access through readers. The RAII guards returned from the
27/// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
28/// to allow access to the contained of the lock.
29///
30/// # Fairness
31///
32/// A typical unfair lock can often end up in a situation where a single thread
33/// quickly acquires and releases the same lock in succession, which can starve
34/// other threads waiting to acquire the rwlock. While this improves throughput
35/// because it doesn't force a context switch when a thread tries to re-acquire
36/// a rwlock it has just released, this can starve other threads.
37///
38/// This rwlock uses [eventual fairness](https://trac.webkit.org/changeset/203350)
39/// to ensure that the lock will be fair on average without sacrificing
40/// throughput. This is done by forcing a fair unlock on average every 0.5ms,
41/// which will force the lock to go to the next thread waiting for the rwlock.
42///
43/// Additionally, any critical section longer than 1ms will always use a fair
44/// unlock, which has a negligible impact on throughput considering the length
45/// of the critical section.
46///
47/// You can also force a fair unlock by calling `RwLockReadGuard::unlock_fair`
48/// or `RwLockWriteGuard::unlock_fair` when unlocking a mutex instead of simply
49/// dropping the guard.
50///
51/// # Differences from the standard library `RwLock`
52///
53/// - Supports atomically downgrading a write lock into a read lock.
54/// - Task-fair locking policy instead of an unspecified platform default.
55/// - No poisoning, the lock is released normally on panic.
56/// - Only requires 1 word of space, whereas the standard library boxes the
57/// `RwLock` due to platform limitations.
58/// - Can be statically constructed (requires the `const_fn` nightly feature).
59/// - Does not require any drop glue when dropped.
60/// - Inline fast path for the uncontended case.
61/// - Efficient handling of micro-contention using adaptive spinning.
62/// - Allows raw locking & unlocking without a guard.
63/// - Supports eventual fairness so that the rwlock is fair on average.
64/// - Optionally allows making the rwlock fair by calling
65/// `RwLockReadGuard::unlock_fair` and `RwLockWriteGuard::unlock_fair`.
66///
67/// # Examples
68///
69/// ```
70/// use parking_lot::RwLock;
71///
72/// let lock = RwLock::new(5);
73///
74/// // many reader locks can be held at once
75/// {
76/// let r1 = lock.read();
77/// let r2 = lock.read();
78/// assert_eq!(*r1, 5);
79/// assert_eq!(*r2, 5);
80/// } // read locks are dropped at this point
81///
82/// // only one write lock may be held, however
83/// {
84/// let mut w = lock.write();
85/// *w += 1;
86/// assert_eq!(*w, 6);
87/// } // write lock is dropped here
88/// ```
89pub type RwLock<T> = lock_api::RwLock<RawRwLock, T>;
9091/// Creates a new instance of an `RwLock<T>` which is unlocked.
92///
93/// This allows creating a `RwLock<T>` in a constant context on stable Rust.
94pub const fn const_rwlock<T>(val: T) -> RwLock<T> {
95 RwLock::const_new(<RawRwLock as lock_api::RawRwLock>::INIT, val)
96}
9798/// RAII structure used to release the shared read access of a lock when
99/// dropped.
100pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>;
101102/// RAII structure used to release the exclusive write access of a lock when
103/// dropped.
104pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>;
105106/// An RAII read lock guard returned by `RwLockReadGuard::map`, which can point to a
107/// subfield of the protected data.
108///
109/// The main difference between `MappedRwLockReadGuard` and `RwLockReadGuard` is that the
110/// former doesn't support temporarily unlocking and re-locking, since that
111/// could introduce soundness issues if the locked object is modified by another
112/// thread.
113pub type MappedRwLockReadGuard<'a, T> = lock_api::MappedRwLockReadGuard<'a, RawRwLock, T>;
114115/// An RAII write lock guard returned by `RwLockWriteGuard::map`, which can point to a
116/// subfield of the protected data.
117///
118/// The main difference between `MappedRwLockWriteGuard` and `RwLockWriteGuard` is that the
119/// former doesn't support temporarily unlocking and re-locking, since that
120/// could introduce soundness issues if the locked object is modified by another
121/// thread.
122pub type MappedRwLockWriteGuard<'a, T> = lock_api::MappedRwLockWriteGuard<'a, RawRwLock, T>;
123124/// RAII structure used to release the upgradable read access of a lock when
125/// dropped.
126pub type RwLockUpgradableReadGuard<'a, T> = lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>;
127128#[cfg(test)]
129mod tests {
130use crate::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard};
131use rand::Rng;
132use std::sync::atomic::{AtomicUsize, Ordering};
133use std::sync::mpsc::channel;
134use std::sync::Arc;
135use std::thread;
136use std::time::Duration;
137138#[cfg(feature = "serde")]
139use bincode::{deserialize, serialize};
140141#[derive(Eq, PartialEq, Debug)]
142struct NonCopy(i32);
143144#[test]
145fn smoke() {
146let l = RwLock::new(());
147 drop(l.read());
148 drop(l.write());
149 drop(l.upgradable_read());
150 drop((l.read(), l.read()));
151 drop((l.read(), l.upgradable_read()));
152 drop(l.write());
153 }
154155#[test]
156fn frob() {
157const N: u32 = 10;
158const M: u32 = 1000;
159160let r = Arc::new(RwLock::new(()));
161162let (tx, rx) = channel::<()>();
163for _ in 0..N {
164let tx = tx.clone();
165let r = r.clone();
166 thread::spawn(move || {
167let mut rng = rand::thread_rng();
168for _ in 0..M {
169if rng.gen_bool(1.0 / N as f64) {
170 drop(r.write());
171 } else {
172 drop(r.read());
173 }
174 }
175 drop(tx);
176 });
177 }
178 drop(tx);
179let _ = rx.recv();
180 }
181182#[test]
183fn test_rw_arc_no_poison_wr() {
184let arc = Arc::new(RwLock::new(1));
185let arc2 = arc.clone();
186let _: Result<(), _> = thread::spawn(move || {
187let _lock = arc2.write();
188panic!();
189 })
190 .join();
191let lock = arc.read();
192assert_eq!(*lock, 1);
193 }
194195#[test]
196fn test_rw_arc_no_poison_ww() {
197let arc = Arc::new(RwLock::new(1));
198let arc2 = arc.clone();
199let _: Result<(), _> = thread::spawn(move || {
200let _lock = arc2.write();
201panic!();
202 })
203 .join();
204let lock = arc.write();
205assert_eq!(*lock, 1);
206 }
207208#[test]
209fn test_rw_arc_no_poison_rr() {
210let arc = Arc::new(RwLock::new(1));
211let arc2 = arc.clone();
212let _: Result<(), _> = thread::spawn(move || {
213let _lock = arc2.read();
214panic!();
215 })
216 .join();
217let lock = arc.read();
218assert_eq!(*lock, 1);
219 }
220221#[test]
222fn test_rw_arc_no_poison_rw() {
223let arc = Arc::new(RwLock::new(1));
224let arc2 = arc.clone();
225let _: Result<(), _> = thread::spawn(move || {
226let _lock = arc2.read();
227panic!()
228 })
229 .join();
230let lock = arc.write();
231assert_eq!(*lock, 1);
232 }
233234#[test]
235fn test_ruw_arc() {
236let arc = Arc::new(RwLock::new(0));
237let arc2 = arc.clone();
238let (tx, rx) = channel();
239240 thread::spawn(move || {
241for _ in 0..10 {
242let mut lock = arc2.write();
243let tmp = *lock;
244*lock = -1;
245 thread::yield_now();
246*lock = tmp + 1;
247 }
248 tx.send(()).unwrap();
249 });
250251let mut children = Vec::new();
252253// Upgradable readers try to catch the writer in the act and also
254 // try to touch the value
255for _ in 0..5 {
256let arc3 = arc.clone();
257 children.push(thread::spawn(move || {
258let lock = arc3.upgradable_read();
259let tmp = *lock;
260assert!(tmp >= 0);
261 thread::yield_now();
262let mut lock = RwLockUpgradableReadGuard::upgrade(lock);
263assert_eq!(tmp, *lock);
264*lock = -1;
265 thread::yield_now();
266*lock = tmp + 1;
267 }));
268 }
269270// Readers try to catch the writers in the act
271for _ in 0..5 {
272let arc4 = arc.clone();
273 children.push(thread::spawn(move || {
274let lock = arc4.read();
275assert!(*lock >= 0);
276 }));
277 }
278279// Wait for children to pass their asserts
280for r in children {
281assert!(r.join().is_ok());
282 }
283284// Wait for writer to finish
285rx.recv().unwrap();
286let lock = arc.read();
287assert_eq!(*lock, 15);
288 }
289290#[test]
291fn test_rw_arc() {
292let arc = Arc::new(RwLock::new(0));
293let arc2 = arc.clone();
294let (tx, rx) = channel();
295296 thread::spawn(move || {
297let mut lock = arc2.write();
298for _ in 0..10 {
299let tmp = *lock;
300*lock = -1;
301 thread::yield_now();
302*lock = tmp + 1;
303 }
304 tx.send(()).unwrap();
305 });
306307// Readers try to catch the writer in the act
308let mut children = Vec::new();
309for _ in 0..5 {
310let arc3 = arc.clone();
311 children.push(thread::spawn(move || {
312let lock = arc3.read();
313assert!(*lock >= 0);
314 }));
315 }
316317// Wait for children to pass their asserts
318for r in children {
319assert!(r.join().is_ok());
320 }
321322// Wait for writer to finish
323rx.recv().unwrap();
324let lock = arc.read();
325assert_eq!(*lock, 10);
326 }
327328#[test]
329fn test_rw_arc_access_in_unwind() {
330let arc = Arc::new(RwLock::new(1));
331let arc2 = arc.clone();
332let _ = thread::spawn(move || {
333struct Unwinder {
334 i: Arc<RwLock<isize>>,
335 }
336impl Drop for Unwinder {
337fn drop(&mut self) {
338let mut lock = self.i.write();
339*lock += 1;
340 }
341 }
342let _u = Unwinder { i: arc2 };
343panic!();
344 })
345 .join();
346let lock = arc.read();
347assert_eq!(*lock, 2);
348 }
349350#[test]
351fn test_rwlock_unsized() {
352let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
353 {
354let b = &mut *rw.write();
355 b[0] = 4;
356 b[2] = 5;
357 }
358let comp: &[i32] = &[4, 2, 5];
359assert_eq!(&*rw.read(), comp);
360 }
361362#[test]
363fn test_rwlock_try_read() {
364let lock = RwLock::new(0isize);
365 {
366let read_guard = lock.read();
367368let read_result = lock.try_read();
369assert!(
370 read_result.is_some(),
371"try_read should succeed while read_guard is in scope"
372);
373374 drop(read_guard);
375 }
376 {
377let upgrade_guard = lock.upgradable_read();
378379let read_result = lock.try_read();
380assert!(
381 read_result.is_some(),
382"try_read should succeed while upgrade_guard is in scope"
383);
384385 drop(upgrade_guard);
386 }
387 {
388let write_guard = lock.write();
389390let read_result = lock.try_read();
391assert!(
392 read_result.is_none(),
393"try_read should fail while write_guard is in scope"
394);
395396 drop(write_guard);
397 }
398 }
399400#[test]
401fn test_rwlock_try_write() {
402let lock = RwLock::new(0isize);
403 {
404let read_guard = lock.read();
405406let write_result = lock.try_write();
407assert!(
408 write_result.is_none(),
409"try_write should fail while read_guard is in scope"
410);
411assert!(lock.is_locked());
412assert!(!lock.is_locked_exclusive());
413414 drop(read_guard);
415 }
416 {
417let upgrade_guard = lock.upgradable_read();
418419let write_result = lock.try_write();
420assert!(
421 write_result.is_none(),
422"try_write should fail while upgrade_guard is in scope"
423);
424assert!(lock.is_locked());
425assert!(!lock.is_locked_exclusive());
426427 drop(upgrade_guard);
428 }
429 {
430let write_guard = lock.write();
431432let write_result = lock.try_write();
433assert!(
434 write_result.is_none(),
435"try_write should fail while write_guard is in scope"
436);
437assert!(lock.is_locked());
438assert!(lock.is_locked_exclusive());
439440 drop(write_guard);
441 }
442 }
443444#[test]
445fn test_rwlock_try_upgrade() {
446let lock = RwLock::new(0isize);
447 {
448let read_guard = lock.read();
449450let upgrade_result = lock.try_upgradable_read();
451assert!(
452 upgrade_result.is_some(),
453"try_upgradable_read should succeed while read_guard is in scope"
454);
455456 drop(read_guard);
457 }
458 {
459let upgrade_guard = lock.upgradable_read();
460461let upgrade_result = lock.try_upgradable_read();
462assert!(
463 upgrade_result.is_none(),
464"try_upgradable_read should fail while upgrade_guard is in scope"
465);
466467 drop(upgrade_guard);
468 }
469 {
470let write_guard = lock.write();
471472let upgrade_result = lock.try_upgradable_read();
473assert!(
474 upgrade_result.is_none(),
475"try_upgradable should fail while write_guard is in scope"
476);
477478 drop(write_guard);
479 }
480 }
481482#[test]
483fn test_into_inner() {
484let m = RwLock::new(NonCopy(10));
485assert_eq!(m.into_inner(), NonCopy(10));
486 }
487488#[test]
489fn test_into_inner_drop() {
490struct Foo(Arc<AtomicUsize>);
491impl Drop for Foo {
492fn drop(&mut self) {
493self.0.fetch_add(1, Ordering::SeqCst);
494 }
495 }
496let num_drops = Arc::new(AtomicUsize::new(0));
497let m = RwLock::new(Foo(num_drops.clone()));
498assert_eq!(num_drops.load(Ordering::SeqCst), 0);
499 {
500let _inner = m.into_inner();
501assert_eq!(num_drops.load(Ordering::SeqCst), 0);
502 }
503assert_eq!(num_drops.load(Ordering::SeqCst), 1);
504 }
505506#[test]
507fn test_get_mut() {
508let mut m = RwLock::new(NonCopy(10));
509*m.get_mut() = NonCopy(20);
510assert_eq!(m.into_inner(), NonCopy(20));
511 }
512513#[test]
514fn test_rwlockguard_sync() {
515fn sync<T: Sync>(_: T) {}
516517let rwlock = RwLock::new(());
518 sync(rwlock.read());
519 sync(rwlock.write());
520 }
521522#[test]
523fn test_rwlock_downgrade() {
524let x = Arc::new(RwLock::new(0));
525let mut handles = Vec::new();
526for _ in 0..8 {
527let x = x.clone();
528 handles.push(thread::spawn(move || {
529for _ in 0..100 {
530let mut writer = x.write();
531*writer += 1;
532let cur_val = *writer;
533let reader = RwLockWriteGuard::downgrade(writer);
534assert_eq!(cur_val, *reader);
535 }
536 }));
537 }
538for handle in handles {
539 handle.join().unwrap()
540 }
541assert_eq!(*x.read(), 800);
542 }
543544#[test]
545fn test_rwlock_recursive() {
546let arc = Arc::new(RwLock::new(1));
547let arc2 = arc.clone();
548let lock1 = arc.read();
549let t = thread::spawn(move || {
550let _lock = arc2.write();
551 });
552553if cfg!(not(all(target_env = "sgx", target_vendor = "fortanix"))) {
554 thread::sleep(Duration::from_millis(100));
555 } else {
556// FIXME: https://github.com/fortanix/rust-sgx/issues/31
557for _ in 0..100 {
558 thread::yield_now();
559 }
560 }
561562// A normal read would block here since there is a pending writer
563let lock2 = arc.read_recursive();
564565// Unblock the thread and join it.
566drop(lock1);
567 drop(lock2);
568 t.join().unwrap();
569 }
570571#[test]
572fn test_rwlock_debug() {
573let x = RwLock::new(vec![0u8, 10]);
574575assert_eq!(format!("{:?}", x), "RwLock { data: [0, 10] }");
576let _lock = x.write();
577assert_eq!(format!("{:?}", x), "RwLock { data: <locked> }");
578 }
579580#[test]
581fn test_clone() {
582let rwlock = RwLock::new(Arc::new(1));
583let a = rwlock.read_recursive();
584let b = a.clone();
585assert_eq!(Arc::strong_count(&b), 2);
586 }
587588#[cfg(feature = "serde")]
589 #[test]
590fn test_serde() {
591let contents: Vec<u8> = vec![0, 1, 2];
592let mutex = RwLock::new(contents.clone());
593594let serialized = serialize(&mutex).unwrap();
595let deserialized: RwLock<Vec<u8>> = deserialize(&serialized).unwrap();
596597assert_eq!(*(mutex.read()), *(deserialized.read()));
598assert_eq!(contents, *(deserialized.read()));
599 }
600601#[test]
602fn test_issue_203() {
603struct Bar(RwLock<()>);
604605impl Drop for Bar {
606fn drop(&mut self) {
607let _n = self.0.write();
608 }
609 }
610611thread_local! {
612static B: Bar = Bar(RwLock::new(()));
613 }
614615 thread::spawn(|| {
616 B.with(|_| ());
617618let a = RwLock::new(());
619let _a = a.read();
620 })
621 .join()
622 .unwrap();
623 }
624625#[test]
626fn test_rw_write_is_locked() {
627let lock = RwLock::new(0isize);
628 {
629let _read_guard = lock.read();
630631assert!(lock.is_locked());
632assert!(!lock.is_locked_exclusive());
633 }
634635 {
636let _write_guard = lock.write();
637638assert!(lock.is_locked());
639assert!(lock.is_locked_exclusive());
640 }
641 }
642}