// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true. //! //! `Lrc` is an alias of either Rc or Arc. //! //! `Lock` is a mutex. //! It internally uses `parking_lot::Mutex` if cfg!(parallel_queries) is true, //! `RefCell` otherwise. //! //! `RwLock` is a read-write lock. //! It internally uses `parking_lot::RwLock` if cfg!(parallel_queries) is true, //! `RefCell` otherwise. //! //! `LockCell` is a thread safe version of `Cell`, with `set` and `get` operations. //! It can never deadlock. It uses `Cell` when //! cfg!(parallel_queries) is false, otherwise it is a `Lock`. //! //! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false. //! //! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync //! depending on the value of cfg!(parallel_queries). use std::collections::HashMap; use std::hash::{Hash, BuildHasher}; use std::cmp::Ordering; use std::marker::PhantomData; use std::fmt::Debug; use std::fmt::Formatter; use std::fmt; use std; use std::ops::{Deref, DerefMut}; use owning_ref::{Erased, OwningRef}; cfg_if! { if #[cfg(not(parallel_queries))] { pub auto trait Send {} pub auto trait Sync {} impl Send for T {} impl Sync for T {} #[macro_export] macro_rules! rustc_erase_owner { ($v:expr) => { $v.erase_owner() } } pub type MetadataRef = OwningRef, [u8]>; pub use std::rc::Rc as Lrc; pub use std::cell::Ref as ReadGuard; pub use std::cell::RefMut as WriteGuard; pub use std::cell::RefMut as LockGuard; use std::cell::RefCell as InnerRwLock; use std::cell::RefCell as InnerLock; use std::cell::Cell; #[derive(Debug)] pub struct MTLock(T); impl MTLock { #[inline(always)] pub fn new(inner: T) -> Self { MTLock(inner) } #[inline(always)] pub fn into_inner(self) -> T { self.0 } #[inline(always)] pub fn get_mut(&mut self) -> &mut T { &mut self.0 } #[inline(always)] pub fn lock(&self) -> &T { &self.0 } #[inline(always)] pub fn borrow(&self) -> &T { &self.0 } #[inline(always)] pub fn borrow_mut(&self) -> &T { &self.0 } } // FIXME: Probably a bad idea (in the threaded case) impl Clone for MTLock { #[inline] fn clone(&self) -> Self { MTLock(self.0.clone()) } } pub struct LockCell(Cell); impl LockCell { #[inline(always)] pub fn new(inner: T) -> Self { LockCell(Cell::new(inner)) } #[inline(always)] pub fn into_inner(self) -> T { self.0.into_inner() } #[inline(always)] pub fn set(&self, new_inner: T) { self.0.set(new_inner); } #[inline(always)] pub fn get(&self) -> T where T: Copy { self.0.get() } #[inline(always)] pub fn set_mut(&mut self, new_inner: T) { self.0.set(new_inner); } #[inline(always)] pub fn get_mut(&mut self) -> T where T: Copy { self.0.get() } } impl LockCell> { #[inline(always)] pub fn take(&self) -> Option { unsafe { (*self.0.as_ptr()).take() } } } } else { pub use std::marker::Send as Send; pub use std::marker::Sync as Sync; pub use parking_lot::RwLockReadGuard as ReadGuard; pub use parking_lot::RwLockWriteGuard as WriteGuard; pub use parking_lot::MutexGuard as LockGuard; pub use std::sync::Arc as Lrc; pub use self::Lock as MTLock; use parking_lot::Mutex as InnerLock; use parking_lot::RwLock as InnerRwLock; use std::thread; pub type MetadataRef = OwningRef, [u8]>; /// 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; #[macro_export] macro_rules! rustc_erase_owner { ($v:expr) => {{ let v = $v; ::rustc_data_structures::sync::assert_send_val(&v); v.erase_send_sync_owner() }} } pub struct LockCell(Lock); impl LockCell { #[inline(always)] pub fn new(inner: T) -> Self { LockCell(Lock::new(inner)) } #[inline(always)] pub fn into_inner(self) -> T { self.0.into_inner() } #[inline(always)] pub fn set(&self, new_inner: T) { *self.0.lock() = new_inner; } #[inline(always)] pub fn get(&self) -> T where T: Copy { *self.0.lock() } #[inline(always)] pub fn set_mut(&mut self, new_inner: T) { *self.0.get_mut() = new_inner; } #[inline(always)] pub fn get_mut(&mut self) -> T where T: Copy { *self.0.get_mut() } } impl LockCell> { #[inline(always)] pub fn take(&self) -> Option { self.0.lock().take() } } } } pub fn assert_sync() {} pub fn assert_send_val(_t: &T) {} pub fn assert_send_sync_val(_t: &T) {} pub trait HashMapExt { /// Same as HashMap::insert, but it may panic if there's already an /// entry for `key` with a value not equal to `value` fn insert_same(&mut self, key: K, value: V); } impl HashMapExt for HashMap { fn insert_same(&mut self, key: K, value: V) { self.entry(key).and_modify(|old| assert!(*old == value)).or_insert(value); } } /// A type whose inner value can be written once and then will stay read-only // This contains a PhantomData since this type conceptually owns a T outside the Mutex once // initialized. This ensures that Once is Sync only if T is. If we did not have PhantomData // we could send a &Once> to multiple threads and call `get` on it to get access // to &Cell on those threads. pub struct Once(Lock>, PhantomData); impl Once { /// Creates an Once value which is uninitialized #[inline(always)] pub fn new() -> Self { Once(Lock::new(None), PhantomData) } /// Consumes the value and returns Some(T) if it was initialized #[inline(always)] pub fn into_inner(self) -> Option { self.0.into_inner() } /// Tries to initialize the inner value to `value`. /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it /// otherwise if the inner value was already set it returns `value` back to the caller #[inline] pub fn try_set(&self, value: T) -> Option { let mut lock = self.0.lock(); if lock.is_some() { return Some(value); } *lock = Some(value); None } /// Tries to initialize the inner value to `value`. /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it /// otherwise if the inner value was already set it asserts that `value` is equal to the inner /// value and then returns `value` back to the caller #[inline] pub fn try_set_same(&self, value: T) -> Option where T: Eq { let mut lock = self.0.lock(); if let Some(ref inner) = *lock { assert!(*inner == value); return Some(value); } *lock = Some(value); None } /// Tries to initialize the inner value to `value` and panics if it was already initialized #[inline] pub fn set(&self, value: T) { assert!(self.try_set(value).is_none()); } /// Tries to initialize the inner value by calling the closure while ensuring that no-one else /// can access the value in the mean time by holding a lock for the duration of the closure. /// If the value was already initialized the closure is not called and `false` is returned, /// otherwise if the value from the closure initializes the inner value, `true` is returned #[inline] pub fn init_locking T>(&self, f: F) -> bool { let mut lock = self.0.lock(); if lock.is_some() { return false; } *lock = Some(f()); true } /// Tries to initialize the inner value by calling the closure without ensuring that no-one /// else can access it. This mean when this is called from multiple threads, multiple /// closures may concurrently be computing a value which the inner value should take. /// Only one of these closures are used to actually initialize the value. /// If some other closure already set the value, /// we return the value our closure computed wrapped in a `Option`. /// If our closure set the value, `None` is returned. /// If the value is already initialized, the closure is not called and `None` is returned. #[inline] pub fn init_nonlocking T>(&self, f: F) -> Option { if self.0.lock().is_some() { None } else { self.try_set(f()) } } /// Tries to initialize the inner value by calling the closure without ensuring that no-one /// else can access it. This mean when this is called from multiple threads, multiple /// closures may concurrently be computing a value which the inner value should take. /// Only one of these closures are used to actually initialize the value. /// If some other closure already set the value, we assert that it our closure computed /// a value equal to the value aready set and then /// we return the value our closure computed wrapped in a `Option`. /// If our closure set the value, `None` is returned. /// If the value is already initialized, the closure is not called and `None` is returned. #[inline] pub fn init_nonlocking_same T>(&self, f: F) -> Option where T: Eq { if self.0.lock().is_some() { None } else { self.try_set_same(f()) } } /// Tries to get a reference to the inner value, returns `None` if it is not yet initialized #[inline(always)] pub fn try_get(&self) -> Option<&T> { let lock = &*self.0.lock(); if let Some(ref inner) = *lock { // This is safe since we won't mutate the inner value unsafe { Some(&*(inner as *const T)) } } else { None } } /// Gets reference to the inner value, panics if it is not yet initialized #[inline(always)] pub fn get(&self) -> &T { self.try_get().expect("value was not set") } /// Gets reference to the inner value, panics if it is not yet initialized #[inline(always)] pub fn borrow(&self) -> &T { self.get() } } impl Debug for LockCell { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("LockCell") .field("value", &self.get()) .finish() } } impl Default for LockCell { /// Creates a `LockCell`, with the `Default` value for T. #[inline] fn default() -> LockCell { LockCell::new(Default::default()) } } impl PartialEq for LockCell { #[inline] fn eq(&self, other: &LockCell) -> bool { self.get() == other.get() } } impl Eq for LockCell {} impl PartialOrd for LockCell { #[inline] fn partial_cmp(&self, other: &LockCell) -> Option { self.get().partial_cmp(&other.get()) } #[inline] fn lt(&self, other: &LockCell) -> bool { self.get() < other.get() } #[inline] fn le(&self, other: &LockCell) -> bool { self.get() <= other.get() } #[inline] fn gt(&self, other: &LockCell) -> bool { self.get() > other.get() } #[inline] fn ge(&self, other: &LockCell) -> bool { self.get() >= other.get() } } impl Ord for LockCell { #[inline] fn cmp(&self, other: &LockCell) -> Ordering { self.get().cmp(&other.get()) } } #[derive(Debug)] pub struct Lock(InnerLock); impl Lock { #[inline(always)] pub fn new(inner: T) -> Self { Lock(InnerLock::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() } #[cfg(parallel_queries)] #[inline(always)] pub fn lock(&self) -> LockGuard { if ERROR_CHECKING { self.0.try_lock().expect("lock was already held") } else { self.0.lock() } } #[cfg(not(parallel_queries))] #[inline(always)] pub fn lock(&self) -> LockGuard { self.0.borrow_mut() } #[inline(always)] pub fn with_lock R, R>(&self, f: F) -> R { f(&mut *self.lock()) } #[inline(always)] pub fn borrow(&self) -> LockGuard { self.lock() } #[inline(always)] pub fn borrow_mut(&self) -> LockGuard { self.lock() } } impl Default for Lock { #[inline] fn default() -> Self { Lock::new(T::default()) } } // FIXME: Probably a bad idea impl Clone for Lock { #[inline] fn clone(&self) -> Self { Lock::new(self.borrow().clone()) } } #[derive(Debug)] pub struct RwLock(InnerRwLock); impl RwLock { #[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() } #[cfg(not(parallel_queries))] #[inline(always)] pub fn read(&self) -> ReadGuard { self.0.borrow() } #[cfg(parallel_queries)] #[inline(always)] pub fn read(&self) -> ReadGuard { if ERROR_CHECKING { self.0.try_read().expect("lock was already held") } else { self.0.read() } } #[inline(always)] pub fn with_read_lock R, R>(&self, f: F) -> R { f(&*self.read()) } #[cfg(not(parallel_queries))] #[inline(always)] pub fn try_write(&self) -> Result, ()> { self.0.try_borrow_mut().map_err(|_| ()) } #[cfg(parallel_queries)] #[inline(always)] pub fn try_write(&self) -> Result, ()> { self.0.try_write().ok_or(()) } #[cfg(not(parallel_queries))] #[inline(always)] pub fn write(&self) -> WriteGuard { self.0.borrow_mut() } #[cfg(parallel_queries)] #[inline(always)] pub fn write(&self) -> WriteGuard { if ERROR_CHECKING { self.0.try_write().expect("lock was already held") } else { self.0.write() } } #[inline(always)] pub fn with_write_lock R, R>(&self, f: F) -> R { f(&mut *self.write()) } #[inline(always)] pub fn borrow(&self) -> ReadGuard { self.read() } #[inline(always)] pub fn borrow_mut(&self) -> WriteGuard { self.write() } } // FIXME: Probably a bad idea impl Clone for RwLock { #[inline] fn clone(&self) -> Self { RwLock::new(self.borrow().clone()) } } /// A type which only allows its inner value to be used in one thread. /// It will panic if it is used on multiple threads. #[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)] pub struct OneThread { #[cfg(parallel_queries)] thread: thread::ThreadId, inner: T, } unsafe impl std::marker::Sync for OneThread {} unsafe impl std::marker::Send for OneThread {} impl OneThread { #[inline(always)] fn check(&self) { #[cfg(parallel_queries)] assert_eq!(thread::current().id(), self.thread); } #[inline(always)] pub fn new(inner: T) -> Self { OneThread { #[cfg(parallel_queries)] thread: thread::current().id(), inner, } } #[inline(always)] pub fn into_inner(value: Self) -> T { value.check(); value.inner } } impl Deref for OneThread { type Target = T; fn deref(&self) -> &T { self.check(); &self.inner } } impl DerefMut for OneThread { fn deref_mut(&mut self) -> &mut T { self.check(); &mut self.inner } }