|
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