microlock/
untimed.rs

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
15/// An untimed lock. This can be locked and unlocked, but it will never unlock
16/// on its own (see [`crate::TimedLock`] for an expiring lock). If a thread
17/// calls wait_here on a locked lock, it will wait until the lock is unlocked
18/// by another thread.
19pub struct UntimedLock {
20    locked: Mutex<bool>,
21    double_unlock: Mutex<bool>,
22    waiting: AtomicU32,
23    condvar: Condvar,
24}
25
26impl UntimedLock {
27    /// Creates a new untimed lock that is either unlocked or locked.
28    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    /// Creates a new untimed lock that is unlocked.
38    pub const fn unlocked() -> Self {
39        Self::new(false)
40    }
41
42    /// Creates a new untimed lock that is locked.
43    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}