Coverage Report

Created: 2025-02-25 06:39

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