happylock/
mutex.rs

1use std::cell::UnsafeCell;
2use std::marker::PhantomData;
3
4use lock_api::RawMutex;
5
6use crate::poisonable::PoisonFlag;
7use crate::ThreadKey;
8
9mod guard;
10mod mutex;
11
12/// A spinning mutex
13#[cfg(feature = "spin")]
14pub type SpinLock<T> = Mutex<T, spin::Mutex<()>>;
15
16/// A parking lot mutex
17#[cfg(feature = "parking_lot")]
18pub type ParkingMutex<T> = Mutex<T, parking_lot::RawMutex>;
19
20/// A mutual exclusion primitive useful for protecting shared data, which
21/// cannot deadlock.
22///
23/// This mutex will block threads waiting for the lock to become available.
24/// Each mutex has a type parameter which represents the data that it is
25/// protecting. The data can only be accessed through the [`MutexGuard`]s
26/// returned from [`lock`] and [`try_lock`], which guarantees that the data is
27/// only ever accessed when the mutex is locked.
28///
29/// Locking the mutex on a thread that already locked it is impossible, due to
30/// the requirement of the [`ThreadKey`]. Therefore, this will never deadlock.
31///
32/// # Examples
33///
34/// ```
35/// use std::sync::Arc;
36/// use std::thread;
37/// use std::sync::mpsc;
38///
39/// use happylock::{Mutex, ThreadKey};
40///
41/// // Spawn a few threads to increment a shared variable (non-atomically),
42/// // and let the main thread know once all increments are done.
43/// //
44/// // Here we're using an Arc to share memory among threads, and the data
45/// // inside the Arc is protected with a mutex.
46/// const N: usize = 10;
47///
48/// let data = Arc::new(Mutex::new(0));
49///
50/// let (tx, rx) = mpsc::channel();
51/// for _ in 0..N {
52///     let (data, tx) = (Arc::clone(&data), tx.clone());
53///     thread::spawn(move || {
54///         let key = ThreadKey::get().unwrap();
55///         let mut data = data.lock(key);
56///         *data += 1;
57///         if *data == N {
58///             tx.send(()).unwrap();
59///         }
60///         // the lock is unlocked
61///     });
62/// }
63///
64/// rx.recv().unwrap();
65/// ```
66///
67/// To unlock a mutex guard sooner than the end of the enclosing scope, either
68/// create an inner scope, drop the guard manually, or call [`Mutex::unlock`].
69///
70/// ```
71/// use std::sync::Arc;
72/// use std::thread;
73///
74/// use happylock::{Mutex, ThreadKey};
75///
76/// const N: usize = 3;
77///
78/// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
79/// let res_mutex = Arc::new(Mutex::new(0));
80///
81/// let mut threads = Vec::with_capacity(N);
82/// (0..N).for_each(|_| {
83///     let data_mutex_clone = Arc::clone(&data_mutex);
84///     let res_mutex_clone = Arc::clone(&res_mutex);
85///
86///     threads.push(thread::spawn(move || {
87///         let mut key = ThreadKey::get().unwrap();
88///
89///         // Here we use a block to limit the lifetime of the lock guard.
90///         let result = data_mutex_clone.scoped_lock(&mut key, |data| {
91///             let result = data.iter().fold(0, |acc, x| acc + x * 2);
92///             data.push(result);
93///             result
94///             // The mutex guard gets dropped here, so the lock is released
95///         });
96///         // The thread key is available again
97///         *res_mutex_clone.lock(key) += result;
98///     }));
99/// });
100///
101/// let key = ThreadKey::get().unwrap();
102/// let mut data = data_mutex.lock(key);
103/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
104/// data.push(result);
105///
106/// // We drop the `data` explicitly because it's not necessary anymore. This
107/// // allows other threads to start working on the data immediately. Dropping
108/// // the data also gives us access to the thread key, so we can lock
109/// // another mutex.
110/// let key = Mutex::unlock(data);
111///
112/// // Here the mutex guard is not assigned to a variable and so, even if the
113/// // scope does not end after this line, the mutex is still released: there is
114/// // no deadlock.
115/// *res_mutex.lock(key) += result;
116///
117/// threads.into_iter().for_each(|thread| {
118///     thread
119///         .join()
120///         .expect("The thread creating or execution failed !")
121/// });
122///
123/// let key = ThreadKey::get().unwrap();
124/// assert_eq!(*res_mutex.lock(key), 800);
125/// ```
126///
127/// [`lock`]: `Mutex::lock`
128/// [`try_lock`]: `Mutex::try_lock`
129/// [`ThreadKey`]: `crate::ThreadKey`
130pub struct Mutex<T: ?Sized, R> {
131	raw: R,
132	poison: PoisonFlag,
133	data: UnsafeCell<T>,
134}
135
136/// A reference to a mutex that unlocks it when dropped.
137///
138/// This is similar to [`MutexGuard`], except it does not hold a [`Keyable`].
139pub struct MutexRef<'a, T: ?Sized + 'a, R: RawMutex>(&'a Mutex<T, R>, PhantomData<R::GuardMarker>);
140
141/// An RAII implementation of a “scoped lock” of a mutex.
142///
143/// When this structure is dropped (falls out of scope), the lock will be
144/// unlocked.
145///
146/// This is created by calling the [`lock`] and [`try_lock`] methods on [`Mutex`]
147///
148/// [`lock`]: `Mutex::lock`
149/// [`try_lock`]: `Mutex::try_lock`
150//
151// This is the most lifetime-intensive thing I've ever written. Can I graduate
152// from borrow checker university now?
153pub struct MutexGuard<'a, T: ?Sized + 'a, R: RawMutex> {
154	mutex: MutexRef<'a, T, R>, // this way we don't need to re-implement Drop
155	thread_key: ThreadKey,
156}
157
158#[cfg(test)]
159mod tests {
160	use crate::{LockCollection, ThreadKey};
161
162	use super::*;
163
164	#[test]
165	fn unlocked_when_initialized() {
166		let lock: crate::Mutex<_> = Mutex::new("Hello, world!");
167
168		assert!(!lock.is_locked());
169	}
170
171	#[test]
172	fn locked_after_read() {
173		let key = ThreadKey::get().unwrap();
174		let lock: crate::Mutex<_> = Mutex::new("Hello, world!");
175
176		let guard = lock.lock(key);
177
178		assert!(lock.is_locked());
179		drop(guard)
180	}
181
182	#[test]
183	fn from_works() {
184		let key = ThreadKey::get().unwrap();
185		let mutex: crate::Mutex<_> = Mutex::from("Hello, world!");
186
187		let guard = mutex.lock(key);
188		assert_eq!(*guard, "Hello, world!");
189	}
190
191	#[test]
192	fn as_mut_works() {
193		let key = ThreadKey::get().unwrap();
194		let mut mutex = crate::Mutex::from(42);
195
196		let mut_ref = mutex.as_mut();
197		*mut_ref = 24;
198
199		mutex.scoped_lock(key, |guard| assert_eq!(*guard, 24))
200	}
201
202	#[test]
203	fn display_works_for_guard() {
204		let key = ThreadKey::get().unwrap();
205		let mutex: crate::Mutex<_> = Mutex::new("Hello, world!");
206		let guard = mutex.lock(key);
207		assert_eq!(guard.to_string(), "Hello, world!".to_string());
208	}
209
210	#[test]
211	fn display_works_for_ref() {
212		let mutex: crate::Mutex<_> = Mutex::new("Hello, world!");
213		let guard = unsafe { mutex.try_lock_no_key().unwrap() };
214		assert_eq!(guard.to_string(), "Hello, world!".to_string());
215	}
216
217	#[test]
218	fn ref_as_mut() {
219		let key = ThreadKey::get().unwrap();
220		let collection = LockCollection::new(crate::Mutex::new(0));
221		let mut guard = collection.lock(key);
222		let guard_mut = guard.as_mut().as_mut();
223
224		*guard_mut = 3;
225		let key = LockCollection::<crate::Mutex<_>>::unlock(guard);
226
227		let guard = collection.lock(key);
228
229		assert_eq!(guard.as_ref().as_ref(), &3);
230	}
231
232	#[test]
233	fn guard_as_mut() {
234		let key = ThreadKey::get().unwrap();
235		let mutex = crate::Mutex::new(0);
236		let mut guard = mutex.lock(key);
237		let guard_mut = guard.as_mut();
238
239		*guard_mut = 3;
240		let key = Mutex::unlock(guard);
241
242		let guard = mutex.lock(key);
243
244		assert_eq!(guard.as_ref(), &3);
245	}
246
247	#[test]
248	fn dropping_guard_releases_mutex() {
249		let key = ThreadKey::get().unwrap();
250		let mutex: crate::Mutex<_> = Mutex::new("Hello, world!");
251
252		let guard = mutex.lock(key);
253		drop(guard);
254
255		assert!(!mutex.is_locked());
256	}
257
258	#[test]
259	fn dropping_ref_releases_mutex() {
260		let mutex: crate::Mutex<_> = Mutex::new("Hello, world!");
261
262		let guard = unsafe { mutex.try_lock_no_key().unwrap() };
263		drop(guard);
264
265		assert!(!mutex.is_locked());
266	}
267}