]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_data_structures/src/sync.rs
Rollup merge of #99928 - compiler-errors:issue-99914, r=oli-obk
[rust.git] / compiler / rustc_data_structures / src / sync.rs
1 //! This module defines types which are thread safe if cfg!(parallel_compiler) is true.
2 //!
3 //! `Lrc` is an alias of `Arc` if cfg!(parallel_compiler) is true, `Rc` otherwise.
4 //!
5 //! `Lock` is a mutex.
6 //! It internally uses `parking_lot::Mutex` if cfg!(parallel_compiler) is true,
7 //! `RefCell` otherwise.
8 //!
9 //! `RwLock` is a read-write lock.
10 //! It internally uses `parking_lot::RwLock` if cfg!(parallel_compiler) is true,
11 //! `RefCell` otherwise.
12 //!
13 //! `MTLock` is a mutex which disappears if cfg!(parallel_compiler) is false.
14 //!
15 //! `MTRef` is an immutable reference if cfg!(parallel_compiler), and a mutable reference otherwise.
16 //!
17 //! `rustc_erase_owner!` erases an OwningRef owner into Erased or Erased + Send + Sync
18 //! depending on the value of cfg!(parallel_compiler).
19
20 use crate::owning_ref::{Erased, OwningRef};
21 use std::collections::HashMap;
22 use std::hash::{BuildHasher, Hash};
23 use std::ops::{Deref, DerefMut};
24 use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
25
26 pub use std::sync::atomic::Ordering;
27 pub use std::sync::atomic::Ordering::SeqCst;
28
29 cfg_if! {
30     if #[cfg(not(parallel_compiler))] {
31         pub auto trait Send {}
32         pub auto trait Sync {}
33
34         impl<T: ?Sized> Send for T {}
35         impl<T: ?Sized> Sync for T {}
36
37         #[macro_export]
38         macro_rules! rustc_erase_owner {
39             ($v:expr) => {
40                 $v.erase_owner()
41             }
42         }
43
44         use std::ops::Add;
45
46         /// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc.
47         /// It has explicit ordering arguments and is only intended for use with
48         /// the native atomic types.
49         /// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases
50         /// as it's not intended to be used separately.
51         #[derive(Debug)]
52         pub struct Atomic<T: Copy>(Cell<T>);
53
54         impl<T: Copy> Atomic<T> {
55             #[inline]
56             pub fn new(v: T) -> Self {
57                 Atomic(Cell::new(v))
58             }
59
60             #[inline]
61             pub fn into_inner(self) -> T {
62                 self.0.into_inner()
63             }
64
65             #[inline]
66             pub fn load(&self, _: Ordering) -> T {
67                 self.0.get()
68             }
69
70             #[inline]
71             pub fn store(&self, val: T, _: Ordering) {
72                 self.0.set(val)
73             }
74
75             #[inline]
76             pub fn swap(&self, val: T, _: Ordering) -> T {
77                 self.0.replace(val)
78             }
79         }
80
81         impl<T: Copy + PartialEq> Atomic<T> {
82             #[inline]
83             pub fn compare_exchange(&self,
84                                     current: T,
85                                     new: T,
86                                     _: Ordering,
87                                     _: Ordering)
88                                     -> Result<T, T> {
89                 let read = self.0.get();
90                 if read == current {
91                     self.0.set(new);
92                     Ok(read)
93                 } else {
94                     Err(read)
95                 }
96             }
97         }
98
99         impl<T: Add<Output=T> + Copy> Atomic<T> {
100             #[inline]
101             pub fn fetch_add(&self, val: T, _: Ordering) -> T {
102                 let old = self.0.get();
103                 self.0.set(old + val);
104                 old
105             }
106         }
107
108         pub type AtomicUsize = Atomic<usize>;
109         pub type AtomicBool = Atomic<bool>;
110         pub type AtomicU32 = Atomic<u32>;
111         pub type AtomicU64 = Atomic<u64>;
112
113         pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
114             where A: FnOnce() -> RA,
115                   B: FnOnce() -> RB
116         {
117             (oper_a(), oper_b())
118         }
119
120         #[macro_export]
121         macro_rules! parallel {
122             ($($blocks:tt),*) => {
123                 // We catch panics here ensuring that all the blocks execute.
124                 // This makes behavior consistent with the parallel compiler.
125                 let mut panic = None;
126                 $(
127                     if let Err(p) = ::std::panic::catch_unwind(
128                         ::std::panic::AssertUnwindSafe(|| $blocks)
129                     ) {
130                         if panic.is_none() {
131                             panic = Some(p);
132                         }
133                     }
134                 )*
135                 if let Some(panic) = panic {
136                     ::std::panic::resume_unwind(panic);
137                 }
138             }
139         }
140
141         pub use std::iter::Iterator as ParallelIterator;
142
143         pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter {
144             t.into_iter()
145         }
146
147         pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) {
148             // We catch panics here ensuring that all the loop iterations execute.
149             // This makes behavior consistent with the parallel compiler.
150             let mut panic = None;
151             t.into_iter().for_each(|i| {
152                 if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) {
153                     if panic.is_none() {
154                         panic = Some(p);
155                     }
156                 }
157             });
158             if let Some(panic) = panic {
159                 resume_unwind(panic);
160             }
161         }
162
163         pub type MetadataRef = OwningRef<Box<dyn Erased>, [u8]>;
164
165         pub use std::rc::Rc as Lrc;
166         pub use std::rc::Weak as Weak;
167         pub use std::cell::Ref as ReadGuard;
168         pub use std::cell::Ref as MappedReadGuard;
169         pub use std::cell::RefMut as WriteGuard;
170         pub use std::cell::RefMut as MappedWriteGuard;
171         pub use std::cell::RefMut as LockGuard;
172         pub use std::cell::RefMut as MappedLockGuard;
173
174         pub use std::cell::OnceCell;
175
176         use std::cell::RefCell as InnerRwLock;
177         use std::cell::RefCell as InnerLock;
178
179         use std::cell::Cell;
180
181         #[derive(Debug)]
182         pub struct WorkerLocal<T>(OneThread<T>);
183
184         impl<T> WorkerLocal<T> {
185             /// Creates a new worker local where the `initial` closure computes the
186             /// value this worker local should take for each thread in the thread pool.
187             #[inline]
188             pub fn new<F: FnMut(usize) -> T>(mut f: F) -> WorkerLocal<T> {
189                 WorkerLocal(OneThread::new(f(0)))
190             }
191
192             /// Returns the worker-local value for each thread
193             #[inline]
194             pub fn into_inner(self) -> Vec<T> {
195                 vec![OneThread::into_inner(self.0)]
196             }
197         }
198
199         impl<T> Deref for WorkerLocal<T> {
200             type Target = T;
201
202             #[inline(always)]
203             fn deref(&self) -> &T {
204                 &*self.0
205             }
206         }
207
208         pub type MTRef<'a, T> = &'a mut T;
209
210         #[derive(Debug, Default)]
211         pub struct MTLock<T>(T);
212
213         impl<T> MTLock<T> {
214             #[inline(always)]
215             pub fn new(inner: T) -> Self {
216                 MTLock(inner)
217             }
218
219             #[inline(always)]
220             pub fn into_inner(self) -> T {
221                 self.0
222             }
223
224             #[inline(always)]
225             pub fn get_mut(&mut self) -> &mut T {
226                 &mut self.0
227             }
228
229             #[inline(always)]
230             pub fn lock(&self) -> &T {
231                 &self.0
232             }
233
234             #[inline(always)]
235             pub fn lock_mut(&mut self) -> &mut T {
236                 &mut self.0
237             }
238         }
239
240         // FIXME: Probably a bad idea (in the threaded case)
241         impl<T: Clone> Clone for MTLock<T> {
242             #[inline]
243             fn clone(&self) -> Self {
244                 MTLock(self.0.clone())
245             }
246         }
247     } else {
248         pub use std::marker::Send as Send;
249         pub use std::marker::Sync as Sync;
250
251         pub use parking_lot::RwLockReadGuard as ReadGuard;
252         pub use parking_lot::MappedRwLockReadGuard as MappedReadGuard;
253         pub use parking_lot::RwLockWriteGuard as WriteGuard;
254         pub use parking_lot::MappedRwLockWriteGuard as MappedWriteGuard;
255
256         pub use parking_lot::MutexGuard as LockGuard;
257         pub use parking_lot::MappedMutexGuard as MappedLockGuard;
258
259         pub use std::sync::OnceLock as OnceCell;
260
261         pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
262
263         pub use std::sync::Arc as Lrc;
264         pub use std::sync::Weak as Weak;
265
266         pub type MTRef<'a, T> = &'a T;
267
268         #[derive(Debug, Default)]
269         pub struct MTLock<T>(Lock<T>);
270
271         impl<T> MTLock<T> {
272             #[inline(always)]
273             pub fn new(inner: T) -> Self {
274                 MTLock(Lock::new(inner))
275             }
276
277             #[inline(always)]
278             pub fn into_inner(self) -> T {
279                 self.0.into_inner()
280             }
281
282             #[inline(always)]
283             pub fn get_mut(&mut self) -> &mut T {
284                 self.0.get_mut()
285             }
286
287             #[inline(always)]
288             pub fn lock(&self) -> LockGuard<'_, T> {
289                 self.0.lock()
290             }
291
292             #[inline(always)]
293             pub fn lock_mut(&self) -> LockGuard<'_, T> {
294                 self.lock()
295             }
296         }
297
298         use parking_lot::Mutex as InnerLock;
299         use parking_lot::RwLock as InnerRwLock;
300
301         use std::thread;
302         pub use rayon::{join, scope};
303
304         /// Runs a list of blocks in parallel. The first block is executed immediately on
305         /// the current thread. Use that for the longest running block.
306         #[macro_export]
307         macro_rules! parallel {
308             (impl $fblock:tt [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => {
309                 parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
310             };
311             (impl $fblock:tt [$($blocks:tt,)*] []) => {
312                 ::rustc_data_structures::sync::scope(|s| {
313                     $(
314                         s.spawn(|_| $blocks);
315                     )*
316                     $fblock;
317                 })
318             };
319             ($fblock:tt, $($blocks:tt),*) => {
320                 // Reverse the order of the later blocks since Rayon executes them in reverse order
321                 // when using a single thread. This ensures the execution order matches that
322                 // of a single threaded rustc
323                 parallel!(impl $fblock [] [$($blocks),*]);
324             };
325         }
326
327         pub use rayon_core::WorkerLocal;
328
329         pub use rayon::iter::ParallelIterator;
330         use rayon::iter::IntoParallelIterator;
331
332         pub fn par_iter<T: IntoParallelIterator>(t: T) -> T::Iter {
333             t.into_par_iter()
334         }
335
336         pub fn par_for_each_in<T: IntoParallelIterator>(
337             t: T,
338             for_each: impl Fn(T::Item) + Sync + Send,
339         ) {
340             let ps: Vec<_> = t.into_par_iter().map(|i| catch_unwind(AssertUnwindSafe(|| for_each(i)))).collect();
341             ps.into_iter().for_each(|p| if let Err(panic) = p {
342                 resume_unwind(panic)
343             });
344         }
345
346         pub type MetadataRef = OwningRef<Box<dyn Erased + Send + Sync>, [u8]>;
347
348         /// This makes locks panic if they are already held.
349         /// It is only useful when you are running in a single thread
350         const ERROR_CHECKING: bool = false;
351
352         #[macro_export]
353         macro_rules! rustc_erase_owner {
354             ($v:expr) => {{
355                 let v = $v;
356                 ::rustc_data_structures::sync::assert_send_val(&v);
357                 v.erase_send_sync_owner()
358             }}
359         }
360     }
361 }
362
363 pub fn assert_sync<T: ?Sized + Sync>() {}
364 pub fn assert_send<T: ?Sized + Send>() {}
365 pub fn assert_send_val<T: ?Sized + Send>(_t: &T) {}
366 pub fn assert_send_sync_val<T: ?Sized + Sync + Send>(_t: &T) {}
367
368 pub trait HashMapExt<K, V> {
369     /// Same as HashMap::insert, but it may panic if there's already an
370     /// entry for `key` with a value not equal to `value`
371     fn insert_same(&mut self, key: K, value: V);
372 }
373
374 impl<K: Eq + Hash, V: Eq, S: BuildHasher> HashMapExt<K, V> for HashMap<K, V, S> {
375     fn insert_same(&mut self, key: K, value: V) {
376         self.entry(key).and_modify(|old| assert!(*old == value)).or_insert(value);
377     }
378 }
379
380 #[derive(Debug)]
381 pub struct Lock<T>(InnerLock<T>);
382
383 impl<T> Lock<T> {
384     #[inline(always)]
385     pub fn new(inner: T) -> Self {
386         Lock(InnerLock::new(inner))
387     }
388
389     #[inline(always)]
390     pub fn into_inner(self) -> T {
391         self.0.into_inner()
392     }
393
394     #[inline(always)]
395     pub fn get_mut(&mut self) -> &mut T {
396         self.0.get_mut()
397     }
398
399     #[cfg(parallel_compiler)]
400     #[inline(always)]
401     pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
402         self.0.try_lock()
403     }
404
405     #[cfg(not(parallel_compiler))]
406     #[inline(always)]
407     pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
408         self.0.try_borrow_mut().ok()
409     }
410
411     #[cfg(parallel_compiler)]
412     #[inline(always)]
413     pub fn lock(&self) -> LockGuard<'_, T> {
414         if ERROR_CHECKING {
415             self.0.try_lock().expect("lock was already held")
416         } else {
417             self.0.lock()
418         }
419     }
420
421     #[cfg(not(parallel_compiler))]
422     #[inline(always)]
423     pub fn lock(&self) -> LockGuard<'_, T> {
424         self.0.borrow_mut()
425     }
426
427     #[inline(always)]
428     pub fn with_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
429         f(&mut *self.lock())
430     }
431
432     #[inline(always)]
433     pub fn borrow(&self) -> LockGuard<'_, T> {
434         self.lock()
435     }
436
437     #[inline(always)]
438     pub fn borrow_mut(&self) -> LockGuard<'_, T> {
439         self.lock()
440     }
441 }
442
443 impl<T: Default> Default for Lock<T> {
444     #[inline]
445     fn default() -> Self {
446         Lock::new(T::default())
447     }
448 }
449
450 // FIXME: Probably a bad idea
451 impl<T: Clone> Clone for Lock<T> {
452     #[inline]
453     fn clone(&self) -> Self {
454         Lock::new(self.borrow().clone())
455     }
456 }
457
458 #[derive(Debug, Default)]
459 pub struct RwLock<T>(InnerRwLock<T>);
460
461 impl<T> RwLock<T> {
462     #[inline(always)]
463     pub fn new(inner: T) -> Self {
464         RwLock(InnerRwLock::new(inner))
465     }
466
467     #[inline(always)]
468     pub fn into_inner(self) -> T {
469         self.0.into_inner()
470     }
471
472     #[inline(always)]
473     pub fn get_mut(&mut self) -> &mut T {
474         self.0.get_mut()
475     }
476
477     #[cfg(not(parallel_compiler))]
478     #[inline(always)]
479     pub fn read(&self) -> ReadGuard<'_, T> {
480         self.0.borrow()
481     }
482
483     #[cfg(parallel_compiler)]
484     #[inline(always)]
485     pub fn read(&self) -> ReadGuard<'_, T> {
486         if ERROR_CHECKING {
487             self.0.try_read().expect("lock was already held")
488         } else {
489             self.0.read()
490         }
491     }
492
493     #[inline(always)]
494     pub fn with_read_lock<F: FnOnce(&T) -> R, R>(&self, f: F) -> R {
495         f(&*self.read())
496     }
497
498     #[cfg(not(parallel_compiler))]
499     #[inline(always)]
500     pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
501         self.0.try_borrow_mut().map_err(|_| ())
502     }
503
504     #[cfg(parallel_compiler)]
505     #[inline(always)]
506     pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
507         self.0.try_write().ok_or(())
508     }
509
510     #[cfg(not(parallel_compiler))]
511     #[inline(always)]
512     pub fn write(&self) -> WriteGuard<'_, T> {
513         self.0.borrow_mut()
514     }
515
516     #[cfg(parallel_compiler)]
517     #[inline(always)]
518     pub fn write(&self) -> WriteGuard<'_, T> {
519         if ERROR_CHECKING {
520             self.0.try_write().expect("lock was already held")
521         } else {
522             self.0.write()
523         }
524     }
525
526     #[inline(always)]
527     pub fn with_write_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
528         f(&mut *self.write())
529     }
530
531     #[inline(always)]
532     pub fn borrow(&self) -> ReadGuard<'_, T> {
533         self.read()
534     }
535
536     #[inline(always)]
537     pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
538         self.write()
539     }
540
541     #[cfg(not(parallel_compiler))]
542     #[inline(always)]
543     pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> {
544         ReadGuard::clone(rg)
545     }
546
547     #[cfg(parallel_compiler)]
548     #[inline(always)]
549     pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> {
550         ReadGuard::rwlock(&rg).read()
551     }
552
553     #[cfg(not(parallel_compiler))]
554     #[inline(always)]
555     pub fn leak(&self) -> &T {
556         ReadGuard::leak(self.read())
557     }
558
559     #[cfg(parallel_compiler)]
560     #[inline(always)]
561     pub fn leak(&self) -> &T {
562         let guard = self.read();
563         let ret = unsafe { &*(&*guard as *const T) };
564         std::mem::forget(guard);
565         ret
566     }
567 }
568
569 // FIXME: Probably a bad idea
570 impl<T: Clone> Clone for RwLock<T> {
571     #[inline]
572     fn clone(&self) -> Self {
573         RwLock::new(self.borrow().clone())
574     }
575 }
576
577 /// A type which only allows its inner value to be used in one thread.
578 /// It will panic if it is used on multiple threads.
579 #[derive(Debug)]
580 pub struct OneThread<T> {
581     #[cfg(parallel_compiler)]
582     thread: thread::ThreadId,
583     inner: T,
584 }
585
586 #[cfg(parallel_compiler)]
587 unsafe impl<T> std::marker::Sync for OneThread<T> {}
588 #[cfg(parallel_compiler)]
589 unsafe impl<T> std::marker::Send for OneThread<T> {}
590
591 impl<T> OneThread<T> {
592     #[inline(always)]
593     fn check(&self) {
594         #[cfg(parallel_compiler)]
595         assert_eq!(thread::current().id(), self.thread);
596     }
597
598     #[inline(always)]
599     pub fn new(inner: T) -> Self {
600         OneThread {
601             #[cfg(parallel_compiler)]
602             thread: thread::current().id(),
603             inner,
604         }
605     }
606
607     #[inline(always)]
608     pub fn into_inner(value: Self) -> T {
609         value.check();
610         value.inner
611     }
612 }
613
614 impl<T> Deref for OneThread<T> {
615     type Target = T;
616
617     fn deref(&self) -> &T {
618         self.check();
619         &self.inner
620     }
621 }
622
623 impl<T> DerefMut for OneThread<T> {
624     fn deref_mut(&mut self) -> &mut T {
625         self.check();
626         &mut self.inner
627     }
628 }