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