diff options
Diffstat (limited to 'library/std/src/sys/sgx/mutex.rs')
| -rw-r--r-- | library/std/src/sys/sgx/mutex.rs | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs new file mode 100644 index 00000000000..4911c2f5387 --- /dev/null +++ b/library/std/src/sys/sgx/mutex.rs @@ -0,0 +1,140 @@ +use fortanix_sgx_abi::Tcs; + +use super::abi::thread; + +use super::waitqueue::{try_lock_or_false, NotifiedTcs, SpinMutex, WaitQueue, WaitVariable}; + +pub struct Mutex { + inner: SpinMutex<WaitVariable<bool>>, +} + +// Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28 +impl Mutex { + pub const fn new() -> Mutex { + Mutex { inner: SpinMutex::new(WaitVariable::new(false)) } + } + + #[inline] + pub unsafe fn init(&mut self) {} + + #[inline] + pub unsafe fn lock(&self) { + let mut guard = self.inner.lock(); + if *guard.lock_var() { + // Another thread has the lock, wait + WaitQueue::wait(guard, || {}) + // Another thread has passed the lock to us + } else { + // We are just now obtaining the lock + *guard.lock_var_mut() = true; + } + } + + #[inline] + pub unsafe fn unlock(&self) { + let guard = self.inner.lock(); + if let Err(mut guard) = WaitQueue::notify_one(guard) { + // No other waiters, unlock + *guard.lock_var_mut() = false; + } else { + // There was a thread waiting, just pass the lock + } + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + let mut guard = try_lock_or_false!(self.inner); + if *guard.lock_var() { + // Another thread has the lock + false + } else { + // We are just now obtaining the lock + *guard.lock_var_mut() = true; + true + } + } + + #[inline] + pub unsafe fn destroy(&self) {} +} + +struct ReentrantLock { + owner: Option<Tcs>, + count: usize, +} + +pub struct ReentrantMutex { + inner: SpinMutex<WaitVariable<ReentrantLock>>, +} + +impl ReentrantMutex { + pub const fn uninitialized() -> ReentrantMutex { + ReentrantMutex { + inner: SpinMutex::new(WaitVariable::new(ReentrantLock { owner: None, count: 0 })), + } + } + + #[inline] + pub unsafe fn init(&self) {} + + #[inline] + pub unsafe fn lock(&self) { + let mut guard = self.inner.lock(); + match guard.lock_var().owner { + Some(tcs) if tcs != thread::current() => { + // Another thread has the lock, wait + WaitQueue::wait(guard, || {}); + // Another thread has passed the lock to us + } + _ => { + // We are just now obtaining the lock + guard.lock_var_mut().owner = Some(thread::current()); + guard.lock_var_mut().count += 1; + } + } + } + + #[inline] + pub unsafe fn unlock(&self) { + let mut guard = self.inner.lock(); + if guard.lock_var().count > 1 { + guard.lock_var_mut().count -= 1; + } else { + match WaitQueue::notify_one(guard) { + Err(mut guard) => { + // No other waiters, unlock + guard.lock_var_mut().count = 0; + guard.lock_var_mut().owner = None; + } + Ok(mut guard) => { + // There was a thread waiting, just pass the lock + if let NotifiedTcs::Single(tcs) = guard.notified_tcs() { + guard.lock_var_mut().owner = Some(tcs) + } else { + unreachable!() // called notify_one + } + } + } + } + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + let mut guard = try_lock_or_false!(self.inner); + match guard.lock_var().owner { + Some(tcs) if tcs != thread::current() => { + // Another thread has the lock + false + } + _ => { + // We are just now obtaining the lock + guard.lock_var_mut().owner = Some(thread::current()); + guard.lock_var_mut().count += 1; + true + } + } + } + + #[inline] + pub unsafe fn destroy(&self) {} +} |
