1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use num::NonZeroUsize;
13 use super::waitqueue::{WaitVariable, WaitQueue, SpinMutex, NotifiedTcs, try_lock_or_false};
16 readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
17 writer: SpinMutex<WaitVariable<bool>>,
20 //unsafe impl Send for RWLock {}
21 //unsafe impl Sync for RWLock {} // FIXME
24 pub const fn new() -> RWLock {
26 readers: SpinMutex::new(WaitVariable::new(None)),
27 writer: SpinMutex::new(WaitVariable::new(false))
32 pub unsafe fn read(&self) {
33 let mut rguard = self.readers.lock();
34 let wguard = self.writer.lock();
35 if *wguard.lock_var() || !wguard.queue_empty() {
36 // Another thread has or is waiting for the write lock, wait
38 WaitQueue::wait(rguard);
39 // Another thread has passed the lock to us
41 // No waiting writers, acquire the read lock
42 *rguard.lock_var_mut() =
43 NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
48 pub unsafe fn try_read(&self) -> bool {
49 let mut rguard = try_lock_or_false!(self.readers);
50 let wguard = try_lock_or_false!(self.writer);
51 if *wguard.lock_var() || !wguard.queue_empty() {
52 // Another thread has or is waiting for the write lock
55 // No waiting writers, acquire the read lock
56 *rguard.lock_var_mut() =
57 NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
63 pub unsafe fn write(&self) {
64 let rguard = self.readers.lock();
65 let mut wguard = self.writer.lock();
66 if *wguard.lock_var() || rguard.lock_var().is_some() {
67 // Another thread has the lock, wait
69 WaitQueue::wait(wguard);
70 // Another thread has passed the lock to us
72 // We are just now obtaining the lock
73 *wguard.lock_var_mut() = true;
78 pub unsafe fn try_write(&self) -> bool {
79 let rguard = try_lock_or_false!(self.readers);
80 let mut wguard = try_lock_or_false!(self.writer);
81 if *wguard.lock_var() || rguard.lock_var().is_some() {
82 // Another thread has the lock
85 // We are just now obtaining the lock
86 *wguard.lock_var_mut() = true;
92 pub unsafe fn read_unlock(&self) {
93 let mut rguard = self.readers.lock();
94 let wguard = self.writer.lock();
95 *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1);
96 if rguard.lock_var().is_some() {
97 // There are other active readers
99 if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
100 // A writer was waiting, pass the lock
101 *wguard.lock_var_mut() = true;
103 // No writers were waiting, the lock is released
104 assert!(rguard.queue_empty());
110 pub unsafe fn write_unlock(&self) {
111 let rguard = self.readers.lock();
112 let wguard = self.writer.lock();
113 if let Err(mut wguard) = WaitQueue::notify_one(wguard) {
114 // No writers waiting, release the write lock
115 *wguard.lock_var_mut() = false;
116 if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
117 // One or more readers were waiting, pass the lock to them
118 if let NotifiedTcs::All { count } = rguard.notified_tcs() {
119 *rguard.lock_var_mut() = Some(count)
121 unreachable!() // called notify_all
124 // No readers waiting, the lock is released
127 // There was a thread waiting for write, just pass the lock
132 pub unsafe fn destroy(&self) {}