Skip to main content

lock_api/
remutex.rs

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