rustc_data_structures/sync/
lock.rs1use std::fmt;
5
6#[derive(Clone, Copy, PartialEq)]
7pub enum Mode {
8 NoSync,
9 Sync,
10}
11
12use std::cell::{Cell, UnsafeCell};
13use std::intrinsics::unlikely;
14use std::marker::PhantomData;
15use std::mem::ManuallyDrop;
16use std::ops::{Deref, DerefMut};
17
18use parking_lot::RawMutex;
19use parking_lot::lock_api::RawMutex as _;
20
21use crate::sync::{DynSend, DynSync, mode};
22
23#[must_use = "if unused the Lock will immediately unlock"]
25pub struct LockGuard<'a, T> {
26 lock: &'a Lock<T>,
27 marker: PhantomData<&'a mut T>,
28
29 mode: Mode,
32}
33
34impl<'a, T: 'a> Deref for LockGuard<'a, T> {
35 type Target = T;
36 #[inline]
37 fn deref(&self) -> &T {
38 unsafe { &*self.lock.data.get() }
41 }
42}
43
44impl<'a, T: 'a> DerefMut for LockGuard<'a, T> {
45 #[inline]
46 fn deref_mut(&mut self) -> &mut T {
47 unsafe { &mut *self.lock.data.get() }
49 }
50}
51
52impl<'a, T: 'a> Drop for LockGuard<'a, T> {
53 #[inline]
54 fn drop(&mut self) {
55 match self.mode {
58 Mode::NoSync => {
59 let cell = unsafe { &self.lock.mode_union.no_sync };
60 debug_assert!(cell.get());
61 cell.set(false);
62 }
63 Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() },
65 }
66 }
67}
68
69union ModeUnion {
70 no_sync: ManuallyDrop<Cell<bool>>,
72
73 sync: ManuallyDrop<RawMutex>,
75}
76
77const LOCKED: bool = true;
79
80pub struct Lock<T> {
83 mode: Mode,
87
88 mode_union: ModeUnion,
89 data: UnsafeCell<T>,
90}
91
92impl<T> Lock<T> {
93 #[inline(always)]
94 pub fn new(inner: T) -> Self {
95 let (mode, mode_union) = if unlikely(mode::might_be_dyn_thread_safe()) {
96 (Mode::Sync, ModeUnion { sync: ManuallyDrop::new(RawMutex::INIT) })
98 } else {
99 (Mode::NoSync, ModeUnion { no_sync: ManuallyDrop::new(Cell::new(!LOCKED)) })
101 };
102 Lock { mode, mode_union, data: UnsafeCell::new(inner) }
103 }
104
105 #[inline(always)]
106 pub fn into_inner(self) -> T {
107 self.data.into_inner()
108 }
109
110 #[inline(always)]
111 pub fn get_mut(&mut self) -> &mut T {
112 self.data.get_mut()
113 }
114
115 #[inline(always)]
116 pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
117 let mode = self.mode;
118 match mode {
120 Mode::NoSync => {
121 let cell = unsafe { &self.mode_union.no_sync };
122 let was_unlocked = cell.get() != LOCKED;
123 if was_unlocked {
124 cell.set(LOCKED);
125 }
126 was_unlocked
127 }
128 Mode::Sync => unsafe { self.mode_union.sync.try_lock() },
129 }
130 .then(|| LockGuard { lock: self, marker: PhantomData, mode })
131 }
132
133 #[inline(always)]
139 #[track_caller]
140 pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> {
141 #[inline(never)]
142 #[track_caller]
143 #[cold]
144 fn lock_held() -> ! {
145 panic!("lock was already held")
146 }
147
148 unsafe {
151 match mode {
152 Mode::NoSync => {
153 if unlikely(self.mode_union.no_sync.replace(LOCKED) == LOCKED) {
154 lock_held()
155 }
156 }
157 Mode::Sync => self.mode_union.sync.lock(),
158 }
159 }
160 LockGuard { lock: self, marker: PhantomData, mode }
161 }
162
163 #[inline(always)]
164 #[track_caller]
165 pub fn lock(&self) -> LockGuard<'_, T> {
166 unsafe { self.lock_assume(self.mode) }
167 }
168}
169
170unsafe impl<T: DynSend> DynSend for Lock<T> {}
171unsafe impl<T: DynSend> DynSync for Lock<T> {}
172
173impl<T> Lock<T> {
174 #[inline(always)]
175 #[track_caller]
176 pub fn with_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
177 f(&mut *self.lock())
178 }
179
180 #[inline(always)]
181 #[track_caller]
182 pub fn borrow(&self) -> LockGuard<'_, T> {
183 self.lock()
184 }
185
186 #[inline(always)]
187 #[track_caller]
188 pub fn borrow_mut(&self) -> LockGuard<'_, T> {
189 self.lock()
190 }
191}
192
193impl<T: Default> Default for Lock<T> {
194 #[inline]
195 fn default() -> Self {
196 Lock::new(T::default())
197 }
198}
199
200impl<T: fmt::Debug> fmt::Debug for Lock<T> {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 match self.try_lock() {
203 Some(guard) => f.debug_struct("Lock").field("data", &&*guard).finish(),
204 None => {
205 struct LockedPlaceholder;
206 impl fmt::Debug for LockedPlaceholder {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 f.write_str("<locked>")
209 }
210 }
211
212 f.debug_struct("Lock").field("data", &LockedPlaceholder).finish()
213 }
214 }
215 }
216}