]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/rwlock.rs
Rollup merge of #56217 - frewsxcv:frewsxcv-float-parse, r=QuietMisdreavus
[rust.git] / src / libstd / sys / sgx / rwlock.rs
1 use alloc::{self, Layout};
2 use num::NonZeroUsize;
3 use slice;
4 use str;
5
6 use super::waitqueue::{
7     try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
8 };
9 use mem;
10
11 pub struct RWLock {
12     readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
13     writer: SpinMutex<WaitVariable<bool>>,
14 }
15
16 // Below is to check at compile time, that RWLock has size of 128 bytes.
17 #[allow(dead_code)]
18 unsafe fn rw_lock_size_assert(r: RWLock) {
19     mem::transmute::<RWLock, [u8; 128]>(r);
20 }
21
22 //unsafe impl Send for RWLock {}
23 //unsafe impl Sync for RWLock {} // FIXME
24
25 impl RWLock {
26     pub const fn new() -> RWLock {
27         RWLock {
28             readers: SpinMutex::new(WaitVariable::new(None)),
29             writer: SpinMutex::new(WaitVariable::new(false)),
30         }
31     }
32
33     #[inline]
34     pub unsafe fn read(&self) {
35         let mut rguard = self.readers.lock();
36         let wguard = self.writer.lock();
37         if *wguard.lock_var() || !wguard.queue_empty() {
38             // Another thread has or is waiting for the write lock, wait
39             drop(wguard);
40             WaitQueue::wait(rguard);
41             // Another thread has passed the lock to us
42         } else {
43             // No waiting writers, acquire the read lock
44             *rguard.lock_var_mut() =
45                 NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
46         }
47     }
48
49     #[inline]
50     pub unsafe fn try_read(&self) -> bool {
51         let mut rguard = try_lock_or_false!(self.readers);
52         let wguard = try_lock_or_false!(self.writer);
53         if *wguard.lock_var() || !wguard.queue_empty() {
54             // Another thread has or is waiting for the write lock
55             false
56         } else {
57             // No waiting writers, acquire the read lock
58             *rguard.lock_var_mut() =
59                 NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
60             true
61         }
62     }
63
64     #[inline]
65     pub unsafe fn write(&self) {
66         let rguard = self.readers.lock();
67         let mut wguard = self.writer.lock();
68         if *wguard.lock_var() || rguard.lock_var().is_some() {
69             // Another thread has the lock, wait
70             drop(rguard);
71             WaitQueue::wait(wguard);
72             // Another thread has passed the lock to us
73         } else {
74             // We are just now obtaining the lock
75             *wguard.lock_var_mut() = true;
76         }
77     }
78
79     #[inline]
80     pub unsafe fn try_write(&self) -> bool {
81         let rguard = try_lock_or_false!(self.readers);
82         let mut wguard = try_lock_or_false!(self.writer);
83         if *wguard.lock_var() || rguard.lock_var().is_some() {
84             // Another thread has the lock
85             false
86         } else {
87             // We are just now obtaining the lock
88             *wguard.lock_var_mut() = true;
89             true
90         }
91     }
92
93     #[inline]
94     unsafe fn __read_unlock(
95         &self,
96         mut rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>,
97         wguard: SpinMutexGuard<WaitVariable<bool>>,
98     ) {
99         *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1);
100         if rguard.lock_var().is_some() {
101             // There are other active readers
102         } else {
103             if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
104                 // A writer was waiting, pass the lock
105                 *wguard.lock_var_mut() = true;
106             } else {
107                 // No writers were waiting, the lock is released
108                 assert!(rguard.queue_empty());
109             }
110         }
111     }
112
113     #[inline]
114     pub unsafe fn read_unlock(&self) {
115         let rguard = self.readers.lock();
116         let wguard = self.writer.lock();
117         self.__read_unlock(rguard, wguard);
118     }
119
120     #[inline]
121     unsafe fn __write_unlock(
122         &self,
123         rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>,
124         wguard: SpinMutexGuard<WaitVariable<bool>>,
125     ) {
126         if let Err(mut wguard) = WaitQueue::notify_one(wguard) {
127             // No writers waiting, release the write lock
128             *wguard.lock_var_mut() = false;
129             if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
130                 // One or more readers were waiting, pass the lock to them
131                 if let NotifiedTcs::All { count } = rguard.notified_tcs() {
132                     *rguard.lock_var_mut() = Some(count)
133                 } else {
134                     unreachable!() // called notify_all
135                 }
136             } else {
137                 // No readers waiting, the lock is released
138             }
139         } else {
140             // There was a thread waiting for write, just pass the lock
141         }
142     }
143
144     #[inline]
145     pub unsafe fn write_unlock(&self) {
146         let rguard = self.readers.lock();
147         let wguard = self.writer.lock();
148         self.__write_unlock(rguard, wguard);
149     }
150
151     // only used by __rust_rwlock_unlock below
152     #[inline]
153     unsafe fn unlock(&self) {
154         let rguard = self.readers.lock();
155         let wguard = self.writer.lock();
156         if *wguard.lock_var() == true {
157             self.__write_unlock(rguard, wguard);
158         } else {
159             self.__read_unlock(rguard, wguard);
160         }
161     }
162
163     #[inline]
164     pub unsafe fn destroy(&self) {}
165 }
166
167 const EINVAL: i32 = 22;
168
169 // used by libunwind port
170 #[no_mangle]
171 pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
172     if p.is_null() {
173         return EINVAL;
174     }
175     (*p).read();
176     return 0;
177 }
178
179 #[no_mangle]
180 pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 {
181     if p.is_null() {
182         return EINVAL;
183     }
184     (*p).write();
185     return 0;
186 }
187 #[no_mangle]
188 pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
189     if p.is_null() {
190         return EINVAL;
191     }
192     (*p).unlock();
193     return 0;
194 }
195
196 // the following functions are also used by the libunwind port. They're
197 // included here to make sure parallel codegen and LTO don't mess things up.
198 #[no_mangle]
199 pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
200     if s < 0 {
201         return;
202     }
203     let buf = slice::from_raw_parts(m as *const u8, s as _);
204     if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
205         eprint!("{}", s);
206     }
207 }
208
209 #[no_mangle]
210 pub unsafe extern "C" fn __rust_abort() {
211     ::sys::abort_internal();
212 }
213
214 #[no_mangle]
215 pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
216     alloc::alloc(Layout::from_size_align_unchecked(size, align))
217 }
218
219 #[no_mangle]
220 pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
221     alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
222 }
223
224 #[cfg(test)]
225 mod tests {
226
227     use super::*;
228     use core::array::FixedSizeArray;
229     use mem::MaybeUninit;
230     use {mem, ptr};
231
232     // The below test verifies that the bytes of initialized RWLock are the ones
233     // we use in libunwind.
234     // If they change we need to update src/UnwindRustSgx.h in libunwind.
235     #[test]
236     fn test_c_rwlock_initializer() {
237         const RWLOCK_INIT: &[u8] = &[
238             0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
239             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
240             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
241             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
242             0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
243             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
244             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
245             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
246             0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
247             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
248             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
249             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
250             0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
251             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
252             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
253             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
254         ];
255
256         let mut init = MaybeUninit::<RWLock>::zeroed();
257         init.set(RWLock::new());
258         assert_eq!(
259             mem::transmute::<_, [u8; 128]>(init.into_inner()).as_slice(),
260             RWLOCK_INIT
261         );
262     }
263 }