chj_rustbin/
checked_mutex.rs1use std::{
14 ops::{Deref, DerefMut},
15 sync::{Mutex, MutexGuard},
16 thread::ThreadId,
17};
18
19#[derive(Debug, thiserror::Error)]
20pub enum CheckedMutexError {
21 #[error("mutex is poisoned")]
24 PoisonError,
25 #[error("mutex is locked by the same thread already")]
26 LockedByOurselves,
27}
28
29#[derive(Debug)]
30pub struct CheckedMutex<T> {
31 locked_by: Mutex<Option<ThreadId>>,
32 mutex: Mutex<T>,
33}
34
35pub struct CheckedMutexGuard<'m, T> {
36 checked_mutex: &'m CheckedMutex<T>,
37 guard: MutexGuard<'m, T>,
38}
39
40impl<'m, T> Deref for CheckedMutexGuard<'m, T> {
41 type Target = T;
42
43 fn deref(&self) -> &Self::Target {
44 self.guard.deref()
45 }
46}
47
48impl<'m, T> DerefMut for CheckedMutexGuard<'m, T> {
49 fn deref_mut(&mut self) -> &mut Self::Target {
50 self.guard.deref_mut()
51 }
52}
53
54impl<'m, T> Drop for CheckedMutexGuard<'m, T> {
55 fn drop(&mut self) {
56 let mut locked_by = self.checked_mutex.locked_by.lock().unwrap();
57 *locked_by = None;
61 }
62}
63
64impl<T> CheckedMutex<T> {
65 pub fn new(value: T) -> Self {
66 Self {
67 locked_by: Mutex::new(None),
68 mutex: Mutex::new(value),
69 }
70 }
71
72 pub fn lock(&self) -> Result<CheckedMutexGuard<'_, T>, CheckedMutexError> {
73 let mut locked_by = self.locked_by.lock().unwrap();
79 let id = std::thread::current().id();
80 if let Some(locking_id) = *locked_by {
81 if locking_id == id {
82 return Err(CheckedMutexError::LockedByOurselves);
83 }
84 }
85 match self.mutex.lock() {
86 Ok(guard) => {
87 *locked_by = Some(id);
89 Ok(CheckedMutexGuard {
90 checked_mutex: self,
91 guard,
92 })
93 }
94 Err(_e) => Err(CheckedMutexError::PoisonError),
95 }
96 }
97}