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