1use crate::raw_mutex::RawMutex;
2use core::num::NonZeroUsize;
3use lock_api::{self, GetThreadId};
45/// Implementation of the `GetThreadId` trait for `lock_api::ReentrantMutex`.
6pub struct RawThreadId;
78unsafe impl GetThreadIdfor RawThreadId {
9const INIT: RawThreadId = RawThreadId;
1011fn nonzero_thread_id(&self) -> NonZeroUsize {
12// The address of a thread-local variable is guaranteed to be unique to the
13 // current thread, and is also guaranteed to be non-zero. The variable has to have a
14 // non-zero size to guarantee it has a unique address for each thread.
15const KEY: ::std::thread::LocalKey<u8> =
{
const __RUST_STD_INTERNAL_INIT: u8 = { 0 };
unsafe {
::std::thread::LocalKey::new(const {
if ::std::mem::needs_drop::<u8>() {
|__rust_std_internal_init|
{
#[thread_local]
static __RUST_STD_INTERNAL_VAL:
::std::thread::local_impl::EagerStorage<u8> =
::std::thread::local_impl::EagerStorage::new(__RUST_STD_INTERNAL_INIT);
__RUST_STD_INTERNAL_VAL.get()
}
} else {
|__rust_std_internal_init|
{
#[thread_local]
static __RUST_STD_INTERNAL_VAL: u8 =
__RUST_STD_INTERNAL_INIT;
&__RUST_STD_INTERNAL_VAL
}
}
})
}
};thread_local!(static KEY: u8 = const { 0 });
16KEY.with(|x| {
17NonZeroUsize::new(core::ptr::from_ref(x).addr())
18 .expect("thread-local variable address is null")
19 })
20 }
21}
2223/// A reentrant mutual exclusion lock.
24///
25/// This lock blocks other threads waiting for it to become available. A thread
26/// which already holds the lock can acquire it additional times without
27/// blocking.
28///
29/// Unlike [`Mutex`](crate::Mutex), [`ReentrantMutexGuard`] does not provide
30/// mutable references to the locked data, because multiple guards can coexist
31/// on the same thread. Use interior mutability, such as [`RefCell`](core::cell::RefCell),
32/// to mutate the guarded data.
33///
34/// See [`Mutex`](crate::Mutex) for more details about the underlying mutex
35/// primitive.
36///
37/// # Examples
38///
39/// ```
40/// use parking_lot::ReentrantMutex;
41/// use std::cell::RefCell;
42///
43/// let lock = ReentrantMutex::new(RefCell::new(0));
44/// let first = lock.lock();
45/// let second = lock.lock();
46/// *first.borrow_mut() += 1;
47/// *second.borrow_mut() += 1;
48/// assert_eq!(*lock.lock().borrow(), 2);
49/// ```
50pub type ReentrantMutex<T> = lock_api::ReentrantMutex<RawMutex, RawThreadId, T>;
5152/// An RAII guard which releases one level of recursive locking when dropped.
53///
54/// The data protected by the mutex can be accessed through this guard via its
55/// [`Deref`](core::ops::Deref) implementation.
56pub type ReentrantMutexGuard<'a, T> = lock_api::ReentrantMutexGuard<'a, RawMutex, RawThreadId, T>;
5758/// An RAII mutex guard returned by [`ReentrantMutexGuard::map`], which can point to a
59/// subfield of the protected data.
60///
61/// The main difference between `MappedReentrantMutexGuard` and `ReentrantMutexGuard` is that the
62/// former doesn't support temporarily unlocking and re-locking, since that
63/// could introduce soundness issues if the locked object is modified by another
64/// thread.
65pub type MappedReentrantMutexGuard<'a, T> =
66 lock_api::MappedReentrantMutexGuard<'a, RawMutex, RawThreadId, T>;
6768#[cfg(test)]
69mod tests {
70use crate::ReentrantMutex;
71use crate::ReentrantMutexGuard;
72use std::cell::RefCell;
73use std::sync::Arc;
74use std::sync::mpsc::channel;
75use std::thread;
7677#[cfg(feature = "serde")]
78use postcard::{from_bytes, to_stdvec};
7980#[test]
81fn smoke() {
82let m = ReentrantMutex::new(2);
83 {
84let a = m.lock();
85 {
86let b = m.lock();
87 {
88let c = m.lock();
89assert_eq!(*c, 2);
90 }
91assert_eq!(*b, 2);
92 }
93assert_eq!(*a, 2);
94 }
95 }
9697#[test]
98fn is_mutex() {
99let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
100let m2 = m.clone();
101let lock = m.lock();
102let child = thread::spawn(move || {
103let lock = m2.lock();
104assert_eq!(*lock.borrow(), 4950);
105 });
106for i in 0..100 {
107let lock = m.lock();
108*lock.borrow_mut() += i;
109 }
110 drop(lock);
111 child.join().unwrap();
112 }
113114#[test]
115fn trylock_works() {
116let m = Arc::new(ReentrantMutex::new(()));
117let m2 = m.clone();
118let _lock = m.try_lock().unwrap();
119let _lock2 = m.try_lock().unwrap();
120 thread::spawn(move || {
121let lock = m2.try_lock();
122assert!(lock.is_none());
123 })
124 .join()
125 .unwrap();
126let _lock3 = m.try_lock().unwrap();
127 }
128129#[test]
130fn test_reentrant_mutex_debug() {
131let mutex = ReentrantMutex::new(vec![0u8, 10]);
132133assert_eq!(format!("{:?}", mutex), "ReentrantMutex { data: [0, 10] }");
134 }
135136#[test]
137fn test_reentrant_mutex_bump() {
138let mutex = Arc::new(ReentrantMutex::new(()));
139let mutex2 = mutex.clone();
140141let mut guard = mutex.lock();
142143let (tx, rx) = channel();
144145 thread::spawn(move || {
146let _guard = mutex2.lock();
147 tx.send(()).unwrap();
148 });
149150// `bump()` repeatedly until the thread starts up and requests the lock
151while rx.try_recv().is_err() {
152 ReentrantMutexGuard::bump(&mut guard);
153 }
154 }
155156#[cfg(feature = "serde")]
157 #[test]
158fn test_serde() {
159let contents: Vec<u8> = vec![0, 1, 2];
160let mutex = ReentrantMutex::new(contents.clone());
161162let serialized = to_stdvec(&mutex).unwrap();
163let deserialized: ReentrantMutex<Vec<u8>> = from_bytes(&serialized).unwrap();
164165assert_eq!(*(mutex.lock()), *(deserialized.lock()));
166assert_eq!(contents, *(deserialized.lock()));
167 }
168}