Coverage Report

Created: 2026-07-14 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/parking_lot-0.12.5/src/mutex.rs
Line
Count
Source
1
// Copyright 2016 Amanieu d'Antras
2
//
3
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5
// http://opensource.org/licenses/MIT>, at your option. This file may not be
6
// copied, modified, or distributed except according to those terms.
7
8
use crate::raw_mutex::RawMutex;
9
10
/// A mutual exclusion primitive useful for protecting shared data
11
///
12
/// This mutex will block threads waiting for the lock to become available. The
13
/// mutex can be statically initialized or created by the `new`
14
/// constructor. Each mutex has a type parameter which represents the data that
15
/// it is protecting. The data can only be accessed through the RAII guards
16
/// returned from `lock` and `try_lock`, which guarantees that the data is only
17
/// ever accessed when the mutex is locked.
18
///
19
/// # Fairness
20
///
21
/// A typical unfair lock can often end up in a situation where a single thread
22
/// quickly acquires and releases the same mutex in succession, which can starve
23
/// other threads waiting to acquire the mutex. While this improves throughput
24
/// because it doesn't force a context switch when a thread tries to re-acquire
25
/// a mutex it has just released, this can starve other threads.
26
///
27
/// This mutex uses [eventual fairness](https://trac.webkit.org/changeset/203350)
28
/// to ensure that the lock will be fair on average without sacrificing
29
/// throughput. This is done by forcing a fair unlock on average every 0.5ms,
30
/// which will force the lock to go to the next thread waiting for the mutex.
31
///
32
/// Additionally, any critical section longer than 1ms will always use a fair
33
/// unlock, which has a negligible impact on throughput considering the length
34
/// of the critical section.
35
///
36
/// You can also force a fair unlock by calling `MutexGuard::unlock_fair` when
37
/// unlocking a mutex instead of simply dropping the `MutexGuard`.
38
///
39
/// # Differences from the standard library `Mutex`
40
///
41
/// - No poisoning, the lock is released normally on panic.
42
/// - Only requires 1 byte of space, whereas the standard library boxes the
43
///   `Mutex` due to platform limitations.
44
/// - Can be statically constructed.
45
/// - Does not require any drop glue when dropped.
46
/// - Inline fast path for the uncontended case.
47
/// - Efficient handling of micro-contention using adaptive spinning.
48
/// - Allows raw locking & unlocking without a guard.
49
/// - Supports eventual fairness so that the mutex is fair on average.
50
/// - Optionally allows making the mutex fair by calling `MutexGuard::unlock_fair`.
51
///
52
/// # Examples
53
///
54
/// ```
55
/// use parking_lot::Mutex;
56
/// use std::sync::{Arc, mpsc::channel};
57
/// use std::thread;
58
///
59
/// const N: usize = 10;
60
///
61
/// // Spawn a few threads to increment a shared variable (non-atomically), and
62
/// // let the main thread know once all increments are done.
63
/// //
64
/// // Here we're using an Arc to share memory among threads, and the data inside
65
/// // the Arc is protected with a mutex.
66
/// let data = Arc::new(Mutex::new(0));
67
///
68
/// let (tx, rx) = channel();
69
/// for _ in 0..10 {
70
///     let (data, tx) = (Arc::clone(&data), tx.clone());
71
///     thread::spawn(move || {
72
///         // The shared state can only be accessed once the lock is held.
73
///         // Our non-atomic increment is safe because we're the only thread
74
///         // which can access the shared state when the lock is held.
75
///         let mut data = data.lock();
76
///         *data += 1;
77
///         if *data == N {
78
///             tx.send(()).unwrap();
79
///         }
80
///         // the lock is unlocked here when `data` goes out of scope.
81
///     });
82
/// }
83
///
84
/// rx.recv().unwrap();
85
/// ```
86
pub type Mutex<T> = lock_api::Mutex<RawMutex, T>;
87
88
/// Creates a new mutex in an unlocked state ready for use.
89
///
90
/// This allows creating a mutex in a constant context on stable Rust.
91
0
pub const fn const_mutex<T>(val: T) -> Mutex<T> {
92
0
    Mutex::const_new(<RawMutex as lock_api::RawMutex>::INIT, val)
93
0
}
Unexecuted instantiation: parking_lot::mutex::const_mutex::<_>
Unexecuted instantiation: parking_lot::mutex::const_mutex::<_>
94
95
/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
96
/// dropped (falls out of scope), the lock will be unlocked.
97
///
98
/// The data protected by the mutex can be accessed through this guard via its
99
/// `Deref` and `DerefMut` implementations.
100
pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>;
101
102
/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a
103
/// subfield of the protected data.
104
///
105
/// The main difference between `MappedMutexGuard` and `MutexGuard` is that the
106
/// former doesn't support temporarily unlocking and re-locking, since that
107
/// could introduce soundness issues if the locked object is modified by another
108
/// thread.
109
pub type MappedMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawMutex, T>;
110
111
#[cfg(test)]
112
mod tests {
113
    use crate::{Condvar, MappedMutexGuard, Mutex, MutexGuard};
114
    use std::collections::HashMap;
115
    use std::ops::Deref;
116
    use std::sync::atomic::{AtomicUsize, Ordering};
117
    use std::sync::mpsc::channel;
118
    use std::sync::Arc;
119
    use std::thread;
120
121
    #[cfg(feature = "serde")]
122
    use bincode::{deserialize, serialize};
123
124
    struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
125
126
    #[derive(Eq, PartialEq, Debug)]
127
    struct NonCopy(i32);
128
129
    unsafe impl<T: Send> Send for Packet<T> {}
130
    unsafe impl<T> Sync for Packet<T> {}
131
132
    #[test]
133
    fn smoke() {
134
        let m = Mutex::new(());
135
        drop(m.lock());
136
        drop(m.lock());
137
    }
138
139
    #[test]
140
    fn lots_and_lots() {
141
        const J: u32 = 1000;
142
        const K: u32 = 3;
143
144
        let m = Arc::new(Mutex::new(0));
145
146
        fn inc(m: &Mutex<u32>) {
147
            for _ in 0..J {
148
                *m.lock() += 1;
149
            }
150
        }
151
152
        let (tx, rx) = channel();
153
        for _ in 0..K {
154
            let tx2 = tx.clone();
155
            let m2 = m.clone();
156
            thread::spawn(move || {
157
                inc(&m2);
158
                tx2.send(()).unwrap();
159
            });
160
            let tx2 = tx.clone();
161
            let m2 = m.clone();
162
            thread::spawn(move || {
163
                inc(&m2);
164
                tx2.send(()).unwrap();
165
            });
166
        }
167
168
        drop(tx);
169
        for _ in 0..2 * K {
170
            rx.recv().unwrap();
171
        }
172
        assert_eq!(*m.lock(), J * K * 2);
173
    }
174
175
    #[test]
176
    fn try_lock() {
177
        let m = Mutex::new(());
178
        *m.try_lock().unwrap() = ();
179
    }
180
181
    #[test]
182
    fn test_into_inner() {
183
        let m = Mutex::new(NonCopy(10));
184
        assert_eq!(m.into_inner(), NonCopy(10));
185
    }
186
187
    #[test]
188
    fn test_into_inner_drop() {
189
        struct Foo(Arc<AtomicUsize>);
190
        impl Drop for Foo {
191
            fn drop(&mut self) {
192
                self.0.fetch_add(1, Ordering::SeqCst);
193
            }
194
        }
195
        let num_drops = Arc::new(AtomicUsize::new(0));
196
        let m = Mutex::new(Foo(num_drops.clone()));
197
        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
198
        {
199
            let _inner = m.into_inner();
200
            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
201
        }
202
        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
203
    }
204
205
    #[test]
206
    fn test_get_mut() {
207
        let mut m = Mutex::new(NonCopy(10));
208
        *m.get_mut() = NonCopy(20);
209
        assert_eq!(m.into_inner(), NonCopy(20));
210
    }
211
212
    #[test]
213
    fn test_mutex_arc_condvar() {
214
        let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
215
        let packet2 = Packet(packet.0.clone());
216
        let (tx, rx) = channel();
217
        let _t = thread::spawn(move || {
218
            // wait until parent gets in
219
            rx.recv().unwrap();
220
            let (lock, cvar) = &*packet2.0;
221
            let mut lock = lock.lock();
222
            *lock = true;
223
            cvar.notify_one();
224
        });
225
226
        let (lock, cvar) = &*packet.0;
227
        let mut lock = lock.lock();
228
        tx.send(()).unwrap();
229
        assert!(!*lock);
230
        while !*lock {
231
            cvar.wait(&mut lock);
232
        }
233
    }
234
235
    #[test]
236
    fn test_mutex_arc_nested() {
237
        // Tests nested mutexes and access
238
        // to underlying data.
239
        let arc = Arc::new(Mutex::new(1));
240
        let arc2 = Arc::new(Mutex::new(arc));
241
        let (tx, rx) = channel();
242
        let _t = thread::spawn(move || {
243
            let lock = arc2.lock();
244
            let lock2 = lock.lock();
245
            assert_eq!(*lock2, 1);
246
            tx.send(()).unwrap();
247
        });
248
        rx.recv().unwrap();
249
    }
250
251
    #[test]
252
    fn test_mutex_arc_access_in_unwind() {
253
        let arc = Arc::new(Mutex::new(1));
254
        let arc2 = arc.clone();
255
        let _ = thread::spawn(move || {
256
            struct Unwinder {
257
                i: Arc<Mutex<i32>>,
258
            }
259
            impl Drop for Unwinder {
260
                fn drop(&mut self) {
261
                    *self.i.lock() += 1;
262
                }
263
            }
264
            let _u = Unwinder { i: arc2 };
265
            panic!();
266
        })
267
        .join();
268
        let lock = arc.lock();
269
        assert_eq!(*lock, 2);
270
    }
271
272
    #[test]
273
    fn test_mutex_unsized() {
274
        let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
275
        {
276
            let b = &mut *mutex.lock();
277
            b[0] = 4;
278
            b[2] = 5;
279
        }
280
        let comp: &[i32] = &[4, 2, 5];
281
        assert_eq!(&*mutex.lock(), comp);
282
    }
283
284
    #[test]
285
    fn test_mutexguard_sync() {
286
        fn sync<T: Sync>(_: T) {}
287
288
        let mutex = Mutex::new(());
289
        sync(mutex.lock());
290
    }
291
292
    #[test]
293
    fn test_mutex_debug() {
294
        let mutex = Mutex::new(vec![0u8, 10]);
295
296
        assert_eq!(format!("{:?}", mutex), "Mutex { data: [0, 10] }");
297
        let _lock = mutex.lock();
298
        assert_eq!(format!("{:?}", mutex), "Mutex { data: <locked> }");
299
    }
300
301
    #[cfg(feature = "serde")]
302
    #[test]
303
    fn test_serde() {
304
        let contents: Vec<u8> = vec![0, 1, 2];
305
        let mutex = Mutex::new(contents.clone());
306
307
        let serialized = serialize(&mutex).unwrap();
308
        let deserialized: Mutex<Vec<u8>> = deserialize(&serialized).unwrap();
309
310
        assert_eq!(*(mutex.lock()), *(deserialized.lock()));
311
        assert_eq!(contents, *(deserialized.lock()));
312
    }
313
314
    #[test]
315
    fn test_map_or_err_not_mapped() {
316
        let mut map = HashMap::new();
317
        map.insert("hello".to_string(), "world".to_string());
318
319
        let mutex = Mutex::new(map);
320
        let guard = mutex.lock();
321
        let guard = match MutexGuard::try_map_or_err(guard, |the_map| {
322
            the_map.get_mut("hello2").ok_or(12345i32)
323
        }) {
324
            Ok(_) => unreachable!(),
325
            Err((guard, data)) => {
326
                assert_eq!(data, 12345i32);
327
                assert_eq!(guard.get("hello"), Some(&"world".to_string()));
328
                guard
329
            }
330
        };
331
332
        // Lets try again
333
        let mapped_guard = match MutexGuard::try_map_or_err(guard, |the_map| {
334
            the_map.get_mut("hello").ok_or("unreachable")
335
        }) {
336
            Ok(mapped_guard) => mapped_guard,
337
            Err((_, _)) => unreachable!(),
338
        };
339
340
        assert_eq!(mapped_guard.as_str(), "world");
341
342
        match MappedMutexGuard::try_map_or_err(mapped_guard, |the_string| {
343
            if the_string != "world" {
344
                //unreachable
345
                Ok(the_string.as_mut_str())
346
            } else {
347
                Err(45678i32)
348
            }
349
        }) {
350
            Ok(_) => unreachable!(),
351
            Err((guard, err)) => {
352
                assert_eq!(guard.as_str(), "world");
353
                assert_eq!(err, 45678i32);
354
            }
355
        };
356
    }
357
358
    #[test]
359
    fn test_map_or_err_mapped() {
360
        let mut map = HashMap::new();
361
        map.insert("hello".to_string(), "world".to_string());
362
363
        let mutex = Mutex::new(map);
364
        let guard = mutex.lock();
365
        let mapped_guard = match MutexGuard::try_map_or_err(guard, |the_map| {
366
            the_map.get_mut("hello").ok_or("unreachable")
367
        }) {
368
            Ok(mapped_guard) => mapped_guard,
369
            Err((_, _)) => unreachable!(),
370
        };
371
372
        assert_eq!(mapped_guard.as_str(), "world");
373
374
        match MappedMutexGuard::try_map_or_err(mapped_guard, |the_string| {
375
            if the_string == "world" {
376
                Ok(the_string.as_mut_str())
377
            } else {
378
                Err("unreachable")
379
            }
380
        }) {
381
            Ok(mapped_guard) => assert_eq!(mapped_guard.deref(), "world"),
382
            Err((_, _)) => unreachable!(),
383
        };
384
    }
385
}