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.
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.
11 use fortanix_sgx_abi::Tcs;
13 use super::abi::thread;
15 use super::waitqueue::{WaitVariable, WaitQueue, SpinMutex, NotifiedTcs, try_lock_or_false};
18 inner: SpinMutex<WaitVariable<bool>>,
21 // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
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)) }
29 pub unsafe fn init(&mut self) {}
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
39 // We are just now obtaining the lock
40 *guard.lock_var_mut() = true;
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;
51 // There was a thread waiting, just pass the lock
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
62 // We are just now obtaining the lock
63 *guard.lock_var_mut() = true;
69 pub unsafe fn destroy(&self) {}
72 struct ReentrantLock {
77 pub struct ReentrantMutex {
78 inner: SpinMutex<WaitVariable<ReentrantLock>>,
82 #[unstable(feature = "sgx_internals", issue = "0")] // FIXME: min_const_fn
83 pub const fn uninitialized() -> ReentrantMutex {
85 inner: SpinMutex::new(WaitVariable::new(ReentrantLock { owner: None, count: 0 }))
90 pub unsafe fn init(&mut self) {}
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
102 // We are just now obtaining the lock
103 guard.lock_var_mut().owner = Some(thread::current());
104 guard.lock_var_mut().count += 1;
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;
115 match WaitQueue::notify_one(guard) {
117 // No other waiters, unlock
118 guard.lock_var_mut().count = 0;
119 guard.lock_var_mut().owner = None;
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)
126 unreachable!() // called notify_one
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
142 // We are just now obtaining the lock
143 guard.lock_var_mut().owner = Some(thread::current());
144 guard.lock_var_mut().count += 1;
151 pub unsafe fn destroy(&self) {}