blob: aa747d56b0d3bf2b353ee3683c323e2f2e6ef12f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable};
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
pub struct Mutex {
inner: SpinMutex<WaitVariable<bool>>,
}
// not movable: see UnsafeList implementation
pub(crate) type MovableMutex = LazyBox<Mutex>;
impl LazyInit for Mutex {
fn init() -> Box<Self> {
Box::new(Self::new())
}
}
// 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 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
}
}
}
|