4 use crate::num::NonZeroUsize;
5 use crate::sys_common::lazy_box::{LazyBox, LazyInit};
7 use super::waitqueue::{
8 try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
10 use crate::alloc::Layout;
12 struct AllocatedRwLock {
13 readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
14 writer: SpinMutex<WaitVariable<bool>>,
18 inner: LazyBox<AllocatedRwLock>,
21 impl LazyInit for AllocatedRwLock {
22 fn init() -> Box<Self> {
23 Box::new(AllocatedRwLock {
24 readers: SpinMutex::new(WaitVariable::new(None)),
25 writer: SpinMutex::new(WaitVariable::new(false)),
30 // Check at compile time that RwLock's size and alignment matches the C definition
31 // in libunwind (see also `test_c_rwlock_initializer` in `tests`).
33 let rust = Layout::new::<RwLock>();
34 let c = Layout::new::<*mut ()>();
35 assert!(rust.size() == c.size());
36 assert!(rust.align() == c.align());
40 pub const fn new() -> RwLock {
41 RwLock { inner: LazyBox::new() }
46 let lock = &*self.inner;
47 let mut rguard = lock.readers.lock();
48 let wguard = lock.writer.lock();
49 if *wguard.lock_var() || !wguard.queue_empty() {
50 // Another thread has or is waiting for the write lock, wait
52 WaitQueue::wait(rguard, || {});
53 // Another thread has passed the lock to us
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);
62 pub unsafe fn try_read(&self) -> bool {
63 let lock = &*self.inner;
64 let mut rguard = try_lock_or_false!(lock.readers);
65 let wguard = try_lock_or_false!(lock.writer);
66 if *wguard.lock_var() || !wguard.queue_empty() {
67 // Another thread has or is waiting for the write lock
70 // No waiting writers, acquire the read lock
71 *rguard.lock_var_mut() =
72 NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
79 let lock = &*self.inner;
80 let rguard = lock.readers.lock();
81 let mut wguard = lock.writer.lock();
82 if *wguard.lock_var() || rguard.lock_var().is_some() {
83 // Another thread has the lock, wait
85 WaitQueue::wait(wguard, || {});
86 // Another thread has passed the lock to us
88 // We are just now obtaining the lock
89 *wguard.lock_var_mut() = true;
94 pub fn try_write(&self) -> bool {
95 let lock = &*self.inner;
96 let rguard = try_lock_or_false!(lock.readers);
97 let mut wguard = try_lock_or_false!(lock.writer);
98 if *wguard.lock_var() || rguard.lock_var().is_some() {
99 // Another thread has the lock
102 // We are just now obtaining the lock
103 *wguard.lock_var_mut() = true;
109 unsafe fn __read_unlock(
111 mut rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZeroUsize>>>,
112 wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
114 *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1);
115 if rguard.lock_var().is_some() {
116 // There are other active readers
118 if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
119 // A writer was waiting, pass the lock
120 *wguard.lock_var_mut() = true;
121 wguard.drop_after(rguard);
123 // No writers were waiting, the lock is released
124 rtassert!(rguard.queue_empty());
130 pub unsafe fn read_unlock(&self) {
131 let lock = &*self.inner;
132 let rguard = lock.readers.lock();
133 let wguard = lock.writer.lock();
134 unsafe { self.__read_unlock(rguard, wguard) };
138 unsafe fn __write_unlock(
140 rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZeroUsize>>>,
141 wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
143 match WaitQueue::notify_one(wguard) {
145 // No writers waiting, release the write lock
146 *wguard.lock_var_mut() = false;
147 if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
148 // One or more readers were waiting, pass the lock to them
149 if let NotifiedTcs::All { count } = rguard.notified_tcs() {
150 *rguard.lock_var_mut() = Some(count)
152 unreachable!() // called notify_all
154 rguard.drop_after(wguard);
156 // No readers waiting, the lock is released
160 // There was a thread waiting for write, just pass the lock
161 wguard.drop_after(rguard);
167 pub unsafe fn write_unlock(&self) {
168 let lock = &*self.inner;
169 let rguard = lock.readers.lock();
170 let wguard = lock.writer.lock();
171 unsafe { self.__write_unlock(rguard, wguard) };
174 // only used by __rust_rwlock_unlock below
176 #[cfg_attr(test, allow(dead_code))]
177 unsafe fn unlock(&self) {
178 let lock = &*self.inner;
179 let rguard = lock.readers.lock();
180 let wguard = lock.writer.lock();
181 if *wguard.lock_var() == true {
182 unsafe { self.__write_unlock(rguard, wguard) };
184 unsafe { self.__read_unlock(rguard, wguard) };
189 // The following functions are needed by libunwind. These symbols are named
190 // in pre-link args for the target specification, so keep that in sync.
192 const EINVAL: i32 = 22;
196 pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RwLock) -> i32 {
200 unsafe { (*p).read() };
206 pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RwLock) -> i32 {
210 unsafe { (*p).write() };
216 pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 {
220 unsafe { (*p).unlock() };