@@ -32,14 +32,17 @@ 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+ #[ cfg( parallel_compiler) ]
44+ use rustc_data_structures:: sync:: DynSend ;
45+ use rustc_data_structures:: sync:: { self , FreezeReadGuard , Lock , Lrc , RwLock , WorkerLocal } ;
4346use rustc_data_structures:: unord:: UnordSet ;
4447use rustc_errors:: {
4548 DecorateLint , DiagnosticBuilder , DiagnosticMessage , ErrorGuaranteed , MultiSpan ,
@@ -585,6 +588,8 @@ pub struct GlobalCtxt<'tcx> {
585588
586589 /// Stores memory for globals (statics/consts).
587590 pub ( crate ) alloc_map : Lock < interpret:: AllocMap < ' tcx > > ,
591+
592+ current_gcx : CurrentGcx ,
588593}
589594
590595impl < ' tcx > GlobalCtxt < ' tcx > {
@@ -595,10 +600,60 @@ impl<'tcx> GlobalCtxt<'tcx> {
595600 F : FnOnce ( TyCtxt < ' tcx > ) -> R ,
596601 {
597602 let icx = tls:: ImplicitCtxt :: new ( self ) ;
603+
604+ let gcx_ptr =
605+ GcxPtr { value : Lrc :: new ( RwLock :: new ( Some ( icx. tcx . gcx as * const _ as * const ( ) ) ) ) } ;
606+
607+ // Reset `gcx_ptr` to `None` when we exit.
608+ let gcx_ptr_ = gcx_ptr. clone ( ) ;
609+ let _on_drop = defer ( move || {
610+ * gcx_ptr_. value . write ( ) = None ;
611+ } ) ;
612+
613+ // Set this `GlobalCtxt` as the current one.
614+ * self . current_gcx . value . lock ( ) = Some ( gcx_ptr) ;
615+
598616 tls:: enter_context ( & icx, || f ( icx. tcx ) )
599617 }
600618}
601619
620+ /// This stores a pointer to a `GlobalCtxt`. When the `GlobalCtxt` is no longer available the lock
621+ /// will be set to `None`.
622+ #[ derive( Clone ) ]
623+ struct GcxPtr {
624+ value : Lrc < RwLock < Option < * const ( ) > > > ,
625+ }
626+
627+ #[ cfg( parallel_compiler) ]
628+ unsafe impl DynSend for GcxPtr { }
629+
630+ /// This is used to get a reference to a `GlobalCtxt` if one is available.
631+ ///
632+ /// This is needed to allow the deadlock handler access to `GlobalCtxt` to look for query cycles.
633+ /// It cannot use the `TLV` global because that's only guaranteed to be defined on the thread
634+ /// creating the `GlobalCtxt`. Other threads have access to the `TLV` only inside Rayon jobs, but
635+ /// the deadlock handler is not called inside such a job.
636+ #[ derive( Clone ) ]
637+ pub struct CurrentGcx {
638+ value : Lrc < Lock < Option < GcxPtr > > > ,
639+ }
640+
641+ impl CurrentGcx {
642+ pub fn new ( ) -> Self {
643+ Self { value : Lrc :: new ( Lock :: new ( None ) ) }
644+ }
645+
646+ pub fn access < R > ( & self , f : impl for < ' tcx > FnOnce ( & ' tcx GlobalCtxt < ' tcx > ) -> R ) -> R {
647+ let gcx_ptr = self . value . lock ( ) . clone ( ) . unwrap ( ) ;
648+ let read_guard = gcx_ptr. value . read ( ) ;
649+ let gcx: * const GlobalCtxt < ' _ > = read_guard. unwrap ( ) as * const _ ;
650+ // SAFETY: We hold the read lock for `GcxPtr`. That prevents `GlobalCtxt::enter` from
651+ // returning as it would first acquire the write lock. This ensures the `GlobalCtxt` is
652+ // live during `f`.
653+ f ( unsafe { & * gcx } )
654+ }
655+ }
656+
602657impl < ' tcx > TyCtxt < ' tcx > {
603658 /// Expects a body and returns its codegen attributes.
604659 ///
@@ -708,6 +763,7 @@ impl<'tcx> TyCtxt<'tcx> {
708763 query_kinds : & ' tcx [ DepKindStruct < ' tcx > ] ,
709764 query_system : QuerySystem < ' tcx > ,
710765 hooks : crate :: hooks:: Providers ,
766+ current_gcx : CurrentGcx ,
711767 ) -> GlobalCtxt < ' tcx > {
712768 let data_layout = s. target . parse_data_layout ( ) . unwrap_or_else ( |err| {
713769 s. emit_fatal ( err) ;
@@ -742,6 +798,7 @@ impl<'tcx> TyCtxt<'tcx> {
742798 new_solver_coherence_evaluation_cache : Default :: default ( ) ,
743799 data_layout,
744800 alloc_map : Lock :: new ( interpret:: AllocMap :: new ( ) ) ,
801+ current_gcx,
745802 }
746803 }
747804
0 commit comments