@@ -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, require_complete, & mut job_map_out) ;
52- if res. is_none( ) {
53- complete = false ;
54- }
66+ gather_active_jobs( 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,59 +76,49 @@ 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 > (
6882 query : & ' tcx QueryVTable < ' tcx , C > ,
69- require_complete : bool ,
70- job_map_out : & mut QueryJobMap < ' tcx > , // Out-param; job info is gathered into this map
71- ) -> Option < ( ) >
72- where
83+ collect_kind : CollectActiveJobsKind ,
84+ job_map : & mut QueryJobMap < ' tcx > ,
85+ ) where
7386 C : QueryCache < Key : QueryKey + DynSend + DynSync > ,
7487 QueryVTable < ' tcx , C > : DynSync ,
7588{
76- let mut active = Vec :: new ( ) ;
77-
78- // Helper to gather active jobs from a single shard.
7989 let mut gather_shard_jobs = |shard : & HashTable < ( C :: Key , ActiveKeyStatus < ' tcx > ) > | {
80- for ( k, v) in shard. iter ( ) {
81- if let ActiveKeyStatus :: Started ( ref job) = * v {
82- active. push ( ( * k, job. clone ( ) ) ) ;
90+ for ( key, status) in shard. iter ( ) {
91+ if let ActiveKeyStatus :: Started ( job) = status {
92+ // This function is safe to call with the shard locked because it is very simple.
93+ let frame = crate :: plumbing:: create_query_stack_frame ( query, * key) ;
94+ job_map. insert ( job. id , QueryJobInfo { frame, job : job. clone ( ) } ) ;
8395 }
8496 }
8597 } ;
8698
87- // Lock shards and gather jobs from each shard.
88- if require_complete {
89- for shard in query. state . active . lock_shards ( ) {
90- gather_shard_jobs ( & shard) ;
99+ match collect_kind {
100+ CollectActiveJobsKind :: Full => {
101+ for shard in query. state . active . lock_shards ( ) {
102+ gather_shard_jobs ( & shard) ;
103+ }
91104 }
92- } else {
93- // We use try_lock_shards here since we are called from the
94- // deadlock handler, and this shouldn't be locked.
95- for shard in query. state . active . try_lock_shards ( ) {
96- // This can be called during unwinding, and the function has a `try_`-prefix, so
97- // don't `unwrap()` here, just manually check for `None` and do best-effort error
98- // reporting.
99- match shard {
100- None => {
101- tracing:: warn!(
102- "Failed to collect active jobs for query with name `{}`!" ,
103- query. name
104- ) ;
105- return None ;
105+ CollectActiveJobsKind :: FullNoContention => {
106+ for shard in query. state . active . try_lock_shards ( ) {
107+ match shard {
108+ Some ( shard) => gather_shard_jobs ( & shard) ,
109+ None => panic ! ( "Failed to collect active jobs for query `{}`!" , query. name) ,
110+ }
111+ }
112+ }
113+ CollectActiveJobsKind :: PartialAllowed => {
114+ for shard in query. state . active . try_lock_shards ( ) {
115+ match shard {
116+ Some ( shard) => gather_shard_jobs ( & shard) ,
117+ None => warn ! ( "Failed to collect active jobs for query `{}`!" , query. name) ,
106118 }
107- Some ( shard) => gather_shard_jobs ( & shard) ,
108119 }
109120 }
110121 }
111-
112- // Call `make_frame` while we're not holding a `state.active` lock as `make_frame` may call
113- // queries leading to a deadlock.
114- for ( key, job) in active {
115- let frame = crate :: plumbing:: create_query_stack_frame ( query, key) ;
116- job_map_out. insert ( job. id , QueryJobInfo { frame, job } ) ;
117- }
118-
119- Some ( ( ) )
120122}
121123
122124#[ cold]
@@ -223,11 +225,10 @@ fn cycle_error<'tcx, C: QueryCache>(
223225 try_execute : QueryJobId ,
224226 span : Span ,
225227) -> ( C :: Value , Option < DepNodeIndex > ) {
226- // Ensure there was no errors collecting all active jobs.
228+ // Ensure there were no errors collecting all active jobs.
227229 // We need the complete map to ensure we find a cycle to break.
228- let job_map = collect_active_jobs_from_all_queries ( tcx, false )
229- . ok ( )
230- . expect ( "failed to collect active queries" ) ;
230+ let job_map =
231+ collect_active_jobs_from_all_queries ( tcx, CollectActiveJobsKind :: FullNoContention ) ;
231232
232233 let error = find_cycle_in_stack ( try_execute, job_map, & current_query_job ( ) , span) ;
233234 ( mk_cycle ( query, tcx, key, error) , None )
0 commit comments