1 use crate::cell::UnsafeCell;
3 use crate::sync::atomic::{AtomicU32, Ordering};
4 use crate::sys::cloudabi::abi;
8 static __pthread_thread_id: abi::tid;
12 static mut RDLOCKS_ACQUIRED: u32 = 0;
15 lock: UnsafeCell<AtomicU32>,
18 pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 {
22 unsafe impl Send for RWLock {}
23 unsafe impl Sync for RWLock {}
25 const NEW: RWLock = RWLock {
26 lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)),
30 pub const fn new() -> RWLock {
34 pub unsafe fn try_read(&self) -> bool {
35 let lock = self.lock.get();
36 let mut old = abi::LOCK_UNLOCKED.0;
38 (*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
40 if (cur & abi::LOCK_WRLOCKED.0) != 0 {
41 // Another thread already has a write lock.
43 old & !abi::LOCK_KERNEL_MANAGED.0,
44 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
45 "Attempted to acquire a read lock while holding a write lock"
48 } else if (old & abi::LOCK_KERNEL_MANAGED.0) != 0 && RDLOCKS_ACQUIRED == 0 {
49 // Lock has threads waiting for the lock. Only acquire
50 // the lock if we have already acquired read locks. In
51 // that case, it is justified to acquire this lock to
52 // prevent a deadlock.
58 RDLOCKS_ACQUIRED += 1;
62 pub unsafe fn read(&self) {
64 // Call into the kernel to acquire a read lock.
65 let lock = self.lock.get();
66 let subscription = abi::subscription {
67 type_: abi::eventtype::LOCK_RDLOCK,
68 union: abi::subscription_union {
69 lock: abi::subscription_lock {
70 lock: lock as *mut abi::lock,
71 lock_scope: abi::scope::PRIVATE,
76 let mut event: abi::event = mem::uninitialized();
77 let mut nevents: usize = mem::uninitialized();
78 let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
79 assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire read lock");
83 "Failed to acquire read lock"
86 RDLOCKS_ACQUIRED += 1;
90 pub unsafe fn read_unlock(&self) {
91 // Perform a read unlock. We can do this in userspace, except when
92 // other threads are blocked and we are performing the last unlock.
93 // In that case, call into the kernel.
95 // Other threads may attempt to increment the read lock count,
96 // meaning that the call into the kernel could be spurious. To
97 // prevent this from happening, upgrade to a write lock first. This
98 // allows us to call into the kernel, having the guarantee that the
99 // lock value will not change in the meantime.
100 assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count");
103 let lock = self.lock.get();
104 if old == 1 | abi::LOCK_KERNEL_MANAGED.0 {
105 // Last read lock while threads are waiting. Attempt to upgrade
106 // to a write lock before calling into the kernel to unlock.
107 if let Err(cur) = (*lock).compare_exchange_weak(
109 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0,
115 // Call into the kernel to unlock.
116 let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
117 assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
121 // No threads waiting or not the last read lock. Just decrement
122 // the read lock count.
124 old & !abi::LOCK_KERNEL_MANAGED.0,
126 "This rwlock is not locked"
129 old & abi::LOCK_WRLOCKED.0,
131 "Attempted to read-unlock a write-locked rwlock"
133 if let Err(cur) = (*lock).compare_exchange_weak(
146 RDLOCKS_ACQUIRED -= 1;
149 pub unsafe fn try_write(&self) -> bool {
150 // Attempt to acquire the lock.
151 let lock = self.lock.get();
152 if let Err(old) = (*lock).compare_exchange(
153 abi::LOCK_UNLOCKED.0,
154 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
158 // Failure. Crash upon recursive acquisition.
160 old & !abi::LOCK_KERNEL_MANAGED.0,
161 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
162 "Attempted to recursive write-lock a rwlock",
171 pub unsafe fn write(&self) {
172 if !self.try_write() {
173 // Call into the kernel to acquire a write lock.
174 let lock = self.lock.get();
175 let subscription = abi::subscription {
176 type_: abi::eventtype::LOCK_WRLOCK,
177 union: abi::subscription_union {
178 lock: abi::subscription_lock {
179 lock: lock as *mut abi::lock,
180 lock_scope: abi::scope::PRIVATE,
185 let mut event: abi::event = mem::uninitialized();
186 let mut nevents: usize = mem::uninitialized();
187 let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
188 assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire write lock");
192 "Failed to acquire write lock"
197 pub unsafe fn write_unlock(&self) {
198 let lock = self.lock.get();
200 (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
201 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
202 "This rwlock is not write-locked by this thread"
207 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
208 abi::LOCK_UNLOCKED.0,
214 // Lock is managed by kernelspace. Call into the kernel
215 // to unblock waiting threads.
216 let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
217 assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
221 pub unsafe fn destroy(&self) {
222 let lock = self.lock.get();
224 (*lock).load(Ordering::Relaxed),
225 abi::LOCK_UNLOCKED.0,
226 "Attempted to destroy locked rwlock"