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