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