simple_mutex/
lib.rs

1//! A simple mutex.
2//!
3//! More efficient than [`std::sync::Mutex`] and simpler than
4//! [`parking_lot::Mutex`](https://docs.rs/parking_lot).
5//!
6//! The locking mechanism uses eventual fairness to ensure locking will be fair on average without
7//! sacrificing performance. This is done by forcing a fair lock whenever a lock operation is
8//! starved for longer than 0.5 milliseconds.
9//!
10//! # Examples
11//!
12//! ```
13//! use simple_mutex::Mutex;
14//! use std::sync::Arc;
15//! use std::thread;
16//!
17//! let m = Arc::new(Mutex::new(0));
18//! let mut threads = vec![];
19//!
20//! for _ in 0..10 {
21//!     let m = m.clone();
22//!     threads.push(thread::spawn(move || {
23//!         *m.lock() += 1;
24//!     }));
25//! }
26//!
27//! for t in threads {
28//!     t.join().unwrap();
29//! }
30//! assert_eq!(*m.lock(), 10);
31//! ```
32
33#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
34
35use std::cell::UnsafeCell;
36use std::fmt;
37use std::ops::{Deref, DerefMut};
38use std::sync::atomic::{self, AtomicUsize, Ordering};
39use std::thread;
40use std::time::{Duration, Instant};
41
42use event_listener::Event;
43
44/// A simple mutex.
45pub struct Mutex<T> {
46    /// Current state of the mutex.
47    ///
48    /// The least significant bit is set to 1 if the mutex is locked.
49    /// The other bits hold the number of starved lock operations.
50    state: AtomicUsize,
51
52    /// Lock operations waiting for the mutex to be released.
53    lock_ops: Event,
54
55    /// The value inside the mutex.
56    data: UnsafeCell<T>,
57}
58
59unsafe impl<T: Send> Send for Mutex<T> {}
60unsafe impl<T: Send> Sync for Mutex<T> {}
61
62impl<T> Mutex<T> {
63    /// Creates a new mutex.
64    ///
65    /// # Examples
66    ///
67    /// ```
68    /// use simple_mutex::Mutex;
69    ///
70    /// let mutex = Mutex::new(0);
71    /// ```
72    pub fn new(data: T) -> Mutex<T> {
73        Mutex {
74            state: AtomicUsize::new(0),
75            lock_ops: Event::new(),
76            data: UnsafeCell::new(data),
77        }
78    }
79
80    /// Acquires the mutex.
81    ///
82    /// Returns a guard that releases the mutex when dropped.
83    ///
84    /// # Examples
85    ///
86    /// ```
87    /// use simple_mutex::Mutex;
88    ///
89    /// let mutex = Mutex::new(10);
90    /// let guard = mutex.lock();
91    /// assert_eq!(*guard, 10);
92    /// ```
93    #[inline]
94    pub fn lock(&self) -> MutexGuard<'_, T> {
95        if let Some(guard) = self.try_lock() {
96            return guard;
97        }
98        self.lock_slow()
99    }
100
101    /// Slow path for acquiring the mutex.
102    #[cold]
103    fn lock_slow(&self) -> MutexGuard<'_, T> {
104        for step in 0..10 {
105            // Try locking if nobody is being starved.
106            match self.state.compare_and_swap(0, 1, Ordering::Acquire) {
107                // Lock acquired!
108                0 => return MutexGuard(self),
109
110                // Lock is held and nobody is starved.
111                1 => {}
112
113                // Somebody is starved.
114                _ => break,
115            }
116
117            // Back off before trying again.
118            if step <= 3 {
119                for _ in 0..1 << step {
120                    atomic::spin_loop_hint();
121                }
122            } else {
123                thread::yield_now();
124            }
125        }
126
127        // Get the current time.
128        let start = Instant::now();
129
130        loop {
131            // Start listening for events.
132            let listener = self.lock_ops.listen();
133
134            // Try locking if nobody is being starved.
135            match self.state.compare_and_swap(0, 1, Ordering::Acquire) {
136                // Lock acquired!
137                0 => return MutexGuard(self),
138
139                // Lock is held and nobody is starved.
140                1 => {}
141
142                // Somebody is starved.
143                _ => break,
144            }
145
146            // Wait for a notification.
147            listener.wait();
148
149            // Try locking if nobody is being starved.
150            match self.state.compare_and_swap(0, 1, Ordering::Acquire) {
151                // Lock acquired!
152                0 => return MutexGuard(self),
153
154                // Lock is held and nobody is starved.
155                1 => {}
156
157                // Somebody is starved.
158                _ => {
159                    // Notify the first listener in line because we probably received a
160                    // notification that was meant for a starved thread.
161                    self.lock_ops.notify(1);
162                    break;
163                }
164            }
165
166            // If waiting for too long, fall back to a fairer locking strategy that will prevent
167            // newer lock operations from starving us forever.
168            if start.elapsed() > Duration::from_micros(500) {
169                break;
170            }
171        }
172
173        // Increment the number of starved lock operations.
174        self.state.fetch_add(2, Ordering::Release);
175
176        // Decrement the counter when exiting this function.
177        let _call = CallOnDrop(|| {
178            self.state.fetch_sub(2, Ordering::Release);
179        });
180
181        loop {
182            // Start listening for events.
183            let listener = self.lock_ops.listen();
184
185            // Try locking if nobody else is being starved.
186            match self.state.compare_and_swap(2, 2 | 1, Ordering::Acquire) {
187                // Lock acquired!
188                2 => return MutexGuard(self),
189
190                // Lock is held by someone.
191                s if s % 2 == 1 => {}
192
193                // Lock is available.
194                _ => {
195                    // Be fair: notify the first listener and then go wait in line.
196                    self.lock_ops.notify(1);
197                }
198            }
199
200            // Wait for a notification.
201            listener.wait();
202
203            // Try acquiring the lock without waiting for others.
204            if self.state.fetch_or(1, Ordering::Acquire) % 2 == 0 {
205                return MutexGuard(self);
206            }
207        }
208    }
209
210    /// Attempts to acquire the mutex.
211    ///
212    /// If the mutex could not be acquired at this time, then [`None`] is returned. Otherwise, a
213    /// guard is returned that releases the mutex when dropped.
214    ///
215    /// # Examples
216    ///
217    /// ```
218    /// use simple_mutex::Mutex;
219    ///
220    /// let mutex = Mutex::new(10);
221    /// if let Some(guard) = mutex.try_lock() {
222    ///     assert_eq!(*guard, 10);
223    /// }
224    /// # ;
225    /// ```
226    #[inline]
227    pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
228        if self.state.compare_and_swap(0, 1, Ordering::Acquire) == 0 {
229            Some(MutexGuard(self))
230        } else {
231            None
232        }
233    }
234
235    /// Consumes the mutex, returning the underlying data.
236    ///
237    /// # Examples
238    ///
239    /// ```
240    /// use simple_mutex::Mutex;
241    ///
242    /// let mutex = Mutex::new(10);
243    /// assert_eq!(mutex.into_inner(), 10);
244    /// ```
245    pub fn into_inner(self) -> T {
246        self.data.into_inner()
247    }
248
249    /// Returns a mutable reference to the underlying data.
250    ///
251    /// Since this call borrows the mutex mutably, no actual locking takes place -- the mutable
252    /// borrow statically guarantees the mutex is not already acquired.
253    ///
254    /// # Examples
255    ///
256    /// ```
257    /// use simple_mutex::Mutex;
258    ///
259    /// let mut mutex = Mutex::new(0);
260    /// *mutex.get_mut() = 10;
261    /// assert_eq!(*mutex.lock(), 10);
262    /// ```
263    pub fn get_mut(&mut self) -> &mut T {
264        unsafe { &mut *self.data.get() }
265    }
266}
267
268impl<T: fmt::Debug> fmt::Debug for Mutex<T> {
269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270        struct Locked;
271        impl fmt::Debug for Locked {
272            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273                f.write_str("<locked>")
274            }
275        }
276
277        match self.try_lock() {
278            None => f.debug_struct("Mutex").field("data", &Locked).finish(),
279            Some(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
280        }
281    }
282}
283
284impl<T> From<T> for Mutex<T> {
285    fn from(val: T) -> Mutex<T> {
286        Mutex::new(val)
287    }
288}
289
290impl<T: Default> Default for Mutex<T> {
291    fn default() -> Mutex<T> {
292        Mutex::new(Default::default())
293    }
294}
295
296/// A guard that releases the mutex when dropped.
297pub struct MutexGuard<'a, T>(&'a Mutex<T>);
298
299unsafe impl<T: Send> Send for MutexGuard<'_, T> {}
300unsafe impl<T: Sync> Sync for MutexGuard<'_, T> {}
301
302impl<'a, T> MutexGuard<'a, T> {
303    /// Returns a reference to the mutex a guard came from.
304    ///
305    /// # Examples
306    ///
307    /// ```
308    /// use simple_mutex::{Mutex, MutexGuard};
309    ///
310    /// let mutex = Mutex::new(10i32);
311    /// let guard = mutex.lock();
312    /// dbg!(MutexGuard::source(&guard));
313    /// ```
314    pub fn source(guard: &MutexGuard<'a, T>) -> &'a Mutex<T> {
315        guard.0
316    }
317}
318
319impl<T> Drop for MutexGuard<'_, T> {
320    fn drop(&mut self) {
321        // Remove the last bit and notify a waiting lock operation.
322        self.0.state.fetch_sub(1, Ordering::Release);
323
324        if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
325            // On x86 architectures, `fetch_sub()` has the effect of a `SeqCst` fence so we don't need
326            // to emit another one here.
327            self.0.lock_ops.notify_relaxed(1);
328        } else {
329            self.0.lock_ops.notify(1);
330        }
331    }
332}
333
334impl<T: fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
335    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336        fmt::Debug::fmt(&**self, f)
337    }
338}
339
340impl<T: fmt::Display> fmt::Display for MutexGuard<'_, T> {
341    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342        (**self).fmt(f)
343    }
344}
345
346impl<T> Deref for MutexGuard<'_, T> {
347    type Target = T;
348
349    fn deref(&self) -> &T {
350        unsafe { &*self.0.data.get() }
351    }
352}
353
354impl<T> DerefMut for MutexGuard<'_, T> {
355    fn deref_mut(&mut self) -> &mut T {
356        unsafe { &mut *self.0.data.get() }
357    }
358}
359
360/// Calls a function when dropped.
361struct CallOnDrop<F: Fn()>(F);
362
363impl<F: Fn()> Drop for CallOnDrop<F> {
364    fn drop(&mut self) {
365        (self.0)();
366    }
367}