]> git.proxmox.com Git - rustc.git/blame - library/std/src/sys/sgx/rwlock.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / library / std / src / sys / sgx / rwlock.rs
CommitLineData
1b1a35ee
XL
1#[cfg(test)]
2mod tests;
3
532ac7d7 4use crate::num::NonZeroUsize;
0731742a
XL
5
6use super::waitqueue::{
7 try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
8};
532ac7d7 9use crate::mem;
0731742a
XL
10
11pub struct RWLock {
12 readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
13 writer: SpinMutex<WaitVariable<bool>>,
14}
15
74b04a01 16// Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below)
0731742a
XL
17#[allow(dead_code)]
18unsafe fn rw_lock_size_assert(r: RWLock) {
74b04a01 19 mem::transmute::<RWLock, [u8; 144]>(r);
0731742a
XL
20}
21
0731742a
XL
22impl RWLock {
23 pub const fn new() -> RWLock {
24 RWLock {
25 readers: SpinMutex::new(WaitVariable::new(None)),
26 writer: SpinMutex::new(WaitVariable::new(false)),
27 }
28 }
29
30 #[inline]
31 pub unsafe fn read(&self) {
32 let mut rguard = self.readers.lock();
33 let wguard = self.writer.lock();
34 if *wguard.lock_var() || !wguard.queue_empty() {
35 // Another thread has or is waiting for the write lock, wait
36 drop(wguard);
dfeec247
XL
37 WaitQueue::wait(rguard, || {});
38 // Another thread has passed the lock to us
0731742a
XL
39 } else {
40 // No waiting writers, acquire the read lock
41 *rguard.lock_var_mut() =
42 NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
43 }
44 }
45
46 #[inline]
47 pub unsafe fn try_read(&self) -> bool {
48 let mut rguard = try_lock_or_false!(self.readers);
49 let wguard = try_lock_or_false!(self.writer);
50 if *wguard.lock_var() || !wguard.queue_empty() {
51 // Another thread has or is waiting for the write lock
52 false
53 } else {
54 // No waiting writers, acquire the read lock
55 *rguard.lock_var_mut() =
56 NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
57 true
58 }
59 }
60
61 #[inline]
62 pub unsafe fn write(&self) {
63 let rguard = self.readers.lock();
64 let mut wguard = self.writer.lock();
65 if *wguard.lock_var() || rguard.lock_var().is_some() {
66 // Another thread has the lock, wait
67 drop(rguard);
dfeec247
XL
68 WaitQueue::wait(wguard, || {});
69 // Another thread has passed the lock to us
0731742a
XL
70 } else {
71 // We are just now obtaining the lock
72 *wguard.lock_var_mut() = true;
73 }
74 }
75
76 #[inline]
77 pub unsafe fn try_write(&self) -> bool {
78 let rguard = try_lock_or_false!(self.readers);
79 let mut wguard = try_lock_or_false!(self.writer);
80 if *wguard.lock_var() || rguard.lock_var().is_some() {
81 // Another thread has the lock
82 false
83 } else {
84 // We are just now obtaining the lock
85 *wguard.lock_var_mut() = true;
86 true
87 }
88 }
89
90 #[inline]
91 unsafe fn __read_unlock(
92 &self,
532ac7d7
XL
93 mut rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZeroUsize>>>,
94 wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
0731742a
XL
95 ) {
96 *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1);
97 if rguard.lock_var().is_some() {
98 // There are other active readers
99 } else {
100 if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
101 // A writer was waiting, pass the lock
102 *wguard.lock_var_mut() = true;
e1599b0c 103 wguard.drop_after(rguard);
0731742a
XL
104 } else {
105 // No writers were waiting, the lock is released
532ac7d7 106 rtassert!(rguard.queue_empty());
0731742a
XL
107 }
108 }
109 }
110
111 #[inline]
112 pub unsafe fn read_unlock(&self) {
113 let rguard = self.readers.lock();
114 let wguard = self.writer.lock();
115 self.__read_unlock(rguard, wguard);
116 }
117
118 #[inline]
119 unsafe fn __write_unlock(
120 &self,
532ac7d7
XL
121 rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZeroUsize>>>,
122 wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
0731742a 123 ) {
e1599b0c
XL
124 match WaitQueue::notify_one(wguard) {
125 Err(mut wguard) => {
126 // No writers waiting, release the write lock
127 *wguard.lock_var_mut() = false;
128 if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
129 // One or more readers were waiting, pass the lock to them
130 if let NotifiedTcs::All { count } = rguard.notified_tcs() {
131 *rguard.lock_var_mut() = Some(count)
132 } else {
133 unreachable!() // called notify_all
134 }
135 rguard.drop_after(wguard);
0731742a 136 } else {
e1599b0c 137 // No readers waiting, the lock is released
0731742a 138 }
dfeec247 139 }
e1599b0c
XL
140 Ok(wguard) => {
141 // There was a thread waiting for write, just pass the lock
142 wguard.drop_after(rguard);
0731742a 143 }
0731742a
XL
144 }
145 }
146
147 #[inline]
148 pub unsafe fn write_unlock(&self) {
149 let rguard = self.readers.lock();
150 let wguard = self.writer.lock();
151 self.__write_unlock(rguard, wguard);
152 }
153
9fa01778 154 // only used by __rust_rwlock_unlock below
0731742a 155 #[inline]
532ac7d7 156 #[cfg_attr(test, allow(dead_code))]
0731742a
XL
157 unsafe fn unlock(&self) {
158 let rguard = self.readers.lock();
159 let wguard = self.writer.lock();
160 if *wguard.lock_var() == true {
161 self.__write_unlock(rguard, wguard);
162 } else {
163 self.__read_unlock(rguard, wguard);
164 }
165 }
166
167 #[inline]
168 pub unsafe fn destroy(&self) {}
169}
170
532ac7d7
XL
171// The following functions are needed by libunwind. These symbols are named
172// in pre-link args for the target specification, so keep that in sync.
173#[cfg(not(test))]
0731742a
XL
174const EINVAL: i32 = 22;
175
532ac7d7 176#[cfg(not(test))]
0731742a
XL
177#[no_mangle]
178pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
179 if p.is_null() {
180 return EINVAL;
181 }
182 (*p).read();
183 return 0;
184}
185
532ac7d7 186#[cfg(not(test))]
0731742a
XL
187#[no_mangle]
188pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 {
189 if p.is_null() {
190 return EINVAL;
191 }
192 (*p).write();
193 return 0;
194}
532ac7d7 195#[cfg(not(test))]
0731742a
XL
196#[no_mangle]
197pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
198 if p.is_null() {
199 return EINVAL;
200 }
201 (*p).unlock();
202 return 0;
203}