lock_api/remutex.rs
1use crate::{
2 GuardNoSend,
3 guard::{SharedGuardData, abort_on_panic},
4 mutex::{RawMutex, RawMutexFair, RawMutexTimed},
5};
6use core::{
7 cell::{Cell, UnsafeCell},
8 fmt,
9 marker::PhantomData,
10 mem::{self, MaybeUninit},
11 num::NonZeroUsize,
12 ops::Deref,
13 sync::atomic::{AtomicUsize, Ordering},
14};
15
16#[cfg(feature = "arc_lock")]
17use alloc::sync::Arc;
18use core::mem::ManuallyDrop;
19#[cfg(feature = "arc_lock")]
20use core::ptr;
21
22#[cfg(feature = "owning_ref")]
23use owning_ref::StableAddress;
24
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Deserializer, Serialize, Serializer};
27
28/// Helper trait which returns a non-zero thread ID.
29///
30/// The simplest way to implement this trait is to return the address of a
31/// thread-local variable.
32///
33/// # Safety
34///
35/// Implementations of this trait must ensure that no two active threads share
36/// the same thread ID. Repeated calls on the same `GetThreadId` value from the
37/// same active thread must return the same thread ID. However the ID of a
38/// thread that has exited can be reused since that thread is no longer active.
39pub unsafe trait GetThreadId {
40 /// Initial value.
41 // A “non-constant” const item is a legacy way to supply an initialized value to downstream
42 // static items. Can hopefully be replaced with `const fn new() -> Self` at some point.
43 #[allow(clippy::declare_interior_mutable_const)]
44 const INIT: Self;
45
46 /// Returns a non-zero thread ID which identifies the current thread of
47 /// execution.
48 fn nonzero_thread_id(&self) -> NonZeroUsize;
49}
50
51/// A raw mutex type that wraps another raw mutex to provide reentrancy.
52///
53/// Although this has the same methods as the [`RawMutex`] trait, it does
54/// not implement it, and should not be used in the same way, since this
55/// mutex can successfully acquire a lock multiple times in the same thread.
56/// Only use this when you know you want a raw mutex that can be locked
57/// reentrantly; you probably want [`ReentrantMutex`] instead.
58pub struct RawReentrantMutex<R: RawMutex, G> {
59 owner: AtomicUsize,
60 lock_count: Cell<usize>,
61 mutex: R,
62 guard: UnsafeCell<MaybeUninit<R::Guard>>,
63 get_thread_id: G,
64}
65
66// The acquisition state is only accessed by the owning thread and is leaked
67// if the raw mutex is dropped while locked, just like a forgotten guard.
68unsafe impl<R: RawMutex + Send, G: Send> Send for RawReentrantMutex<R, G> {}
69
70unsafe impl<R: RawMutex + Sync, G: GetThreadId + Sync> Sync for RawReentrantMutex<R, G> {}
71
72impl<R: RawMutex, G: GetThreadId> RawReentrantMutex<R, G> {
73 /// Initial value for an unlocked mutex.
74 #[allow(clippy::declare_interior_mutable_const)]
75 pub const INIT: Self = RawReentrantMutex {
76 owner: AtomicUsize::new(0),
77 lock_count: Cell::new(0),
78 guard: UnsafeCell::new(MaybeUninit::uninit()),
79 mutex: R::INIT,
80 get_thread_id: G::INIT,
81 };
82
83 #[inline]
84 fn lock_internal<F: FnOnce() -> Option<R::Guard>>(&self, try_lock: F) -> bool {
85 let id = self.get_thread_id.nonzero_thread_id().get();
86 if self.owner.load(Ordering::Relaxed) == id {
87 self.lock_count.set(
88 self.lock_count
89 .get()
90 .checked_add(1)
91 .expect("ReentrantMutex lock count overflow"),
92 );
93 } else {
94 let Some(guard) = try_lock() else {
95 return false;
96 };
97 // SAFETY: We have just acquired the underlying mutex.
98 unsafe {
99 (*self.guard.get()).write(guard);
100 }
101 self.owner.store(id, Ordering::Relaxed);
102 debug_assert_eq!(self.lock_count.get(), 0);
103 self.lock_count.set(1);
104 }
105 true
106 }
107
108 /// Acquires this mutex, blocking if it is held by another thread.
109 ///
110 /// # Panics
111 ///
112 /// Panics if the recursive lock count overflows.
113 #[inline]
114 pub fn lock(&self) {
115 self.lock_internal(|| Some(self.mutex.lock()));
116 }
117
118 /// Attempts to acquire this mutex without blocking. Returns `true`
119 /// if the lock was successfully acquired and `false` otherwise.
120 ///
121 /// # Panics
122 ///
123 /// Panics if the recursive lock count overflows.
124 #[inline]
125 pub fn try_lock(&self) -> bool {
126 self.lock_internal(|| self.mutex.try_lock())
127 }
128
129 /// Unlocks this mutex. The inner mutex may not be unlocked if
130 /// this mutex was acquired previously in the current thread.
131 ///
132 /// # Safety
133 ///
134 /// This method may only be called if the mutex is held by the current thread.
135 #[inline]
136 pub unsafe fn unlock(&self) {
137 let lock_count = self.lock_count.get() - 1;
138 self.lock_count.set(lock_count);
139 if lock_count == 0 {
140 self.owner.store(0, Ordering::Relaxed);
141 // SAFETY: The final owner takes the state before releasing the mutex.
142 let guard = unsafe { (*self.guard.get()).assume_init_read() };
143 unsafe { self.mutex.unlock(guard) };
144 }
145 }
146
147 /// Checks whether the mutex is currently locked.
148 #[inline]
149 pub fn is_locked(&self) -> bool {
150 self.mutex.is_locked()
151 }
152
153 /// Checks whether the mutex is currently held by the current thread.
154 #[inline]
155 pub fn is_owned_by_current_thread(&self) -> bool {
156 let id = self.get_thread_id.nonzero_thread_id().get();
157 self.owner.load(Ordering::Relaxed) == id
158 }
159}
160
161impl<R: RawMutexFair, G: GetThreadId> RawReentrantMutex<R, G> {
162 /// Unlocks this mutex using a fair unlock protocol. The inner mutex
163 /// may not be unlocked if this mutex was acquired previously in the
164 /// current thread.
165 ///
166 /// # Safety
167 ///
168 /// This method may only be called if the mutex is held by the current thread.
169 #[inline]
170 pub unsafe fn unlock_fair(&self) {
171 let lock_count = self.lock_count.get() - 1;
172 self.lock_count.set(lock_count);
173 if lock_count == 0 {
174 self.owner.store(0, Ordering::Relaxed);
175 // SAFETY: The final owner takes the state before releasing the mutex.
176 let guard = unsafe { (*self.guard.get()).assume_init_read() };
177 unsafe { self.mutex.unlock_fair(guard) };
178 }
179 }
180
181 /// Temporarily yields the mutex to a waiting thread if there is one.
182 ///
183 /// This method is functionally equivalent to calling `unlock_fair` followed
184 /// by `lock`, however it can be much more efficient in the case where there
185 /// are no waiting threads.
186 ///
187 /// # Safety
188 ///
189 /// This method may only be called if the mutex is held by the current thread.
190 #[inline]
191 pub unsafe fn bump(&self) {
192 if self.lock_count.get() == 1 {
193 let id = self.owner.load(Ordering::Relaxed);
194 self.owner.store(0, Ordering::Relaxed);
195 self.lock_count.set(0);
196 // Other threads may use the token storage while bump releases the
197 // mutex. Restore our token and metadata once ownership is restored,
198 // including when the underlying bump unwinds.
199 let state = unsafe { (*self.guard.get()).assume_init_read() };
200 let mut guard = scopeguard::guard(state, |state| {
201 unsafe {
202 (*self.guard.get()).write(state);
203 }
204 self.owner.store(id, Ordering::Relaxed);
205 self.lock_count.set(1);
206 });
207 unsafe { self.mutex.bump(&mut guard) };
208 }
209 }
210}
211
212impl<R: RawMutexTimed, G: GetThreadId> RawReentrantMutex<R, G> {
213 /// Attempts to acquire this lock until a timeout is reached.
214 ///
215 /// See [`RawMutexTimed::try_lock_until`] for timeout behavior.
216 ///
217 /// # Panics
218 ///
219 /// Panics if the recursive lock count overflows.
220 #[inline]
221 pub fn try_lock_until(&self, timeout: R::Instant) -> bool {
222 self.lock_internal(|| self.mutex.try_lock_until(timeout))
223 }
224
225 /// Attempts to acquire this lock until a timeout is reached.
226 ///
227 /// See [`RawMutexTimed::try_lock_for`] for timeout behavior.
228 ///
229 /// # Panics
230 ///
231 /// Panics if the recursive lock count overflows.
232 #[inline]
233 pub fn try_lock_for(&self, timeout: R::Duration) -> bool {
234 self.lock_internal(|| self.mutex.try_lock_for(timeout))
235 }
236}
237
238/// A reentrant mutual exclusion lock.
239///
240/// This lock blocks other threads waiting for it to become available. A thread
241/// which already holds the lock can acquire it additional times without
242/// blocking.
243///
244/// Unlike [`Mutex`](crate::Mutex), [`ReentrantMutexGuard`] does not provide
245/// mutable references to the locked data, because multiple guards can coexist
246/// on the same thread. Use interior mutability, such as
247/// [`Cell`](core::cell::Cell) or [`RefCell`](core::cell::RefCell), to mutate the
248/// guarded data.
249pub struct ReentrantMutex<R: RawMutex, G, T: ?Sized> {
250 raw: RawReentrantMutex<R, G>,
251 data: UnsafeCell<T>,
252}
253
254unsafe impl<R: RawMutex + Sync, G: GetThreadId + Sync, T: ?Sized + Send> Sync
255 for ReentrantMutex<R, G, T>
256{
257}
258
259impl<R: RawMutex, G: GetThreadId, T> ReentrantMutex<R, G, T> {
260 /// Creates a new reentrant mutex in an unlocked state ready for use.
261 #[inline]
262 pub const fn new(val: T) -> ReentrantMutex<R, G, T> {
263 ReentrantMutex {
264 data: UnsafeCell::new(val),
265 raw: RawReentrantMutex {
266 owner: AtomicUsize::new(0),
267 lock_count: Cell::new(0),
268 guard: UnsafeCell::new(MaybeUninit::uninit()),
269 mutex: R::INIT,
270 get_thread_id: G::INIT,
271 },
272 }
273 }
274
275 /// Consumes this mutex, returning the underlying data.
276 #[inline]
277 pub fn into_inner(self) -> T {
278 self.data.into_inner()
279 }
280}
281
282impl<R: RawMutex, G, T> ReentrantMutex<R, G, T> {
283 /// Creates a new reentrant mutex based on a pre-existing raw mutex and a
284 /// helper to get the thread ID.
285 #[inline]
286 pub const fn from_raw(raw_mutex: R, get_thread_id: G, val: T) -> ReentrantMutex<R, G, T> {
287 ReentrantMutex {
288 data: UnsafeCell::new(val),
289 raw: RawReentrantMutex {
290 owner: AtomicUsize::new(0),
291 lock_count: Cell::new(0),
292 guard: UnsafeCell::new(MaybeUninit::uninit()),
293 mutex: raw_mutex,
294 get_thread_id,
295 },
296 }
297 }
298
299 /// Consumes this mutex, returning the underlying data, raw mutex and
300 /// thread ID helper.
301 #[inline]
302 pub fn into_inner_with_raw(self) -> (R, G, T) {
303 (
304 self.raw.mutex,
305 self.raw.get_thread_id,
306 self.data.into_inner(),
307 )
308 }
309}
310
311impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
312 /// Creates a new `ReentrantMutexGuard` without checking if the lock is held.
313 ///
314 /// # Safety
315 ///
316 /// This method must only be called if the thread logically holds the lock.
317 ///
318 /// Calling this function when a guard has already been produced is undefined behavior unless
319 /// the guard was forgotten with `mem::forget`.
320 ///
321 /// The caller must ensure that existing references to the protected data
322 /// remain valid when the returned guard is used or dropped. In particular,
323 /// the returned guard must not permit accesses that conflict with existing
324 /// references.
325 #[inline]
326 pub unsafe fn make_guard_unchecked(&self) -> ReentrantMutexGuard<'_, R, G, T> {
327 ReentrantMutexGuard {
328 remutex: self,
329 marker: PhantomData,
330 }
331 }
332
333 /// Acquires a reentrant mutex, blocking the current thread until it is able
334 /// to do so.
335 ///
336 /// If the mutex is held by another thread then this function will block the
337 /// local thread until it is available to acquire the mutex. If the mutex is
338 /// already held by the current thread then this function will increment the
339 /// lock reference count and return immediately. Upon returning,
340 /// the thread is the only thread with the mutex held. An RAII guard is
341 /// returned to allow scoped unlock of the lock. When the guard goes out of
342 /// scope, the mutex will be unlocked.
343 ///
344 /// # Panics
345 ///
346 /// Panics if the recursive lock count overflows.
347 #[inline]
348 #[track_caller]
349 pub fn lock(&self) -> ReentrantMutexGuard<'_, R, G, T> {
350 self.raw.lock();
351 // SAFETY: The lock is held, as required.
352 unsafe { self.make_guard_unchecked() }
353 }
354
355 /// Attempts to acquire this lock.
356 ///
357 /// If the lock could not be acquired at this time, then `None` is returned.
358 /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
359 /// guard is dropped.
360 ///
361 /// This function does not block.
362 ///
363 /// # Panics
364 ///
365 /// Panics if the recursive lock count overflows.
366 #[inline]
367 #[track_caller]
368 pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, R, G, T>> {
369 if self.raw.try_lock() {
370 // SAFETY: The lock is held, as required.
371 Some(unsafe { self.make_guard_unchecked() })
372 } else {
373 None
374 }
375 }
376
377 /// Returns a mutable reference to the underlying data.
378 ///
379 /// Since this call borrows the `ReentrantMutex` mutably, no actual locking
380 /// needs to take place -- the mutable borrow statically guarantees no new
381 /// locks can be acquired while the reference exists. This method does not
382 /// clear a lock previously abandoned by forgetting a
383 /// [`ReentrantMutexGuard`].
384 #[inline]
385 pub const fn get_mut(&mut self) -> &mut T {
386 self.data.get_mut()
387 }
388
389 /// Checks whether the mutex is currently locked.
390 ///
391 /// The result is a momentary snapshot and may be stale by the time it is
392 /// returned.
393 #[inline]
394 #[track_caller]
395 pub fn is_locked(&self) -> bool {
396 self.raw.is_locked()
397 }
398
399 /// Checks whether the mutex is currently held by the current thread.
400 #[inline]
401 #[track_caller]
402 pub fn is_owned_by_current_thread(&self) -> bool {
403 self.raw.is_owned_by_current_thread()
404 }
405
406 /// Forcibly unlocks the mutex.
407 ///
408 /// This is useful when combined with `mem::forget` to hold a lock without
409 /// the need to maintain a `ReentrantMutexGuard` object alive, for example when
410 /// dealing with FFI.
411 ///
412 /// # Safety
413 ///
414 /// This method must only be called if the current thread logically owns a
415 /// `ReentrantMutexGuard` but that guard has been discarded using
416 /// `mem::forget`.
417 /// Behavior is undefined if a mutex is unlocked when not locked.
418 ///
419 /// The caller must ensure that releasing the lock does not invalidate any
420 /// outstanding references to the protected data. Any subsequent access
421 /// through previously obtained pointers must be properly synchronized.
422 #[inline]
423 #[track_caller]
424 pub unsafe fn force_unlock(&self) {
425 unsafe { self.raw.unlock() };
426 }
427
428 /// Returns the underlying raw mutex object.
429 ///
430 /// Note that you will most likely need to import the `RawMutex` trait from
431 /// `lock_api` to be able to call functions on the raw mutex.
432 ///
433 /// # Safety
434 ///
435 /// The caller must ensure that operations on the raw lock preserve the
436 /// validity of all live guards and references to the protected data.
437 /// A guard must not be used or dropped while its lock is released, and any
438 /// access through previously obtained pointers must be properly synchronized.
439 /// Raw operations must also preserve the reentrant mutex's owner and
440 /// recursion count bookkeeping.
441 #[inline]
442 pub unsafe fn raw(&self) -> &R {
443 &self.raw.mutex
444 }
445
446 /// Returns a raw pointer to the underlying data.
447 ///
448 /// The returned pointer is always non-null and properly aligned, but the
449 /// caller must ensure that accesses through it are valid and properly
450 /// synchronized and that the pointer is not used after the mutex is
451 /// dropped. In particular, writing requires exclusive access to the data;
452 /// merely holding the reentrant mutex does not provide that because
453 /// multiple guards can coexist on the same thread.
454 #[inline]
455 pub const fn data_ptr(&self) -> *mut T {
456 self.data.get()
457 }
458
459 /// Creates a new `ArcReentrantMutexGuard` without checking if the lock is held.
460 ///
461 /// # Safety
462 ///
463 /// This method must only be called if the thread logically holds the lock.
464 ///
465 /// Calling this function when a guard has already been produced is undefined behavior unless
466 /// the guard was forgotten with `mem::forget`.
467 ///
468 /// The caller must ensure that existing references to the protected data
469 /// remain valid when the returned guard is used or dropped. In particular,
470 /// the returned guard must not permit accesses that conflict with existing
471 /// references.
472 #[cfg(feature = "arc_lock")]
473 #[inline]
474 pub unsafe fn make_arc_guard_unchecked(self: &Arc<Self>) -> ArcReentrantMutexGuard<R, G, T> {
475 ArcReentrantMutexGuard {
476 remutex: self.clone(),
477 data_marker: PhantomData,
478 marker: PhantomData,
479 }
480 }
481
482 /// Acquires a reentrant mutex through an `Arc`.
483 ///
484 /// This method is similar to the `lock` method; however, it requires the `ReentrantMutex` to be inside of an
485 /// `Arc` and the resulting mutex guard owns a clone of the `Arc` instead of borrowing the lock.
486 ///
487 /// # Panics
488 ///
489 /// Panics if the recursive lock count overflows.
490 #[cfg(feature = "arc_lock")]
491 #[inline]
492 #[track_caller]
493 pub fn lock_arc(self: &Arc<Self>) -> ArcReentrantMutexGuard<R, G, T> {
494 self.raw.lock();
495 // SAFETY: locking guarantee is upheld
496 unsafe { self.make_arc_guard_unchecked() }
497 }
498
499 /// Attempts to acquire a reentrant mutex through an `Arc`.
500 ///
501 /// This method is similar to the `try_lock` method; however, it requires the `ReentrantMutex` to be inside
502 /// of an `Arc` and the resulting mutex guard owns a clone of the `Arc` instead of borrowing the lock.
503 ///
504 /// # Panics
505 ///
506 /// Panics if the recursive lock count overflows.
507 #[cfg(feature = "arc_lock")]
508 #[inline]
509 #[track_caller]
510 pub fn try_lock_arc(self: &Arc<Self>) -> Option<ArcReentrantMutexGuard<R, G, T>> {
511 if self.raw.try_lock() {
512 // SAFETY: locking guarantee is upheld
513 Some(unsafe { self.make_arc_guard_unchecked() })
514 } else {
515 None
516 }
517 }
518}
519
520impl<R: RawMutexFair, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
521 /// Forcibly unlocks the mutex using a fair unlock protocol.
522 ///
523 /// This is useful when combined with `mem::forget` to hold a lock without
524 /// the need to maintain a `ReentrantMutexGuard` object alive, for example when
525 /// dealing with FFI.
526 ///
527 /// # Safety
528 ///
529 /// This method must only be called if the current thread logically owns a
530 /// `ReentrantMutexGuard` but that guard has been discarded using
531 /// `mem::forget`.
532 /// Behavior is undefined if a mutex is unlocked when not locked.
533 ///
534 /// The caller must ensure that releasing the lock does not invalidate any
535 /// outstanding references to the protected data. Any subsequent access
536 /// through previously obtained pointers must be properly synchronized.
537 #[inline]
538 #[track_caller]
539 pub unsafe fn force_unlock_fair(&self) {
540 unsafe { self.raw.unlock_fair() };
541 }
542}
543
544impl<R: RawMutexTimed, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
545 /// Attempts to acquire this lock until a timeout is reached.
546 ///
547 /// If the lock could not be acquired before the timeout expired, then
548 /// `None` is returned. Otherwise, an RAII guard is returned. The lock will
549 /// be unlocked when the guard is dropped.
550 ///
551 /// A successful operation may return early. An unsuccessful operation will
552 /// not return before the timeout, but may return later due to scheduling or
553 /// platform-specific behavior.
554 ///
555 /// # Panics
556 ///
557 /// Panics if the recursive lock count overflows.
558 #[inline]
559 #[track_caller]
560 pub fn try_lock_for(&self, timeout: R::Duration) -> Option<ReentrantMutexGuard<'_, R, G, T>> {
561 if self.raw.try_lock_for(timeout) {
562 // SAFETY: The lock is held, as required.
563 Some(unsafe { self.make_guard_unchecked() })
564 } else {
565 None
566 }
567 }
568
569 /// Attempts to acquire this lock until a timeout is reached.
570 ///
571 /// If the lock could not be acquired before the timeout expired, then
572 /// `None` is returned. Otherwise, an RAII guard is returned. The lock will
573 /// be unlocked when the guard is dropped.
574 ///
575 /// A successful operation may return early. An unsuccessful operation will
576 /// not return before the timeout, but may return later due to scheduling or
577 /// platform-specific behavior.
578 ///
579 /// # Panics
580 ///
581 /// Panics if the recursive lock count overflows.
582 #[inline]
583 #[track_caller]
584 pub fn try_lock_until(&self, timeout: R::Instant) -> Option<ReentrantMutexGuard<'_, R, G, T>> {
585 if self.raw.try_lock_until(timeout) {
586 // SAFETY: The lock is held, as required.
587 Some(unsafe { self.make_guard_unchecked() })
588 } else {
589 None
590 }
591 }
592
593 /// Attempts to acquire this lock until a timeout is reached, through an `Arc`.
594 ///
595 /// This method is similar to the `try_lock_for` method; however, it requires the `ReentrantMutex` to be
596 /// inside of an `Arc` and the resulting mutex guard owns a clone of the `Arc` instead of borrowing the lock.
597 ///
598 /// See [`try_lock_for`](Self::try_lock_for) for timeout behavior.
599 ///
600 /// # Panics
601 ///
602 /// Panics if the recursive lock count overflows.
603 #[cfg(feature = "arc_lock")]
604 #[inline]
605 #[track_caller]
606 pub fn try_lock_arc_for(
607 self: &Arc<Self>,
608 timeout: R::Duration,
609 ) -> Option<ArcReentrantMutexGuard<R, G, T>> {
610 if self.raw.try_lock_for(timeout) {
611 // SAFETY: locking guarantee is upheld
612 Some(unsafe { self.make_arc_guard_unchecked() })
613 } else {
614 None
615 }
616 }
617
618 /// Attempts to acquire this lock until a timeout is reached, through an `Arc`.
619 ///
620 /// This method is similar to the `try_lock_until` method; however, it requires the `ReentrantMutex` to be
621 /// inside of an `Arc` and the resulting mutex guard owns a clone of the `Arc` instead of borrowing the lock.
622 ///
623 /// See [`try_lock_until`](Self::try_lock_until) for timeout behavior.
624 ///
625 /// # Panics
626 ///
627 /// Panics if the recursive lock count overflows.
628 #[cfg(feature = "arc_lock")]
629 #[inline]
630 #[track_caller]
631 pub fn try_lock_arc_until(
632 self: &Arc<Self>,
633 timeout: R::Instant,
634 ) -> Option<ArcReentrantMutexGuard<R, G, T>> {
635 if self.raw.try_lock_until(timeout) {
636 // SAFETY: locking guarantee is upheld
637 Some(unsafe { self.make_arc_guard_unchecked() })
638 } else {
639 None
640 }
641 }
642}
643
644impl<R: RawMutex, G: GetThreadId, T: Default> Default for ReentrantMutex<R, G, T> {
645 #[inline]
646 fn default() -> ReentrantMutex<R, G, T> {
647 ReentrantMutex::new(Default::default())
648 }
649}
650
651impl<R: RawMutex, G: GetThreadId, T> From<T> for ReentrantMutex<R, G, T> {
652 #[inline]
653 fn from(t: T) -> ReentrantMutex<R, G, T> {
654 ReentrantMutex::new(t)
655 }
656}
657
658impl<R: RawMutex, G: GetThreadId, T: ?Sized + fmt::Debug> fmt::Debug for ReentrantMutex<R, G, T> {
659 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
660 match self.try_lock() {
661 Some(guard) => f
662 .debug_struct("ReentrantMutex")
663 .field("data", &&*guard)
664 .finish(),
665 None => {
666 struct LockedPlaceholder;
667 impl fmt::Debug for LockedPlaceholder {
668 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
669 f.write_str("<locked>")
670 }
671 }
672
673 f.debug_struct("ReentrantMutex")
674 .field("data", &LockedPlaceholder)
675 .finish()
676 }
677 }
678 }
679}
680
681// Copied and modified from serde
682#[cfg(feature = "serde")]
683impl<R, G, T> Serialize for ReentrantMutex<R, G, T>
684where
685 R: RawMutex,
686 G: GetThreadId,
687 T: Serialize + ?Sized,
688{
689 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
690 where
691 S: Serializer,
692 {
693 self.lock().serialize(serializer)
694 }
695}
696
697#[cfg(feature = "serde")]
698impl<'de, R, G, T> Deserialize<'de> for ReentrantMutex<R, G, T>
699where
700 R: RawMutex,
701 G: GetThreadId,
702 T: Deserialize<'de>,
703{
704 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
705 where
706 D: Deserializer<'de>,
707 {
708 Deserialize::deserialize(deserializer).map(ReentrantMutex::new)
709 }
710}
711
712/// An RAII guard which releases one level of recursive locking when dropped.
713///
714/// The data protected by the mutex can be accessed through this guard via its
715/// [`Deref`] implementation.
716///
717/// This structure is created by the [`lock`](ReentrantMutex::lock) and
718/// [`try_lock`](ReentrantMutex::try_lock) methods on [`ReentrantMutex`].
719///
720/// # Mutability
721///
722/// Unlike [`MutexGuard`](crate::MutexGuard), `ReentrantMutexGuard` does not
723/// implement [`DerefMut`](core::ops::DerefMut), because doing so would violate Rust's reference
724/// aliasing rules when multiple guards exist on one thread. Use interior
725/// mutability, such as [`Cell`](core::cell::Cell) or
726/// [`RefCell`](core::cell::RefCell), to mutate the guarded data.
727#[clippy::has_significant_drop]
728#[must_use = "if unused the ReentrantMutex will immediately unlock"]
729pub struct ReentrantMutexGuard<'a, R: RawMutex, G: GetThreadId, T: ?Sized> {
730 remutex: &'a ReentrantMutex<R, G, T>,
731 marker: PhantomData<(&'a T, GuardNoSend)>,
732}
733
734impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> ReentrantMutexGuard<'a, R, G, T> {
735 /// Returns a reference to the original `ReentrantMutex` object.
736 pub fn remutex(s: &Self) -> &'a ReentrantMutex<R, G, T> {
737 s.remutex
738 }
739
740 /// Makes a new `MappedReentrantMutexGuard` for a component of the locked data.
741 ///
742 /// This is an associated function that needs to be
743 /// used as `ReentrantMutexGuard::map(...)`. A method would interfere with methods of
744 /// the same name on the contents of the locked data.
745 ///
746 /// # Panics
747 ///
748 /// If `f` panics, the original guard is dropped.
749 #[inline]
750 pub fn map<U: ?Sized, F>(s: Self, f: F) -> MappedReentrantMutexGuard<'a, R, G, U>
751 where
752 F: FnOnce(&T) -> &U,
753 {
754 let raw = &s.remutex.raw;
755 let data = f(unsafe { s.remutex.data.get().as_ref_unchecked() });
756 mem::forget(s);
757 MappedReentrantMutexGuard {
758 raw,
759 data: SharedGuardData::new(data),
760 marker: PhantomData,
761 }
762 }
763
764 /// Attempts to make a new `MappedReentrantMutexGuard` for a component of the
765 /// locked data. The original guard is returned if the closure returns
766 /// `None`.
767 ///
768 /// This is an associated function that needs to be
769 /// used as `ReentrantMutexGuard::try_map(...)`. A method would interfere with methods of
770 /// the same name on the contents of the locked data.
771 ///
772 /// # Panics
773 ///
774 /// If `f` panics, the original guard is dropped.
775 #[inline]
776 pub fn try_map<U: ?Sized, F>(
777 s: Self,
778 f: F,
779 ) -> Result<MappedReentrantMutexGuard<'a, R, G, U>, Self>
780 where
781 F: FnOnce(&T) -> Option<&U>,
782 {
783 let raw = &s.remutex.raw;
784 let Some(data) = f(unsafe { s.remutex.data.get().as_ref_unchecked() }) else {
785 return Err(s);
786 };
787 mem::forget(s);
788 Ok(MappedReentrantMutexGuard {
789 raw,
790 data: SharedGuardData::new(data),
791 marker: PhantomData,
792 })
793 }
794
795 /// Attempts to make a new `MappedReentrantMutexGuard` for a component of the
796 /// locked data. The original guard is returned alongside arbitrary user data
797 /// if the closure returns `Err`.
798 ///
799 /// This is an associated function that needs to be
800 /// used as `ReentrantMutexGuard::try_map_or_err(...)`. A method would interfere with methods of
801 /// the same name on the contents of the locked data.
802 ///
803 /// # Panics
804 ///
805 /// If `f` panics, the original guard is dropped.
806 #[inline]
807 pub fn try_map_or_err<U: ?Sized, F, E>(
808 s: Self,
809 f: F,
810 ) -> Result<MappedReentrantMutexGuard<'a, R, G, U>, (Self, E)>
811 where
812 F: FnOnce(&T) -> Result<&U, E>,
813 {
814 let raw = &s.remutex.raw;
815 let data = match f(unsafe { s.remutex.data.get().as_ref_unchecked() }) {
816 Ok(data) => data,
817 Err(e) => return Err((s, e)),
818 };
819 mem::forget(s);
820 Ok(MappedReentrantMutexGuard {
821 raw,
822 data: SharedGuardData::new(data),
823 marker: PhantomData,
824 })
825 }
826
827 /// Temporarily unlocks the mutex to execute the given function.
828 ///
829 /// This releases only one level of recursive locking. The underlying mutex
830 /// remains locked if the current thread has acquired it more than once.
831 ///
832 /// # Aborts
833 ///
834 /// Aborts if re-locking the mutex panics.
835 #[inline]
836 #[track_caller]
837 pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
838 where
839 F: FnOnce() -> U,
840 {
841 // Restore the recursive acquisition even if the final raw unlock panics.
842 defer!(abort_on_panic(|| s.remutex.raw.lock()));
843 // SAFETY: This guard owns one recursive acquisition on the current thread.
844 unsafe { s.remutex.raw.unlock() };
845 f()
846 }
847}
848
849impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a>
850 ReentrantMutexGuard<'a, R, G, T>
851{
852 /// Releases one level of recursive locking. A fair unlock is performed
853 /// only if this releases the final level.
854 #[inline]
855 #[track_caller]
856 pub fn unlock_fair(s: Self) {
857 let s = ManuallyDrop::new(s);
858 // Safety: A ReentrantMutexGuard always holds the lock
859 unsafe {
860 s.remutex.raw.unlock_fair();
861 }
862 }
863
864 /// Temporarily unlocks the mutex to execute the given function.
865 ///
866 /// This releases only one level of recursive locking. A fair unlock is
867 /// performed only if this releases the final level.
868 ///
869 /// # Aborts
870 ///
871 /// Aborts if re-locking the mutex panics.
872 #[inline]
873 #[track_caller]
874 pub fn unlocked_fair<F, U>(s: &mut Self, f: F) -> U
875 where
876 F: FnOnce() -> U,
877 {
878 // Restore the recursive acquisition even if the final raw unlock panics.
879 defer!(abort_on_panic(|| s.remutex.raw.lock()));
880 // SAFETY: This guard owns one recursive acquisition on the current thread.
881 unsafe { s.remutex.raw.unlock_fair() };
882 f()
883 }
884
885 /// Temporarily yields the mutex to a waiting thread if there is one.
886 ///
887 /// This method is functionally equivalent to calling `unlock_fair` followed
888 /// by `lock`, however it can be much more efficient in the case where there
889 /// are no waiting threads.
890 #[inline]
891 #[track_caller]
892 pub fn bump(s: &mut Self) {
893 // Safety: A ReentrantMutexGuard always holds the lock
894 unsafe { s.remutex.raw.bump() };
895 }
896}
897
898impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Deref
899 for ReentrantMutexGuard<'a, R, G, T>
900{
901 type Target = T;
902 #[inline]
903 fn deref(&self) -> &T {
904 unsafe { self.remutex.data.get().as_ref_unchecked() }
905 }
906}
907
908impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Drop
909 for ReentrantMutexGuard<'a, R, G, T>
910{
911 #[inline]
912 fn drop(&mut self) {
913 // Safety: A ReentrantMutexGuard always holds the lock.
914 unsafe {
915 self.remutex.raw.unlock();
916 }
917 }
918}
919
920impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug
921 for ReentrantMutexGuard<'a, R, G, T>
922{
923 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
924 fmt::Debug::fmt(&**self, f)
925 }
926}
927
928impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display
929 for ReentrantMutexGuard<'a, R, G, T>
930{
931 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
932 (**self).fmt(f)
933 }
934}
935
936#[cfg(feature = "owning_ref")]
937unsafe impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> StableAddress
938 for ReentrantMutexGuard<'a, R, G, T>
939{
940}
941
942/// An RAII mutex guard returned by the `Arc` locking operations on
943/// [`ReentrantMutex`].
944///
945/// Unlike [`ReentrantMutexGuard`], this guard owns the [`Arc`] used to unlock
946/// the mutex instead of borrowing the mutex, so its lifetime is not tied to a
947/// lock reference.
948#[cfg(feature = "arc_lock")]
949#[clippy::has_significant_drop]
950#[must_use = "if unused the ReentrantMutex will immediately unlock"]
951pub struct ArcReentrantMutexGuard<R: RawMutex, G: GetThreadId, T: ?Sized> {
952 remutex: Arc<ReentrantMutex<R, G, T>>,
953 data_marker: PhantomData<T>,
954 marker: PhantomData<GuardNoSend>,
955}
956
957#[cfg(feature = "arc_lock")]
958impl<R: RawMutex, G: GetThreadId, T: ?Sized> ArcReentrantMutexGuard<R, G, T> {
959 /// Returns a reference to the `ReentrantMutex` this object is guarding, contained in its `Arc`.
960 pub fn remutex(s: &Self) -> &Arc<ReentrantMutex<R, G, T>> {
961 &s.remutex
962 }
963
964 /// Releases one level of recursive locking and returns the `Arc` held by
965 /// the [`ArcReentrantMutexGuard`]. The underlying mutex remains locked if
966 /// the current thread has acquired it more than once.
967 #[inline]
968 pub fn into_arc(s: Self) -> Arc<ReentrantMutex<R, G, T>> {
969 let s = ManuallyDrop::new(s);
970 // SAFETY: ManuallyDrop lets us move the Arc into a local that drops on unwind.
971 let remutex = unsafe { ptr::read(&s.remutex) };
972 // SAFETY: We own this recursive acquisition; ManuallyDrop prevents a second unlock.
973 unsafe { remutex.raw.unlock() };
974 remutex
975 }
976
977 /// Temporarily unlocks the mutex to execute the given function.
978 ///
979 /// This releases only one level of recursive locking. The underlying mutex
980 /// remains locked if the current thread has acquired it more than once.
981 ///
982 /// # Aborts
983 ///
984 /// Aborts if re-locking the mutex panics.
985 #[inline]
986 #[track_caller]
987 pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
988 where
989 F: FnOnce() -> U,
990 {
991 // Restore the recursive acquisition even if the final raw unlock panics.
992 defer!(abort_on_panic(|| s.remutex.raw.lock()));
993 // SAFETY: This guard owns one recursive acquisition on the current thread.
994 unsafe { s.remutex.raw.unlock() };
995 f()
996 }
997}
998
999#[cfg(feature = "arc_lock")]
1000impl<R: RawMutexFair, G: GetThreadId, T: ?Sized> ArcReentrantMutexGuard<R, G, T> {
1001 /// Releases one level of recursive locking. A fair unlock is performed
1002 /// only if this releases the final level.
1003 #[inline]
1004 #[track_caller]
1005 pub fn unlock_fair(s: Self) {
1006 drop(Self::into_arc_fair(s));
1007 }
1008
1009 /// Releases one level of recursive locking and returns the `Arc` held by
1010 /// the [`ArcReentrantMutexGuard`]. A fair unlock is performed only if this
1011 /// releases the final level.
1012 #[inline]
1013 pub fn into_arc_fair(s: Self) -> Arc<ReentrantMutex<R, G, T>> {
1014 let s = ManuallyDrop::new(s);
1015 // SAFETY: ManuallyDrop lets us move the Arc into a local that drops on unwind.
1016 let remutex = unsafe { ptr::read(&s.remutex) };
1017 // SAFETY: We own this recursive acquisition; ManuallyDrop prevents a second unlock.
1018 unsafe { remutex.raw.unlock_fair() };
1019 remutex
1020 }
1021
1022 /// Temporarily unlocks the mutex to execute the given function.
1023 ///
1024 /// This releases only one level of recursive locking. A fair unlock is
1025 /// performed only if this releases the final level.
1026 ///
1027 /// # Aborts
1028 ///
1029 /// Aborts if re-locking the mutex panics.
1030 #[inline]
1031 #[track_caller]
1032 pub fn unlocked_fair<F, U>(s: &mut Self, f: F) -> U
1033 where
1034 F: FnOnce() -> U,
1035 {
1036 // Restore the recursive acquisition even if the final raw unlock panics.
1037 defer!(abort_on_panic(|| s.remutex.raw.lock()));
1038 // SAFETY: This guard owns one recursive acquisition on the current thread.
1039 unsafe { s.remutex.raw.unlock_fair() };
1040 f()
1041 }
1042
1043 /// Temporarily yields the mutex to a waiting thread if there is one.
1044 ///
1045 /// This is functionally equivalent to the `bump` method on [`ReentrantMutexGuard`].
1046 #[inline]
1047 #[track_caller]
1048 pub fn bump(s: &mut Self) {
1049 // Safety: A ReentrantMutexGuard always holds the lock
1050 unsafe { s.remutex.raw.bump() };
1051 }
1052}
1053
1054#[cfg(feature = "arc_lock")]
1055impl<R: RawMutex, G: GetThreadId, T: ?Sized> Deref for ArcReentrantMutexGuard<R, G, T> {
1056 type Target = T;
1057 #[inline]
1058 fn deref(&self) -> &T {
1059 unsafe { self.remutex.data.get().as_ref_unchecked() }
1060 }
1061}
1062
1063#[cfg(feature = "arc_lock")]
1064impl<R: RawMutex, G: GetThreadId, T: ?Sized> Drop for ArcReentrantMutexGuard<R, G, T> {
1065 #[inline]
1066 fn drop(&mut self) {
1067 // Safety: A ReentrantMutexGuard always holds the lock.
1068 unsafe {
1069 self.remutex.raw.unlock();
1070 }
1071 }
1072}
1073
1074/// An RAII mutex guard returned by [`ReentrantMutexGuard::map`], which can point to a
1075/// subfield of the protected data.
1076///
1077/// The main difference between `MappedReentrantMutexGuard` and `ReentrantMutexGuard` is that the
1078/// former doesn't support temporarily unlocking and re-locking, since that
1079/// could introduce soundness issues if the locked object is modified by another
1080/// thread.
1081///
1082/// This structure is created by the [`map`](ReentrantMutexGuard::map) and
1083/// [`try_map`](ReentrantMutexGuard::try_map), and
1084/// [`try_map_or_err`](ReentrantMutexGuard::try_map_or_err) functions on
1085/// [`ReentrantMutexGuard`].
1086#[clippy::has_significant_drop]
1087#[must_use = "if unused the ReentrantMutex will immediately unlock"]
1088pub struct MappedReentrantMutexGuard<'a, R: RawMutex, G: GetThreadId, T: ?Sized + 'a> {
1089 raw: &'a RawReentrantMutex<R, G>,
1090 data: SharedGuardData<T>,
1091 marker: PhantomData<GuardNoSend>,
1092}
1093
1094impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a>
1095 MappedReentrantMutexGuard<'a, R, G, T>
1096{
1097 /// Makes a new `MappedReentrantMutexGuard` for a component of the locked data.
1098 ///
1099 /// This is an associated function that needs to be
1100 /// used as `MappedReentrantMutexGuard::map(...)`. A method would interfere with methods of
1101 /// the same name on the contents of the locked data.
1102 ///
1103 /// # Panics
1104 ///
1105 /// If `f` panics, the original guard is dropped.
1106 #[inline]
1107 pub fn map<U: ?Sized, F>(s: Self, f: F) -> MappedReentrantMutexGuard<'a, R, G, U>
1108 where
1109 F: FnOnce(&T) -> &U,
1110 {
1111 let raw = s.raw;
1112 let data = SharedGuardData::new(f(unsafe { s.data.as_ref() }));
1113 mem::forget(s);
1114 MappedReentrantMutexGuard {
1115 raw,
1116 data,
1117 marker: PhantomData,
1118 }
1119 }
1120
1121 /// Attempts to make a new `MappedReentrantMutexGuard` for a component of the
1122 /// locked data. The original guard is returned if the closure returns `None`.
1123 ///
1124 /// This is an associated function that needs to be
1125 /// used as `MappedReentrantMutexGuard::try_map(...)`. A method would interfere with methods of
1126 /// the same name on the contents of the locked data.
1127 ///
1128 /// # Panics
1129 ///
1130 /// If `f` panics, the original guard is dropped.
1131 #[inline]
1132 pub fn try_map<U: ?Sized, F>(
1133 s: Self,
1134 f: F,
1135 ) -> Result<MappedReentrantMutexGuard<'a, R, G, U>, Self>
1136 where
1137 F: FnOnce(&T) -> Option<&U>,
1138 {
1139 let raw = s.raw;
1140 let Some(data) = f(unsafe { s.data.as_ref() }) else {
1141 return Err(s);
1142 };
1143 let data = SharedGuardData::new(data);
1144 mem::forget(s);
1145 Ok(MappedReentrantMutexGuard {
1146 raw,
1147 data,
1148 marker: PhantomData,
1149 })
1150 }
1151
1152 /// Attempts to make a new `MappedReentrantMutexGuard` for a component of the
1153 /// locked data. The original guard is returned alongside arbitrary user data
1154 /// if the closure returns `Err`.
1155 ///
1156 /// This is an associated function that needs to be
1157 /// used as `MappedReentrantMutexGuard::try_map_or_err(...)`. A method would interfere with methods of
1158 /// the same name on the contents of the locked data.
1159 ///
1160 /// # Panics
1161 ///
1162 /// If `f` panics, the original guard is dropped.
1163 #[inline]
1164 pub fn try_map_or_err<U: ?Sized, F, E>(
1165 s: Self,
1166 f: F,
1167 ) -> Result<MappedReentrantMutexGuard<'a, R, G, U>, (Self, E)>
1168 where
1169 F: FnOnce(&T) -> Result<&U, E>,
1170 {
1171 let raw = s.raw;
1172 let data = match f(unsafe { s.data.as_ref() }) {
1173 Ok(data) => data,
1174 Err(e) => return Err((s, e)),
1175 };
1176 let data = SharedGuardData::new(data);
1177 mem::forget(s);
1178 Ok(MappedReentrantMutexGuard {
1179 raw,
1180 data,
1181 marker: PhantomData,
1182 })
1183 }
1184}
1185
1186impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a>
1187 MappedReentrantMutexGuard<'a, R, G, T>
1188{
1189 /// Releases one level of recursive locking. A fair unlock is performed
1190 /// only if this releases the final level.
1191 #[inline]
1192 #[track_caller]
1193 pub fn unlock_fair(s: Self) {
1194 let s = ManuallyDrop::new(s);
1195 // Safety: A MappedReentrantMutexGuard always holds the lock
1196 unsafe {
1197 s.raw.unlock_fair();
1198 }
1199 }
1200}
1201
1202impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Deref
1203 for MappedReentrantMutexGuard<'a, R, G, T>
1204{
1205 type Target = T;
1206 #[inline]
1207 fn deref(&self) -> &T {
1208 unsafe { self.data.as_ref() }
1209 }
1210}
1211
1212impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Drop
1213 for MappedReentrantMutexGuard<'a, R, G, T>
1214{
1215 #[inline]
1216 fn drop(&mut self) {
1217 // Safety: A MappedReentrantMutexGuard always holds the lock.
1218 unsafe {
1219 self.raw.unlock();
1220 }
1221 }
1222}
1223
1224impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug
1225 for MappedReentrantMutexGuard<'a, R, G, T>
1226{
1227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1228 fmt::Debug::fmt(&**self, f)
1229 }
1230}
1231
1232impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display
1233 for MappedReentrantMutexGuard<'a, R, G, T>
1234{
1235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1236 (**self).fmt(f)
1237 }
1238}
1239
1240#[cfg(feature = "owning_ref")]
1241unsafe impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> StableAddress
1242 for MappedReentrantMutexGuard<'a, R, G, T>
1243{
1244}