|
1 | 1 | use crate::sys::mutex as imp;
|
2 | 2 |
|
3 |
| -/// An OS-based mutual exclusion lock. |
| 3 | +/// An OS-based mutual exclusion lock, meant for use in static variables. |
| 4 | +/// |
| 5 | +/// This mutex has a const constructor ([`StaticMutex::new`]), does not |
| 6 | +/// implement `Drop` to cleanup resources, and causes UB when moved or used |
| 7 | +/// reentrantly. |
| 8 | +/// |
| 9 | +/// This mutex does not implement poisoning. |
4 | 10 | ///
|
5 |
| -/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of |
6 |
| -/// this mutex is unsafe and it is recommended to instead use the safe wrapper |
7 |
| -/// at the top level of the crate instead of this type. |
8 |
| -pub struct Mutex(imp::Mutex); |
| 11 | +/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and |
| 12 | +/// `destroy()`. |
| 13 | +pub struct StaticMutex(imp::Mutex); |
9 | 14 |
|
10 |
| -unsafe impl Sync for Mutex {} |
| 15 | +unsafe impl Sync for StaticMutex {} |
11 | 16 |
|
12 |
| -impl Mutex { |
| 17 | +impl StaticMutex { |
13 | 18 | /// Creates a new mutex for use.
|
14 | 19 | ///
|
15 | 20 | /// Behavior is undefined if the mutex is moved after it is
|
16 | 21 | /// first used with any of the functions below.
|
17 |
| - /// Also, until `init` is called, behavior is undefined if this |
18 |
| - /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock` |
19 |
| - /// are called by the thread currently holding the lock. |
| 22 | + /// Also, the behavior is undefined if this mutex is ever used reentrantly, |
| 23 | + /// i.e., `lock` is called by the thread currently holding the lock. |
20 | 24 | #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
|
21 |
| - pub const fn new() -> Mutex { |
22 |
| - Mutex(imp::Mutex::new()) |
| 25 | + pub const fn new() -> Self { |
| 26 | + Self(imp::Mutex::new()) |
23 | 27 | }
|
24 | 28 |
|
25 |
| - /// Prepare the mutex for use. |
| 29 | + /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex |
| 30 | + /// will be unlocked. |
26 | 31 | ///
|
27 |
| - /// This should be called once the mutex is at a stable memory address. |
28 |
| - /// If called, this must be the very first thing that happens to the mutex. |
29 |
| - /// Calling it in parallel with or after any operation (including another |
30 |
| - /// `init()`) is undefined behavior. |
| 32 | + /// It is undefined behaviour to call this function while locked, or if the |
| 33 | + /// mutex has been moved since the last time this was called. |
31 | 34 | #[inline]
|
32 |
| - pub unsafe fn init(&mut self) { |
33 |
| - self.0.init() |
| 35 | + pub unsafe fn lock(&self) -> StaticMutexGuard<'_> { |
| 36 | + self.0.lock(); |
| 37 | + StaticMutexGuard(&self.0) |
34 | 38 | }
|
| 39 | +} |
35 | 40 |
|
36 |
| - /// Locks the mutex blocking the current thread until it is available. |
37 |
| - /// |
38 |
| - /// Behavior is undefined if the mutex has been moved between this and any |
39 |
| - /// previous function call. |
| 41 | +#[must_use] |
| 42 | +pub struct StaticMutexGuard<'a>(&'a imp::Mutex); |
| 43 | + |
| 44 | +impl Drop for StaticMutexGuard<'_> { |
40 | 45 | #[inline]
|
41 |
| - pub unsafe fn raw_lock(&self) { |
42 |
| - self.0.lock() |
| 46 | + fn drop(&mut self) { |
| 47 | + unsafe { |
| 48 | + self.0.unlock(); |
| 49 | + } |
43 | 50 | }
|
| 51 | +} |
44 | 52 |
|
45 |
| - /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex |
46 |
| - /// will be unlocked. |
| 53 | +/// An OS-based mutual exclusion lock. |
| 54 | +/// |
| 55 | +/// This mutex does *not* have a const constructor, cleans up its resources in |
| 56 | +/// its `Drop` implementation, may safely be moved (when not borrowed), and |
| 57 | +/// does not cause UB when used reentrantly. |
| 58 | +/// |
| 59 | +/// This mutex does not implement poisoning. |
| 60 | +/// |
| 61 | +/// This is a wrapper around `Box<imp::Mutex>`, to allow the object to be moved |
| 62 | +/// without moving the raw mutex. |
| 63 | +pub struct MovableMutex(Box<imp::Mutex>); |
| 64 | + |
| 65 | +unsafe impl Sync for MovableMutex {} |
| 66 | + |
| 67 | +impl MovableMutex { |
| 68 | + /// Creates a new mutex. |
| 69 | + pub fn new() -> Self { |
| 70 | + let mut mutex = box imp::Mutex::new(); |
| 71 | + unsafe { mutex.init() }; |
| 72 | + Self(mutex) |
| 73 | + } |
| 74 | + |
| 75 | + pub(crate) fn raw(&self) -> &imp::Mutex { |
| 76 | + &self.0 |
| 77 | + } |
| 78 | + |
| 79 | + /// Locks the mutex blocking the current thread until it is available. |
47 | 80 | #[inline]
|
48 |
| - pub unsafe fn lock(&self) -> MutexGuard<'_> { |
49 |
| - self.raw_lock(); |
50 |
| - MutexGuard(&self.0) |
| 81 | + pub fn raw_lock(&self) { |
| 82 | + unsafe { self.0.lock() } |
51 | 83 | }
|
52 | 84 |
|
53 | 85 | /// Attempts to lock the mutex without blocking, returning whether it was
|
54 | 86 | /// successfully acquired or not.
|
55 |
| - /// |
56 |
| - /// Behavior is undefined if the mutex has been moved between this and any |
57 |
| - /// previous function call. |
58 | 87 | #[inline]
|
59 |
| - pub unsafe fn try_lock(&self) -> bool { |
60 |
| - self.0.try_lock() |
| 88 | + pub fn try_lock(&self) -> bool { |
| 89 | + unsafe { self.0.try_lock() } |
61 | 90 | }
|
62 | 91 |
|
63 | 92 | /// Unlocks the mutex.
|
64 | 93 | ///
|
65 | 94 | /// Behavior is undefined if the current thread does not actually hold the
|
66 | 95 | /// mutex.
|
67 |
| - /// |
68 |
| - /// Consider switching from the pair of raw_lock() and raw_unlock() to |
69 |
| - /// lock() whenever possible. |
70 | 96 | #[inline]
|
71 | 97 | pub unsafe fn raw_unlock(&self) {
|
72 | 98 | self.0.unlock()
|
73 | 99 | }
|
74 |
| - |
75 |
| - /// Deallocates all resources associated with this mutex. |
76 |
| - /// |
77 |
| - /// Behavior is undefined if there are current or will be future users of |
78 |
| - /// this mutex. |
79 |
| - #[inline] |
80 |
| - pub unsafe fn destroy(&self) { |
81 |
| - self.0.destroy() |
82 |
| - } |
83 | 100 | }
|
84 | 101 |
|
85 |
| -// not meant to be exported to the outside world, just the containing module |
86 |
| -pub fn raw(mutex: &Mutex) -> &imp::Mutex { |
87 |
| - &mutex.0 |
88 |
| -} |
89 |
| - |
90 |
| -#[must_use] |
91 |
| -/// A simple RAII utility for the above Mutex without the poisoning semantics. |
92 |
| -pub struct MutexGuard<'a>(&'a imp::Mutex); |
93 |
| - |
94 |
| -impl Drop for MutexGuard<'_> { |
95 |
| - #[inline] |
| 102 | +impl Drop for MovableMutex { |
96 | 103 | fn drop(&mut self) {
|
97 |
| - unsafe { |
98 |
| - self.0.unlock(); |
99 |
| - } |
| 104 | + unsafe { self.0.destroy() }; |
100 | 105 | }
|
101 | 106 | }
|
0 commit comments