@@ -32,14 +32,15 @@ use crate::ty::{
3232} ;
3333use crate :: ty:: { GenericArg , GenericArgs , GenericArgsRef } ;
3434use rustc_ast:: { self as ast, attr} ;
35+ use rustc_data_structures:: defer;
3536use rustc_data_structures:: fingerprint:: Fingerprint ;
3637use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
3738use rustc_data_structures:: intern:: Interned ;
3839use rustc_data_structures:: profiling:: SelfProfilerRef ;
3940use rustc_data_structures:: sharded:: { IntoPointer , ShardedHashMap } ;
4041use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
4142use rustc_data_structures:: steal:: Steal ;
42- use rustc_data_structures:: sync:: { self , FreezeReadGuard , Lock , Lrc , WorkerLocal } ;
43+ use rustc_data_structures:: sync:: { self , FreezeReadGuard , Lock , Lrc , RwLock , WorkerLocal } ;
4344#[ cfg( parallel_compiler) ]
4445use rustc_data_structures:: sync:: { DynSend , DynSync } ;
4546use rustc_data_structures:: unord:: UnordSet ;
@@ -723,6 +724,8 @@ pub struct GlobalCtxt<'tcx> {
723724
724725 /// Stores memory for globals (statics/consts).
725726 pub ( crate ) alloc_map : Lock < interpret:: AllocMap < ' tcx > > ,
727+
728+ current_gcx : CurrentGcx ,
726729}
727730
728731impl < ' tcx > GlobalCtxt < ' tcx > {
@@ -733,6 +736,19 @@ impl<'tcx> GlobalCtxt<'tcx> {
733736 F : FnOnce ( TyCtxt < ' tcx > ) -> R ,
734737 {
735738 let icx = tls:: ImplicitCtxt :: new ( self ) ;
739+
740+ // Reset `current_gcx` to `None` when we exit.
741+ let _on_drop = defer ( move || {
742+ * self . current_gcx . value . write ( ) = None ;
743+ } ) ;
744+
745+ // Set this `GlobalCtxt` as the current one.
746+ {
747+ let mut guard = self . current_gcx . value . write ( ) ;
748+ assert ! ( guard. is_none( ) , "no `GlobalCtxt` is currently set" ) ;
749+ * guard = Some ( self as * const _ as * const ( ) ) ;
750+ }
751+
736752 tls:: enter_context ( & icx, || f ( icx. tcx ) )
737753 }
738754
@@ -741,6 +757,39 @@ impl<'tcx> GlobalCtxt<'tcx> {
741757 }
742758}
743759
760+ /// This is used to get a reference to a `GlobalCtxt` if one is available.
761+ ///
762+ /// This is needed to allow the deadlock handler access to `GlobalCtxt` to look for query cycles.
763+ /// It cannot use the `TLV` global because that's only guaranteed to be defined on the thread
764+ /// creating the `GlobalCtxt`. Other threads have access to the `TLV` only inside Rayon jobs, but
765+ /// the deadlock handler is not called inside such a job.
766+ #[ derive( Clone ) ]
767+ pub struct CurrentGcx {
768+ /// This stores a pointer to a `GlobalCtxt`. This is set to `Some` inside `GlobalCtxt::enter`
769+ /// and reset to `None` when that function returns or unwinds.
770+ value : Lrc < RwLock < Option < * const ( ) > > > ,
771+ }
772+
773+ #[ cfg( parallel_compiler) ]
774+ unsafe impl DynSend for CurrentGcx { }
775+ #[ cfg( parallel_compiler) ]
776+ unsafe impl DynSync for CurrentGcx { }
777+
778+ impl CurrentGcx {
779+ pub fn new ( ) -> Self {
780+ Self { value : Lrc :: new ( RwLock :: new ( None ) ) }
781+ }
782+
783+ pub fn access < R > ( & self , f : impl for < ' tcx > FnOnce ( & ' tcx GlobalCtxt < ' tcx > ) -> R ) -> R {
784+ let read_guard = self . value . read ( ) ;
785+ let gcx: * const GlobalCtxt < ' _ > = read_guard. unwrap ( ) as * const _ ;
786+ // SAFETY: We hold the read lock for the `GlobalCtxt` pointer. That prevents
787+ // `GlobalCtxt::enter` from returning as it would first acquire the write lock.
788+ // This ensures the `GlobalCtxt` is live during `f`.
789+ f ( unsafe { & * gcx } )
790+ }
791+ }
792+
744793impl < ' tcx > TyCtxt < ' tcx > {
745794 /// Expects a body and returns its codegen attributes.
746795 ///
@@ -859,6 +908,7 @@ impl<'tcx> TyCtxt<'tcx> {
859908 query_kinds : & ' tcx [ DepKindStruct < ' tcx > ] ,
860909 query_system : QuerySystem < ' tcx > ,
861910 hooks : crate :: hooks:: Providers ,
911+ current_gcx : CurrentGcx ,
862912 ) -> GlobalCtxt < ' tcx > {
863913 let data_layout = s. target . parse_data_layout ( ) . unwrap_or_else ( |err| {
864914 s. dcx ( ) . emit_fatal ( err) ;
@@ -893,6 +943,7 @@ impl<'tcx> TyCtxt<'tcx> {
893943 canonical_param_env_cache : Default :: default ( ) ,
894944 data_layout,
895945 alloc_map : Lock :: new ( interpret:: AllocMap :: new ( ) ) ,
946+ current_gcx,
896947 }
897948 }
898949
0 commit comments