@@ -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 :: collect_active_jobs_from_all_queries;
2021use crate :: dep_graph:: { DepNode , DepNodeIndex } ;
@@ -30,67 +31,72 @@ 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 hole 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/// Internal plumbing for collecting the set of active jobs for this query.
3450///
3551/// Should only be called from `collect_active_jobs_from_all_queries`.
3652///
3753/// (We arbitrarily use the word "gather" when collecting the jobs for
3854/// each individual query, so that we have distinct function names to
3955/// grep for.)
56+ ///
57+ /// Aborts if jobs can't be gathered as specified by `collect_kind`.
4058pub ( crate ) fn gather_active_jobs < ' tcx , C > (
41- query : & ' tcx QueryVTable < ' tcx , C > ,
4259 tcx : TyCtxt < ' tcx > ,
43- require_complete : bool ,
44- job_map_out : & mut QueryJobMap < ' tcx > , // Out-param; job info is gathered into this map
45- ) -> Option < ( ) >
46- where
60+ query : & ' tcx QueryVTable < ' tcx , C > ,
61+ collect_kind : CollectActiveJobsKind ,
62+ job_map : & mut QueryJobMap < ' tcx > ,
63+ ) where
4764 C : QueryCache < Key : QueryKey + DynSend + DynSync > ,
4865 QueryVTable < ' tcx , C > : DynSync ,
4966{
50- let mut active = Vec :: new ( ) ;
51-
52- // Helper to gather active jobs from a single shard.
5367 let mut gather_shard_jobs = |shard : & HashTable < ( C :: Key , ActiveKeyStatus < ' tcx > ) > | {
54- for ( k, v) in shard. iter ( ) {
55- if let ActiveKeyStatus :: Started ( ref job) = * v {
56- active. push ( ( * k, job. clone ( ) ) ) ;
68+ for ( key, status) in shard. iter ( ) {
69+ if let ActiveKeyStatus :: Started ( job) = status {
70+ // This function is safe to call with the shard locked because it is very simple.
71+ let frame = crate :: plumbing:: create_deferred_query_stack_frame ( tcx, query, * key) ;
72+ job_map. insert ( job. id , QueryJobInfo { frame, job : job. clone ( ) } ) ;
5773 }
5874 }
5975 } ;
6076
61- // Lock shards and gather jobs from each shard.
62- if require_complete {
63- for shard in query. state . active . lock_shards ( ) {
64- gather_shard_jobs ( & shard) ;
77+ match collect_kind {
78+ CollectActiveJobsKind :: Full => {
79+ for shard in query. state . active . lock_shards ( ) {
80+ gather_shard_jobs ( & shard) ;
81+ }
6582 }
66- } else {
67- // We use try_lock_shards here since we are called from the
68- // deadlock handler, and this shouldn't be locked.
69- for shard in query. state . active . try_lock_shards ( ) {
70- // This can be called during unwinding, and the function has a `try_`-prefix, so
71- // don't `unwrap()` here, just manually check for `None` and do best-effort error
72- // reporting.
73- match shard {
74- None => {
75- tracing:: warn!(
76- "Failed to collect active jobs for query with name `{}`!" ,
77- query. name
78- ) ;
79- return None ;
83+ CollectActiveJobsKind :: FullNoContention => {
84+ for shard in query. state . active . try_lock_shards ( ) {
85+ match shard {
86+ Some ( shard) => gather_shard_jobs ( & shard) ,
87+ None => panic ! ( "Failed to collect active jobs for query `{}`!" , query. name) ,
88+ }
89+ }
90+ }
91+ CollectActiveJobsKind :: PartialAllowed => {
92+ for shard in query. state . active . try_lock_shards ( ) {
93+ match shard {
94+ Some ( shard) => gather_shard_jobs ( & shard) ,
95+ None => warn ! ( "Failed to collect active jobs for query `{}`!" , query. name) ,
8096 }
81- Some ( shard) => gather_shard_jobs ( & shard) ,
8297 }
8398 }
8499 }
85-
86- // Call `make_frame` while we're not holding a `state.active` lock as `make_frame` may call
87- // queries leading to a deadlock.
88- for ( key, job) in active {
89- let frame = crate :: plumbing:: create_deferred_query_stack_frame ( tcx, query, key) ;
90- job_map_out. insert ( job. id , QueryJobInfo { frame, job } ) ;
91- }
92-
93- Some ( ( ) )
94100}
95101
96102#[ cold]
@@ -205,11 +211,10 @@ fn cycle_error<'tcx, C: QueryCache>(
205211 try_execute : QueryJobId ,
206212 span : Span ,
207213) -> ( C :: Value , Option < DepNodeIndex > ) {
208- // Ensure there was no errors collecting all active jobs.
214+ // Ensure there were no errors collecting all active jobs.
209215 // We need the complete map to ensure we find a cycle to break.
210- let job_map = collect_active_jobs_from_all_queries ( tcx, false )
211- . ok ( )
212- . expect ( "failed to collect active queries" ) ;
216+ let job_map =
217+ collect_active_jobs_from_all_queries ( tcx, CollectActiveJobsKind :: FullNoContention ) ;
213218
214219 let error = find_cycle_in_stack ( try_execute, job_map, & current_query_job ( ) , span) ;
215220 ( mk_cycle ( query, tcx, error. lift ( ) ) , None )
0 commit comments