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}