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