1use std::{
2 sync::{
3 atomic::{AtomicU32, Ordering},
4 Condvar, Mutex,
5 },
6 thread,
7 time::Duration,
8};
9
10use crate::{
11 timer::{Timed, Timer, TimerDuration},
12 Lock,
13};
14
15pub struct UntimedLock {
20 locked: Mutex<bool>,
21 double_unlock: Mutex<bool>,
22 waiting: AtomicU32,
23 condvar: Condvar,
24}
25
26impl UntimedLock {
27 pub const fn new(locked: bool) -> Self {
29 Self {
30 locked: Mutex::new(locked),
31 double_unlock: Mutex::new(false),
32 waiting: AtomicU32::new(0),
33 condvar: Condvar::new(),
34 }
35 }
36
37 pub const fn unlocked() -> Self {
39 Self::new(false)
40 }
41
42 pub const fn locked() -> Self {
44 Self::new(true)
45 }
46}
47
48impl Lock for UntimedLock {
49 fn is_locked(&self) -> bool {
50 *self.locked.lock().unwrap()
51 }
52
53 fn lock(&self) {
54 *self.locked.lock().unwrap() = true;
55 *self.double_unlock.lock().unwrap() = false;
56 }
57
58 fn try_lock(&self) -> bool {
59 let mut double_unlock = self.double_unlock.lock().unwrap();
60 if !*double_unlock {
61 *self.locked.lock().unwrap() = true;
62 return true;
63 }
64 *double_unlock = false;
65 drop(double_unlock);
66 false
67 }
68
69 fn unlock(&self) {
70 {
71 let mut locked = self.locked.lock().unwrap();
72 let mut double_unlock = self.double_unlock.lock().unwrap();
73 if !*locked {
74 *double_unlock = true;
75 return;
76 }
77 *locked = false;
78 self.condvar.notify_all();
79 }
80 while self.waiting.load(Ordering::Relaxed) > 0 {
81 thread::yield_now();
82 }
83 }
84
85 fn wait_here(&self) {
86 self.waiting.fetch_add(1, Ordering::Relaxed);
87 {
88 let mut locked = self.locked.lock().unwrap();
89 while *locked {
90 locked = self.condvar.wait(locked).unwrap();
91 }
92 }
93 self.waiting.fetch_sub(1, Ordering::Relaxed);
94 while self.waiting.load(Ordering::Relaxed) > 0 {
95 thread::yield_now();
96 }
97 }
98
99 fn wait_here_for(&self, timeout: TimerDuration) {
100 self.waiting.fetch_add(1, Ordering::Relaxed);
101 {
102 let mut locked = self.locked.lock().unwrap();
103 let timer = Timer::new(timeout);
104 while *locked && !timer.has_elapsed() {
105 locked = self
106 .condvar
107 .wait_timeout(locked, timer.time_left().to_real())
108 .unwrap()
109 .0;
110 }
111 }
112 self.waiting.fetch_sub(1, Ordering::Relaxed);
113 while self.waiting.load(Ordering::Relaxed) > 0 {
114 thread::yield_now();
115 }
116 }
117
118 fn wait_here_for_ms(&self, timeout_ms: u64) {
119 self.wait_here_for(TimerDuration::Real(Duration::from_millis(timeout_ms)));
120 }
121}