@@ -15,6 +15,7 @@ use rustc_middle::query::{
1515use rustc_middle:: ty:: TyCtxt ;
1616use rustc_middle:: verify_ich:: incremental_verify_ich;
1717use rustc_span:: { DUMMY_SP , Span } ;
18+ use tracing:: warn;
1819
1920use crate :: dep_graph:: { DepNode , DepNodeIndex } ;
2021use crate :: for_each_query_vtable;
@@ -30,6 +31,21 @@ pub(crate) fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool {
3031 state. active . lock_shards ( ) . all ( |shard| shard. is_empty ( ) )
3132}
3233
34+ #[ derive( Clone , Copy ) ]
35+ pub enum CollectActiveJobsKind {
36+ /// We need the full query job map, and we are willing to wait to obtain the query state
37+ /// shard lock(s).
38+ Full ,
39+
40+ /// We need the full query job map, and we shouldn't need to wait to obtain the shard lock(s),
41+ /// because we are in a place where nothing else could hold the shard lock(s).
42+ FullNoContention ,
43+
44+ /// We can get by without the full query job map, so we won't bother waiting to obtain the
45+ /// shard lock(s) if they're not already unlocked.
46+ PartialAllowed ,
47+ }
48+
3349/// Returns a map of currently active query jobs, collected from all queries.
3450///
3551/// If `require_complete` is `true`, this function locks all shards of the
@@ -42,19 +58,15 @@ pub(crate) fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool {
4258/// complete map is needed and no deadlock is possible at this call site.
4359pub fn collect_active_jobs_from_all_queries < ' tcx > (
4460 tcx : TyCtxt < ' tcx > ,
45- require_complete : bool ,
46- ) -> Result < QueryJobMap < ' tcx > , QueryJobMap < ' tcx > > {
47- let mut job_map_out = QueryJobMap :: default ( ) ;
48- let mut complete = true ;
61+ collect_kind : CollectActiveJobsKind ,
62+ ) -> QueryJobMap < ' tcx > {
63+ let mut job_map = QueryJobMap :: default ( ) ;
4964
5065 for_each_query_vtable ! ( ALL , tcx, |query| {
51- let res = gather_active_jobs( query, tcx, require_complete, & mut job_map_out) ;
52- if res. is_none( ) {
53- complete = false ;
54- }
66+ gather_active_jobs( tcx, query, collect_kind, & mut job_map) ;
5567 } ) ;
5668
57- if complete { Ok ( job_map_out ) } else { Err ( job_map_out ) }
69+ job_map
5870}
5971
6072/// Internal plumbing for collecting the set of active jobs for this query.
@@ -64,60 +76,50 @@ pub fn collect_active_jobs_from_all_queries<'tcx>(
6476/// (We arbitrarily use the word "gather" when collecting the jobs for
6577/// each individual query, so that we have distinct function names to
6678/// grep for.)
79+ ///
80+ /// Aborts if jobs can't be gathered as specified by `collect_kind`.
6781fn gather_active_jobs < ' tcx , C > (
68- query : & ' tcx QueryVTable < ' tcx , C > ,
6982 tcx : TyCtxt < ' tcx > ,
70- require_complete : bool ,
71- job_map_out : & mut QueryJobMap < ' tcx > , // Out-param; job info is gathered into this map
72- ) -> Option < ( ) >
73- where
83+ query : & ' tcx QueryVTable < ' tcx , C > ,
84+ collect_kind : CollectActiveJobsKind ,
85+ job_map : & mut QueryJobMap < ' tcx > ,
86+ ) where
7487 C : QueryCache < Key : QueryKey + DynSend + DynSync > ,
7588 QueryVTable < ' tcx , C > : DynSync ,
7689{
77- let mut active = Vec :: new ( ) ;
78-
79- // Helper to gather active jobs from a single shard.
8090 let mut gather_shard_jobs = |shard : & HashTable < ( C :: Key , ActiveKeyStatus < ' tcx > ) > | {
81- for ( k, v) in shard. iter ( ) {
82- if let ActiveKeyStatus :: Started ( ref job) = * v {
83- active. push ( ( * k, job. clone ( ) ) ) ;
91+ for ( key, status) in shard. iter ( ) {
92+ if let ActiveKeyStatus :: Started ( job) = status {
93+ // This function is safe to call with the shard locked because it is very simple.
94+ let frame = crate :: plumbing:: create_deferred_query_stack_frame ( tcx, query, * key) ;
95+ job_map. insert ( job. id , QueryJobInfo { frame, job : job. clone ( ) } ) ;
8496 }
8597 }
8698 } ;
8799
88- // Lock shards and gather jobs from each shard.
89- if require_complete {
90- for shard in query. state . active . lock_shards ( ) {
91- gather_shard_jobs ( & shard) ;
100+ match collect_kind {
101+ CollectActiveJobsKind :: Full => {
102+ for shard in query. state . active . lock_shards ( ) {
103+ gather_shard_jobs ( & shard) ;
104+ }
92105 }
93- } else {
94- // We use try_lock_shards here since we are called from the
95- // deadlock handler, and this shouldn't be locked.
96- for shard in query. state . active . try_lock_shards ( ) {
97- // This can be called during unwinding, and the function has a `try_`-prefix, so
98- // don't `unwrap()` here, just manually check for `None` and do best-effort error
99- // reporting.
100- match shard {
101- None => {
102- tracing:: warn!(
103- "Failed to collect active jobs for query with name `{}`!" ,
104- query. name
105- ) ;
106- return None ;
106+ CollectActiveJobsKind :: FullNoContention => {
107+ for shard in query. state . active . try_lock_shards ( ) {
108+ match shard {
109+ Some ( shard) => gather_shard_jobs ( & shard) ,
110+ None => panic ! ( "Failed to collect active jobs for query `{}`!" , query. name) ,
111+ }
112+ }
113+ }
114+ CollectActiveJobsKind :: PartialAllowed => {
115+ for shard in query. state . active . try_lock_shards ( ) {
116+ match shard {
117+ Some ( shard) => gather_shard_jobs ( & shard) ,
118+ None => warn ! ( "Failed to collect active jobs for query `{}`!" , query. name) ,
107119 }
108- Some ( shard) => gather_shard_jobs ( & shard) ,
109120 }
110121 }
111122 }
112-
113- // Call `make_frame` while we're not holding a `state.active` lock as `make_frame` may call
114- // queries leading to a deadlock.
115- for ( key, job) in active {
116- let frame = crate :: plumbing:: create_deferred_query_stack_frame ( tcx, query, key) ;
117- job_map_out. insert ( job. id , QueryJobInfo { frame, job } ) ;
118- }
119-
120- Some ( ( ) )
121123}
122124
123125#[ cold]
@@ -222,11 +224,10 @@ fn cycle_error<'tcx, C: QueryCache>(
222224 try_execute : QueryJobId ,
223225 span : Span ,
224226) -> ( C :: Value , Option < DepNodeIndex > ) {
225- // Ensure there was no errors collecting all active jobs.
227+ // Ensure there were no errors collecting all active jobs.
226228 // We need the complete map to ensure we find a cycle to break.
227- let job_map = collect_active_jobs_from_all_queries ( tcx, false )
228- . ok ( )
229- . expect ( "failed to collect active queries" ) ;
229+ let job_map =
230+ collect_active_jobs_from_all_queries ( tcx, CollectActiveJobsKind :: FullNoContention ) ;
230231
231232 let error = find_cycle_in_stack ( try_execute, job_map, & current_query_job ( ) , span) ;
232233 ( mk_cycle ( query, tcx, error. lift ( ) ) , None )
0 commit comments