@@ -32,14 +32,17 @@ use crate::ty::{
32
32
} ;
33
33
use crate :: ty:: { GenericArg , GenericArgs , GenericArgsRef } ;
34
34
use rustc_ast:: { self as ast, attr} ;
35
+ use rustc_data_structures:: defer;
35
36
use rustc_data_structures:: fingerprint:: Fingerprint ;
36
37
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
37
38
use rustc_data_structures:: intern:: Interned ;
38
39
use rustc_data_structures:: profiling:: SelfProfilerRef ;
39
40
use rustc_data_structures:: sharded:: { IntoPointer , ShardedHashMap } ;
40
41
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
41
42
use 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 } ;
43
46
use rustc_data_structures:: unord:: UnordSet ;
44
47
use rustc_errors:: {
45
48
DecorateLint , DiagnosticBuilder , DiagnosticMessage , ErrorGuaranteed , MultiSpan ,
@@ -585,6 +588,8 @@ pub struct GlobalCtxt<'tcx> {
585
588
586
589
/// Stores memory for globals (statics/consts).
587
590
pub ( crate ) alloc_map : Lock < interpret:: AllocMap < ' tcx > > ,
591
+
592
+ current_gcx : CurrentGcx ,
588
593
}
589
594
590
595
impl < ' tcx > GlobalCtxt < ' tcx > {
@@ -595,10 +600,60 @@ impl<'tcx> GlobalCtxt<'tcx> {
595
600
F : FnOnce ( TyCtxt < ' tcx > ) -> R ,
596
601
{
597
602
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
+
598
616
tls:: enter_context ( & icx, || f ( icx. tcx ) )
599
617
}
600
618
}
601
619
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
+
602
657
impl < ' tcx > TyCtxt < ' tcx > {
603
658
/// Expects a body and returns its codegen attributes.
604
659
///
@@ -708,6 +763,7 @@ impl<'tcx> TyCtxt<'tcx> {
708
763
query_kinds : & ' tcx [ DepKindStruct < ' tcx > ] ,
709
764
query_system : QuerySystem < ' tcx > ,
710
765
hooks : crate :: hooks:: Providers ,
766
+ current_gcx : CurrentGcx ,
711
767
) -> GlobalCtxt < ' tcx > {
712
768
let data_layout = s. target . parse_data_layout ( ) . unwrap_or_else ( |err| {
713
769
s. emit_fatal ( err) ;
@@ -742,6 +798,7 @@ impl<'tcx> TyCtxt<'tcx> {
742
798
new_solver_coherence_evaluation_cache : Default :: default ( ) ,
743
799
data_layout,
744
800
alloc_map : Lock :: new ( interpret:: AllocMap :: new ( ) ) ,
801
+ current_gcx,
745
802
}
746
803
}
747
804
0 commit comments