]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/mutex.rs
Rollup merge of #56242 - GuillaumeGomez:iterator-missing-link, r=Centril
[rust.git] / src / libstd / sys / sgx / mutex.rs
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.
4 //
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.
10
11 use fortanix_sgx_abi::Tcs;
12
13 use super::abi::thread;
14
15 use super::waitqueue::{WaitVariable, WaitQueue, SpinMutex, NotifiedTcs, try_lock_or_false};
16
17 pub struct Mutex {
18     inner: SpinMutex<WaitVariable<bool>>,
19 }
20
21 // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
22 impl Mutex {
23     pub const fn new() -> Mutex {
24         Mutex { inner: SpinMutex::new(WaitVariable::new(false)) }
25     }
26
27     #[inline]
28     pub unsafe fn init(&mut self) {}
29
30     #[inline]
31     pub unsafe fn lock(&self) {
32         let mut guard = self.inner.lock();
33         if *guard.lock_var() {
34             // Another thread has the lock, wait
35             WaitQueue::wait(guard)
36             // Another thread has passed the lock to us
37         } else {
38             // We are just now obtaining the lock
39             *guard.lock_var_mut() = true;
40         }
41     }
42
43     #[inline]
44     pub unsafe fn unlock(&self) {
45         let guard = self.inner.lock();
46         if let Err(mut guard) = WaitQueue::notify_one(guard) {
47             // No other waiters, unlock
48             *guard.lock_var_mut() = false;
49         } else {
50             // There was a thread waiting, just pass the lock
51         }
52     }
53
54     #[inline]
55     pub unsafe fn try_lock(&self) -> bool {
56         let mut guard = try_lock_or_false!(self.inner);
57         if *guard.lock_var() {
58             // Another thread has the lock
59             false
60         } else {
61             // We are just now obtaining the lock
62             *guard.lock_var_mut() = true;
63             true
64         }
65     }
66
67     #[inline]
68     pub unsafe fn destroy(&self) {}
69 }
70
71 struct ReentrantLock {
72     owner: Option<Tcs>,
73     count: usize
74 }
75
76 pub struct ReentrantMutex {
77     inner: SpinMutex<WaitVariable<ReentrantLock>>,
78 }
79
80 impl ReentrantMutex {
81     pub const fn uninitialized() -> ReentrantMutex {
82         ReentrantMutex {
83             inner: SpinMutex::new(WaitVariable::new(ReentrantLock { owner: None, count: 0 }))
84         }
85     }
86
87     #[inline]
88     pub unsafe fn init(&mut self) {}
89
90     #[inline]
91     pub unsafe fn lock(&self) {
92         let mut guard = self.inner.lock();
93         match guard.lock_var().owner {
94             Some(tcs) if tcs != thread::current() => {
95                 // Another thread has the lock, wait
96                 WaitQueue::wait(guard);
97                 // Another thread has passed the lock to us
98             },
99             _ => {
100                 // We are just now obtaining the lock
101                 guard.lock_var_mut().owner = Some(thread::current());
102                 guard.lock_var_mut().count += 1;
103             },
104         }
105     }
106
107     #[inline]
108     pub unsafe fn unlock(&self) {
109         let mut guard = self.inner.lock();
110         if guard.lock_var().count > 1 {
111             guard.lock_var_mut().count -= 1;
112         } else {
113             match WaitQueue::notify_one(guard) {
114                 Err(mut guard) => {
115                     // No other waiters, unlock
116                     guard.lock_var_mut().count = 0;
117                     guard.lock_var_mut().owner = None;
118                 },
119                 Ok(mut guard) => {
120                     // There was a thread waiting, just pass the lock
121                     if let NotifiedTcs::Single(tcs) = guard.notified_tcs() {
122                         guard.lock_var_mut().owner = Some(tcs)
123                     } else {
124                         unreachable!() // called notify_one
125                     }
126                 }
127             }
128         }
129     }
130
131     #[inline]
132     pub unsafe fn try_lock(&self) -> bool {
133         let mut guard = try_lock_or_false!(self.inner);
134         match guard.lock_var().owner {
135             Some(tcs) if tcs != thread::current() => {
136                 // Another thread has the lock
137                 false
138             },
139             _ => {
140                 // We are just now obtaining the lock
141                 guard.lock_var_mut().owner = Some(thread::current());
142                 guard.lock_var_mut().count += 1;
143                 true
144             },
145         }
146     }
147
148     #[inline]
149     pub unsafe fn destroy(&self) {}
150 }