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