1//! This module implements a lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
2//! It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync` traits.
34use std::{fmt, hint};
56#[derive(#[automatically_derived]
impl ::core::clone::Clone for Mode {
#[inline]
fn clone(&self) -> Mode { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Mode { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for Mode {
#[inline]
fn eq(&self, other: &Mode) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq)]
7pub enum Mode {
8 NoSync,
9 Sync,
10}
1112use std::cell::{Cell, UnsafeCell};
13use std::marker::PhantomData;
14use std::mem::ManuallyDrop;
15use std::ops::{Deref, DerefMut};
1617use parking_lot::RawMutex;
18use parking_lot::lock_api::RawMutexas _;
1920use crate::sync::{DynSend, DynSync, mode};
2122/// A guard holding mutable access to a `Lock` which is in a locked state.
23#[must_use = "if unused the Lock will immediately unlock"]
24pub struct LockGuard<'a, T> {
25 lock: &'a Lock<T>,
26 marker: PhantomData<&'a mut T>,
2728/// The synchronization mode of the lock. This is explicitly passed to let LLVM relate it
29 /// to the original lock operation.
30mode: Mode,
31}
3233impl<'a, T: 'a> Dereffor LockGuard<'a, T> {
34type Target = T;
35#[inline]
36fn deref(&self) -> &T {
37// SAFETY: We have shared access to the mutable access owned by this type,
38 // so we can give out a shared reference.
39unsafe { &*self.lock.data.get() }
40 }
41}
4243impl<'a, T: 'a> DerefMutfor LockGuard<'a, T> {
44#[inline]
45fn deref_mut(&mut self) -> &mut T {
46// SAFETY: We have mutable access to the data so we can give out a mutable reference.
47unsafe { &mut *self.lock.data.get() }
48 }
49}
5051impl<'a, T: 'a> Dropfor LockGuard<'a, T> {
52#[inline]
53fn drop(&mut self) {
54// SAFETY (union access): We get `self.mode` from the lock operation so it is consistent
55 // with the `lock.mode` state. This means we access the right union fields.
56match self.mode {
57 Mode::NoSync => {
58let cell = unsafe { &self.lock.mode_union.no_sync };
59if true {
if !cell.get() {
::core::panicking::panic("assertion failed: cell.get()")
};
};debug_assert!(cell.get());
60cell.set(false);
61 }
62// SAFETY (unlock): We know that the lock is locked as this type is a proof of that.
63Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() },
64 }
65 }
66}
6768union ModeUnion {
69/// Indicates if the cell is locked. Only used if `Lock.mode` is `NoSync`.
70no_sync: ManuallyDrop<Cell<bool>>,
7172/// A lock implementation that's only used if `Lock.mode` is `Sync`.
73sync: ManuallyDrop<RawMutex>,
74}
7576/// The value representing a locked state for the `Cell`.
77const LOCKED: bool = true;
7879/// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
80/// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`.
81pub struct Lock<T> {
82/// Indicates if synchronization is used via `mode_union.sync` if it's `Sync`, or if a
83 /// not thread safe cell is used via `mode_union.no_sync` if it's `NoSync`.
84 /// This is set on initialization and never changed.
85mode: Mode,
8687 mode_union: ModeUnion,
88 data: UnsafeCell<T>,
89}
9091impl<T> Lock<T> {
92#[inline(always)]
93pub fn new(inner: T) -> Self {
94let (mode, mode_union) = if mode::might_be_dyn_thread_safe() {
95 hint::cold_path();
96// Create the lock with synchronization enabled using the `RawMutex` type.
97(Mode::Sync, ModeUnion { sync: ManuallyDrop::new(RawMutex::INIT) })
98 } else {
99// Create the lock with synchronization disabled.
100(Mode::NoSync, ModeUnion { no_sync: ManuallyDrop::new(Cell::new(!LOCKED)) })
101 };
102Lock { mode, mode_union, data: UnsafeCell::new(inner) }
103 }
104105#[inline(always)]
106pub fn into_inner(self) -> T {
107self.data.into_inner()
108 }
109110#[inline(always)]
111pub fn get_mut(&mut self) -> &mut T {
112self.data.get_mut()
113 }
114115#[inline(always)]
116pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
117let mode = self.mode;
118// SAFETY: This is safe since the union fields are used in accordance with `self.mode`.
119match mode {
120 Mode::NoSync => {
121let cell = unsafe { &self.mode_union.no_sync };
122let was_unlocked = cell.get() != LOCKED;
123if was_unlocked {
124cell.set(LOCKED);
125 }
126was_unlocked127 }
128 Mode::Sync => unsafe { self.mode_union.sync.try_lock() },
129 }
130 .then(|| LockGuard { lock: self, marker: PhantomData, mode })
131 }
132133/// This acquires the lock assuming synchronization is in a specific mode.
134 ///
135 /// Safety
136 /// This method must only be called with `Mode::Sync` if `might_be_dyn_thread_safe` was
137 /// true on lock creation.
138#[inline(always)]
139 #[track_caller]
140pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> {
141#[inline(never)]
142 #[track_caller]
143 #[cold]
144fn lock_held() -> ! {
145{ ::core::panicking::panic_fmt(format_args!("lock was already held")); }panic!("lock was already held")146 }
147148// SAFETY: This is safe since the union fields are used in accordance with `mode`
149 // which also must match `self.mode` due to the safety precondition.
150unsafe {
151match mode {
152 Mode::NoSync => {
153if self.mode_union.no_sync.replace(LOCKED) == LOCKED {
154 hint::cold_path();
155lock_held()
156 }
157 }
158 Mode::Sync => self.mode_union.sync.lock(),
159 }
160 }
161LockGuard { lock: self, marker: PhantomData, mode }
162 }
163164#[inline(always)]
165 #[track_caller]
166pub fn lock(&self) -> LockGuard<'_, T> {
167unsafe { self.lock_assume(self.mode) }
168 }
169}
170171unsafe impl<T: DynSend> DynSendfor Lock<T> {}
172unsafe impl<T: DynSend> DynSyncfor Lock<T> {}
173174impl<T> Lock<T> {
175#[inline(always)]
176 #[track_caller]
177pub fn with_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
178f(&mut *self.lock())
179 }
180181#[inline(always)]
182 #[track_caller]
183pub fn borrow(&self) -> LockGuard<'_, T> {
184self.lock()
185 }
186187#[inline(always)]
188 #[track_caller]
189pub fn borrow_mut(&self) -> LockGuard<'_, T> {
190self.lock()
191 }
192}
193194impl<T: Default> Defaultfor Lock<T> {
195#[inline]
196fn default() -> Self {
197Lock::new(T::default())
198 }
199}
200201impl<T: fmt::Debug> fmt::Debugfor Lock<T> {
202fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203match self.try_lock() {
204Some(guard) => f.debug_struct("Lock").field("data", &&*guard).finish(),
205None => {
206struct LockedPlaceholder;
207impl fmt::Debugfor LockedPlaceholder {
208fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209f.write_str("<locked>")
210 }
211 }
212213f.debug_struct("Lock").field("data", &LockedPlaceholder).finish()
214 }
215 }
216 }
217}