sync_no_std/
mutex.rs

1use alloc::alloc::Global;
2use core::alloc::Allocator;
3use core::cell::UnsafeCell;
4use core::fmt;
5use core::ops::{Deref, DerefMut};
6use crate::poison::{self, LockResult, TryLockError, TryLockResult};
7
8#[cfg(all(not(target_os="dos"), not(windows)))]
9mod posix;
10
11#[cfg(all(not(target_os="dos"), windows))]
12mod winapi;
13
14#[cfg(target_os="dos")]
15mod dos;
16
17#[cfg(all(not(target_os="dos"), not(windows)))]
18use posix::SysMutex;
19
20#[cfg(all(not(target_os="dos"), windows))]
21use winapi::SysMutex;
22
23#[cfg(target_os="dos")]
24use dos::SysMutex;
25
26pub struct Mutex<T: ?Sized, A: Allocator + Clone = Global> {
27    inner: SysMutex<A>,
28    poison: poison::Flag,
29    data: UnsafeCell<T>,
30}
31
32unsafe impl<T: ?Sized + Send, A: Allocator + Clone> Send for Mutex<T, A> { }
33
34unsafe impl<T: ?Sized + Send, A: Allocator + Clone> Sync for Mutex<T, A> { }
35
36#[must_use="if unused the Mutex will immediately unlock"]
37pub struct MutexGuard<'a, T: ?Sized + 'a, A: Allocator + Clone = Global> {
38    lock: &'a Mutex<T, A>,
39    poison: poison::Guard,
40}
41
42impl<T: ?Sized, A: Allocator + Clone> !Send for MutexGuard<'_, T, A> { }
43
44unsafe impl<T: ?Sized + Sync, A: Allocator + Clone> Sync for MutexGuard<'_, T, A> { }
45
46impl<T, A: Allocator + Clone> Mutex<T, A> {
47    pub const fn new_in(t: T, allocator: A) -> Mutex<T, A> {
48        Mutex { inner: SysMutex::new_in(allocator), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
49    }
50
51    pub const fn allocator(&self) -> &A { self.inner.allocator() }
52}
53
54impl<T> Mutex<T> {
55    pub const fn new(t: T) -> Mutex<T> {
56        Mutex::new_in(t, Global)
57    }
58}
59
60impl<T: ?Sized, A: Allocator + Clone> Mutex<T, A> {
61    pub fn lock(&self) -> LockResult<MutexGuard<'_, T, A>> {
62        unsafe {
63            self.inner.lock();
64            MutexGuard::new(self)
65        }
66    }
67
68    pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T, A>> {
69        unsafe {
70            if self.inner.try_lock() {
71                Ok(MutexGuard::new(self)?)
72            } else {
73                Err(TryLockError::WouldBlock)
74            }
75        }
76    }
77
78    pub fn is_poisoned(&self) -> bool {
79        self.poison.get()
80    }
81
82    pub fn clear_poison(&self) {
83        self.poison.clear();
84    }
85
86    pub fn into_inner(self) -> LockResult<T>
87    where
88        T: Sized,
89    {
90        let data = self.data.into_inner();
91        poison::map_result(self.poison.borrow(), |()| data)
92    }
93
94    pub fn get_mut(&mut self) -> LockResult<&mut T> {
95        let data = self.data.get_mut();
96        poison::map_result(self.poison.borrow(), |()| data)
97    }
98}
99
100impl<T> From<T> for Mutex<T> {
101    fn from(t: T) -> Self {
102        Mutex::new(t)
103    }
104}
105
106impl<T: Default> Default for Mutex<T> {
107    fn default() -> Mutex<T> {
108        Mutex::new(Default::default())
109    }
110}
111
112impl<T: ?Sized + fmt::Debug, A: Allocator + Clone> fmt::Debug for Mutex<T, A> {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        let mut d = f.debug_struct("Mutex");
115        match self.try_lock() {
116            Ok(guard) => {
117                d.field("data", &&*guard);
118            }
119            Err(TryLockError::Poisoned(err)) => {
120                d.field("data", &&**err.get_ref());
121            }
122            Err(TryLockError::WouldBlock) => {
123                d.field("data", &format_args!("<locked>"));
124            }
125        }
126        d.field("poisoned", &self.poison.get());
127        d.finish_non_exhaustive()
128    }
129}
130
131impl<'mutex, T: ?Sized, A: Allocator + Clone> MutexGuard<'mutex, T, A> {
132    unsafe fn new(lock: &'mutex Mutex<T, A>) -> LockResult<MutexGuard<'mutex, T, A>> {
133        poison::map_result(lock.poison.guard(), |guard| MutexGuard { lock, poison: guard })
134    }
135}
136
137impl<T: ?Sized, A: Allocator + Clone> Deref for MutexGuard<'_, T, A> {
138    type Target = T;
139
140    fn deref(&self) -> &T {
141        unsafe { &*self.lock.data.get() }
142    }
143}
144
145impl<T: ?Sized, A: Allocator + Clone> DerefMut for MutexGuard<'_, T, A> {
146    fn deref_mut(&mut self) -> &mut T {
147        unsafe { &mut *self.lock.data.get() }
148    }
149}
150
151impl<T: ?Sized, A: Allocator + Clone> Drop for MutexGuard<'_, T, A> {
152    fn drop(&mut self) {
153        unsafe {
154            self.lock.poison.done(&self.poison);
155            self.lock.inner.unlock();
156        }
157    }
158}
159
160impl<T: ?Sized + fmt::Debug, A: Allocator + Clone> fmt::Debug for MutexGuard<'_, T, A> {
161    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162        fmt::Debug::fmt(&**self, f)
163    }
164}
165
166impl<T: ?Sized + fmt::Display, A: Allocator + Clone> fmt::Display for MutexGuard<'_, T, A> {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        (**self).fmt(f)
169    }
170}