]> git.proxmox.com Git - rustc.git/blob - library/std/src/sys/sgx/waitqueue/spin_mutex.rs
New upstream version 1.54.0+dfsg1
[rustc.git] / library / std / src / sys / sgx / waitqueue / spin_mutex.rs
1 //! Trivial spinlock-based implementation of `sync::Mutex`.
2 // FIXME: Perhaps use Intel TSX to avoid locking?
3
4 #[cfg(test)]
5 mod tests;
6
7 use crate::cell::UnsafeCell;
8 use crate::hint;
9 use crate::ops::{Deref, DerefMut};
10 use crate::sync::atomic::{AtomicBool, Ordering};
11
12 #[derive(Default)]
13 pub struct SpinMutex<T> {
14 value: UnsafeCell<T>,
15 lock: AtomicBool,
16 }
17
18 unsafe impl<T: Send> Send for SpinMutex<T> {}
19 unsafe impl<T: Send> Sync for SpinMutex<T> {}
20
21 pub struct SpinMutexGuard<'a, T: 'a> {
22 mutex: &'a SpinMutex<T>,
23 }
24
25 impl<'a, T> !Send for SpinMutexGuard<'a, T> {}
26 unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {}
27
28 impl<T> SpinMutex<T> {
29 pub const fn new(value: T) -> Self {
30 SpinMutex { value: UnsafeCell::new(value), lock: AtomicBool::new(false) }
31 }
32
33 #[inline(always)]
34 pub fn lock(&self) -> SpinMutexGuard<'_, T> {
35 loop {
36 match self.try_lock() {
37 None => {
38 while self.lock.load(Ordering::Relaxed) {
39 hint::spin_loop()
40 }
41 }
42 Some(guard) => return guard,
43 }
44 }
45 }
46
47 #[inline(always)]
48 pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> {
49 if self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_ok() {
50 Some(SpinMutexGuard { mutex: self })
51 } else {
52 None
53 }
54 }
55 }
56
57 /// Lock the Mutex or return false.
58 pub macro try_lock_or_false($e:expr) {
59 if let Some(v) = $e.try_lock() { v } else { return false }
60 }
61
62 impl<'a, T> Deref for SpinMutexGuard<'a, T> {
63 type Target = T;
64
65 fn deref(&self) -> &T {
66 unsafe { &*self.mutex.value.get() }
67 }
68 }
69
70 impl<'a, T> DerefMut for SpinMutexGuard<'a, T> {
71 fn deref_mut(&mut self) -> &mut T {
72 unsafe { &mut *self.mutex.value.get() }
73 }
74 }
75
76 impl<'a, T> Drop for SpinMutexGuard<'a, T> {
77 fn drop(&mut self) {
78 self.mutex.lock.store(false, Ordering::Release)
79 }
80 }