diff options
| author | bors <bors@rust-lang.org> | 2023-09-08 17:20:23 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-09-08 17:20:23 +0000 |
| commit | 26f4b7272428b181e0a88ad075e5c8f09dcb0e5c (patch) | |
| tree | 414474d281b3ea7204927e0d2ecce11c9e268e22 /compiler/rustc_data_structures/src | |
| parent | 3cd97ed3c3efe11bf6b63d23dce2515238b78a57 (diff) | |
| parent | c83eba92518166b9e40f43b40683d74c919af0ed (diff) | |
| download | rust-26f4b7272428b181e0a88ad075e5c8f09dcb0e5c.tar.gz rust-26f4b7272428b181e0a88ad075e5c8f09dcb0e5c.zip | |
Auto merge of #115418 - Zoxc:freeze-source, r=oli-obk
Use `Freeze` for `SourceFile` This uses the `Freeze` type in `SourceFile` to let accessing `external_src` and `lines` be lock-free. Behavior of `add_external_src` is changed to set `ExternalSourceKind::AbsentErr` on a hash mismatch which matches the documentation. `ExternalSourceKind::Unneeded` was removed as it's unused. Based on https://github.com/rust-lang/rust/pull/115401.
Diffstat (limited to 'compiler/rustc_data_structures/src')
| -rw-r--r-- | compiler/rustc_data_structures/src/sync/freeze.rs | 69 |
1 files changed, 66 insertions, 3 deletions
diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index d9f1d72d851..58ab91237f4 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -3,6 +3,7 @@ use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard}; use crate::sync::{DynSend, DynSync}; use std::{ cell::UnsafeCell, + intrinsics::likely, marker::PhantomData, ops::{Deref, DerefMut}, sync::atomic::Ordering, @@ -27,7 +28,47 @@ unsafe impl<T: DynSync + DynSend> DynSync for FreezeLock<T> {} impl<T> FreezeLock<T> { #[inline] pub fn new(value: T) -> Self { - Self { data: UnsafeCell::new(value), frozen: AtomicBool::new(false), lock: RwLock::new(()) } + Self::with(value, false) + } + + #[inline] + pub fn frozen(value: T) -> Self { + Self::with(value, true) + } + + #[inline] + pub fn with(value: T, frozen: bool) -> Self { + Self { + data: UnsafeCell::new(value), + frozen: AtomicBool::new(frozen), + lock: RwLock::new(()), + } + } + + /// Clones the inner value along with the frozen state. + #[inline] + pub fn clone(&self) -> Self + where + T: Clone, + { + let lock = self.read(); + Self::with(lock.clone(), self.is_frozen()) + } + + #[inline] + pub fn is_frozen(&self) -> bool { + self.frozen.load(Ordering::Acquire) + } + + /// Get the inner value if frozen. + #[inline] + pub fn get(&self) -> Option<&T> { + if likely(self.frozen.load(Ordering::Acquire)) { + // SAFETY: This is frozen so the data cannot be modified. + unsafe { Some(&*self.data.get()) } + } else { + None + } } #[inline] @@ -43,12 +84,25 @@ impl<T> FreezeLock<T> { } #[inline] + pub fn borrow(&self) -> FreezeReadGuard<'_, T> { + self.read() + } + + #[inline] #[track_caller] pub fn write(&self) -> FreezeWriteGuard<'_, T> { + self.try_write().expect("still mutable") + } + + #[inline] + pub fn try_write(&self) -> Option<FreezeWriteGuard<'_, T>> { let _lock_guard = self.lock.write(); // Use relaxed ordering since we're in the write lock. - assert!(!self.frozen.load(Ordering::Relaxed), "still mutable"); - FreezeWriteGuard { _lock_guard, lock: self, marker: PhantomData } + if self.frozen.load(Ordering::Relaxed) { + None + } else { + Some(FreezeWriteGuard { _lock_guard, lock: self, marker: PhantomData }) + } } #[inline] @@ -90,6 +144,15 @@ pub struct FreezeWriteGuard<'a, T> { marker: PhantomData<&'a mut T>, } +impl<'a, T> FreezeWriteGuard<'a, T> { + pub fn freeze(self) -> &'a T { + self.lock.frozen.store(true, Ordering::Release); + + // SAFETY: This is frozen so the data cannot be modified and shared access is sound. + unsafe { &*self.lock.data.get() } + } +} + impl<'a, T: 'a> Deref for FreezeWriteGuard<'a, T> { type Target = T; #[inline] |
