Skip to content

parallel: rustc_data_structures: sync: implement RwLock as enum { Sync(parking_lot::RwLock), NoSync(RefCell) } #136772

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 5 additions & 93 deletions compiler/rustc_data_structures/src/sync.rs
Original file line number Diff line number Diff line change
@@ -111,11 +111,7 @@ pub use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize};
pub use std::sync::{OnceLock, Weak};

pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
pub use parking_lot::{
MappedMutexGuard as MappedLockGuard, MappedRwLockReadGuard as MappedReadGuard,
MappedRwLockWriteGuard as MappedWriteGuard, RwLockReadGuard as ReadGuard,
RwLockWriteGuard as WriteGuard,
};
pub use parking_lot::MappedMutexGuard as MappedLockGuard;
#[cfg(not(target_has_atomic = "64"))]
pub use portable_atomic::AtomicU64;

@@ -151,12 +147,6 @@ impl<T> MTLock<T> {
}
}

use parking_lot::RwLock as InnerRwLock;

/// This makes locks panic if they are already held.
/// It is only useful when you are running in a single thread
const ERROR_CHECKING: bool = false;

pub type MTLockRef<'a, T> = LRef<'a, MTLock<T>>;

#[derive(Default)]
@@ -175,85 +165,7 @@ impl<K: Eq + Hash, V: Eq, S: BuildHasher> HashMapExt<K, V> for HashMap<K, V, S>
}
}

#[derive(Debug, Default)]
pub struct RwLock<T>(InnerRwLock<T>);

impl<T> RwLock<T> {
#[inline(always)]
pub fn new(inner: T) -> Self {
RwLock(InnerRwLock::new(inner))
}

#[inline(always)]
pub fn into_inner(self) -> T {
self.0.into_inner()
}

#[inline(always)]
pub fn get_mut(&mut self) -> &mut T {
self.0.get_mut()
}

#[inline(always)]
pub fn read(&self) -> ReadGuard<'_, T> {
if ERROR_CHECKING {
self.0.try_read().expect("lock was already held")
} else {
self.0.read()
}
}

#[inline(always)]
#[track_caller]
pub fn with_read_lock<F: FnOnce(&T) -> R, R>(&self, f: F) -> R {
f(&*self.read())
}

#[inline(always)]
pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
self.0.try_write().ok_or(())
}

#[inline(always)]
pub fn write(&self) -> WriteGuard<'_, T> {
if ERROR_CHECKING {
self.0.try_write().expect("lock was already held")
} else {
self.0.write()
}
}

#[inline(always)]
#[track_caller]
pub fn with_write_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
f(&mut *self.write())
}

#[inline(always)]
#[track_caller]
pub fn borrow(&self) -> ReadGuard<'_, T> {
self.read()
}

#[inline(always)]
#[track_caller]
pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
self.write()
}

#[inline(always)]
pub fn leak(&self) -> &T {
let guard = self.read();
let ret = unsafe { &*(&raw const *guard) };
std::mem::forget(guard);
ret
}
}

// FIXME: Probably a bad idea
impl<T: Clone> Clone for RwLock<T> {
#[inline]
fn clone(&self) -> Self {
RwLock::new(self.borrow().clone())
}
}
mod rwlock;
pub use rwlock::{
MappedReadGuard, MappedWriteGuard, ReadError, ReadGuard, RwLock, WriteError, WriteGuard,
};
312 changes: 312 additions & 0 deletions compiler/rustc_data_structures/src/sync/rwlock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
use std::cell::{Ref, RefCell, RefMut};
use std::intrinsics::cold_path;
use std::ops::{Deref, DerefMut};

use crate::sync::mode::might_be_dyn_thread_safe;

#[derive(Debug)]
pub enum RwLock<T> {
Sync(parking_lot::RwLock<T>),
NoSync(RefCell<T>),
}

#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
#[derive(Debug)]
pub enum ReadGuard<'a, T> {
Sync(parking_lot::RwLockReadGuard<'a, T>),
NoSync(Ref<'a, T>),
}

#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
#[derive(Debug)]
pub enum WriteGuard<'a, T> {
Sync(parking_lot::RwLockWriteGuard<'a, T>),
NoSync(RefMut<'a, T>),
}

#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
#[derive(Debug)]
pub enum MappedReadGuard<'a, T> {
Sync(parking_lot::MappedRwLockReadGuard<'a, T>),
NoSync(Ref<'a, T>),
}

#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
#[derive(Debug)]
pub enum MappedWriteGuard<'a, T> {
Sync(parking_lot::MappedRwLockWriteGuard<'a, T>),
NoSync(RefMut<'a, T>),
}

#[derive(Debug)]
pub struct ReadError;

#[derive(Debug)]
pub struct WriteError;

impl<T> RwLock<T> {
#[inline(always)]
pub fn new(inner: T) -> Self {
if might_be_dyn_thread_safe() {
cold_path();
RwLock::Sync(parking_lot::RwLock::new(inner))
} else {
RwLock::NoSync(RefCell::new(inner))
}
}

#[inline(always)]
pub fn into_inner(self) -> T {
match self {
RwLock::Sync(inner) => {
cold_path();
parking_lot::RwLock::into_inner(inner)
}
RwLock::NoSync(inner) => RefCell::into_inner(inner),
}
}

#[inline(always)]
pub fn get_mut(&mut self) -> &mut T {
match self {
RwLock::Sync(inner) => {
cold_path();
parking_lot::RwLock::get_mut(inner)
}
RwLock::NoSync(inner) => RefCell::get_mut(inner),
}
}

#[inline(always)]
#[track_caller]
pub fn read(&self) -> ReadGuard<'_, T> {
match self {
RwLock::Sync(inner) => {
cold_path();
ReadGuard::Sync(inner.read())
}
RwLock::NoSync(inner) => ReadGuard::NoSync(inner.borrow()),
}
}

#[inline(always)]
pub fn try_read(&self) -> Result<ReadGuard<'_, T>, ReadError> {
match self {
RwLock::Sync(inner) => {
cold_path();
Ok(ReadGuard::Sync(inner.try_read().ok_or(ReadError)?))
}
RwLock::NoSync(inner) => {
Ok(ReadGuard::NoSync(inner.try_borrow().map_err(|_| ReadError)?))
}
}
}

#[inline(always)]
#[track_caller]
pub fn write(&self) -> WriteGuard<'_, T> {
match self {
RwLock::Sync(inner) => {
cold_path();
WriteGuard::Sync(inner.write())
}
RwLock::NoSync(inner) => WriteGuard::NoSync(inner.borrow_mut()),
}
}

#[inline(always)]
pub fn try_write(&self) -> Result<WriteGuard<'_, T>, WriteError> {
match self {
RwLock::Sync(inner) => {
cold_path();
Ok(WriteGuard::Sync(inner.try_write().ok_or(WriteError)?))
}
RwLock::NoSync(inner) => {
Ok(WriteGuard::NoSync(inner.try_borrow_mut().map_err(|_| WriteError)?))
}
}
}

#[inline(always)]
#[track_caller]
pub fn borrow(&self) -> ReadGuard<'_, T> {
self.read()
}

#[inline(always)]
pub fn try_borrow(&self) -> Result<ReadGuard<'_, T>, ReadError> {
self.try_read()
}

#[inline(always)]
#[track_caller]
pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
self.write()
}

#[inline(always)]
pub fn try_borrow_mut(&self) -> Result<WriteGuard<'_, T>, WriteError> {
self.try_write()
}
}

impl<T: Default> Default for RwLock<T> {
#[inline(always)]
fn default() -> Self {
RwLock::<T>::new(Default::default())
}
}

impl<'a, T> ReadGuard<'a, T> {
#[inline(always)]
pub fn map<U, F>(s: Self, f: F) -> MappedReadGuard<'a, U>
where
F: FnOnce(&T) -> &U,
{
match s {
ReadGuard::Sync(guard) => {
cold_path();
MappedReadGuard::Sync(parking_lot::RwLockReadGuard::map(guard, f))
}
ReadGuard::NoSync(guard) => MappedReadGuard::NoSync(Ref::map(guard, f)),
}
}
}

impl<'a, T> WriteGuard<'a, T> {
#[inline(always)]
pub fn map<U, F>(s: Self, f: F) -> MappedWriteGuard<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
{
match s {
WriteGuard::Sync(guard) => {
cold_path();
MappedWriteGuard::Sync(parking_lot::RwLockWriteGuard::map(guard, f))
}
WriteGuard::NoSync(guard) => MappedWriteGuard::NoSync(RefMut::map(guard, f)),
}
}
}

impl<'a, T> Deref for ReadGuard<'a, T> {
type Target = T;

#[inline(always)]
fn deref(&self) -> &T {
match self {
ReadGuard::Sync(guard) => {
cold_path();
Deref::deref(guard)
}
ReadGuard::NoSync(guard) => Deref::deref(guard),
}
}
}

impl<'a, T> Deref for WriteGuard<'a, T> {
type Target = T;

#[inline(always)]
fn deref(&self) -> &T {
match self {
WriteGuard::Sync(guard) => {
cold_path();
Deref::deref(guard)
}
WriteGuard::NoSync(guard) => Deref::deref(guard),
}
}
}

impl<'a, T> DerefMut for WriteGuard<'a, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
match self {
WriteGuard::Sync(guard) => {
cold_path();
DerefMut::deref_mut(guard)
}
WriteGuard::NoSync(guard) => DerefMut::deref_mut(guard),
}
}
}

impl<'a, T> MappedReadGuard<'a, T> {
#[inline(always)]
pub fn map<U, F>(s: Self, f: F) -> MappedReadGuard<'a, U>
where
F: FnOnce(&T) -> &U,
{
match s {
MappedReadGuard::Sync(guard) => {
cold_path();
MappedReadGuard::Sync(parking_lot::MappedRwLockReadGuard::map(guard, f))
}
MappedReadGuard::NoSync(guard) => MappedReadGuard::NoSync(Ref::map(guard, f)),
}
}
}

impl<'a, T> MappedWriteGuard<'a, T> {
#[inline(always)]
pub fn map<U, F>(s: Self, f: F) -> MappedWriteGuard<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
{
match s {
MappedWriteGuard::Sync(guard) => {
cold_path();
MappedWriteGuard::Sync(parking_lot::MappedRwLockWriteGuard::map(guard, f))
}
MappedWriteGuard::NoSync(guard) => MappedWriteGuard::NoSync(RefMut::map(guard, f)),
}
}
}

impl<'a, T> Deref for MappedReadGuard<'a, T> {
type Target = T;

#[inline(always)]
fn deref(&self) -> &T {
match self {
MappedReadGuard::Sync(guard) => {
cold_path();
Deref::deref(guard)
}
MappedReadGuard::NoSync(guard) => Deref::deref(guard),
}
}
}

impl<'a, T> Deref for MappedWriteGuard<'a, T> {
type Target = T;

#[inline(always)]
fn deref(&self) -> &T {
match self {
MappedWriteGuard::Sync(guard) => {
cold_path();
Deref::deref(guard)
}
MappedWriteGuard::NoSync(guard) => Deref::deref(guard),
}
}
}

impl<'a, T> DerefMut for MappedWriteGuard<'a, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
match self {
MappedWriteGuard::Sync(guard) => {
cold_path();
DerefMut::deref_mut(guard)
}
MappedWriteGuard::NoSync(guard) => DerefMut::deref_mut(guard),
}
}
}
4 changes: 3 additions & 1 deletion compiler/rustc_data_structures/src/sync/vec.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@ use std::marker::PhantomData;

use rustc_index::Idx;

use crate::sync::RwLock;

#[derive(Default)]
pub struct AppendOnlyIndexVec<I: Idx, T: Copy> {
vec: elsa::sync::LockFreeFrozenVec<T>,
@@ -26,7 +28,7 @@ impl<I: Idx, T: Copy> AppendOnlyIndexVec<I, T> {

#[derive(Default)]
pub struct AppendOnlyVec<T: Copy> {
vec: parking_lot::RwLock<Vec<T>>,
vec: RwLock<Vec<T>>,
}

impl<T: Copy> AppendOnlyVec<T> {