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}