Skip to content

Commit 454e301

Browse files
committed
Streamline active job collection.
`collect_active_jobs_from_all_queries` takes a `require_complete` bool, and then some callers `expect` a full map result while others allow a partial map result. The end result is four possible combinations, but only three of them are used/make sense. This commit introduces `CollectActiveJobsKind`, a three-value enum that describes the three sensible combinations, and rewrites `collect_active_jobs_from_all_queries` around it. This makes it and its call sites much clearer, and removes the weird `Option<()>` and `Result<QueryJobMap, QueryJobMap>` return types. Other changes of note. - `active` is removed. The comment about `make_frame` is out of date, and `create_deferred_query_stack_frame` *is* safe to call with the query state locked. - When shard locking failure is allowed, collection no longer stops on the first failed shard.
1 parent b2fabe3 commit 454e301

5 files changed

Lines changed: 67 additions & 65 deletions

File tree

compiler/rustc_interface/src/util.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_data_structures::sync;
1818
use rustc_metadata::{DylibError, EncodedMetadata, load_symbol_from_dylib};
1919
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
2020
use rustc_middle::ty::{CurrentGcx, TyCtxt};
21-
use rustc_query_impl::collect_active_jobs_from_all_queries;
21+
use rustc_query_impl::{CollectActiveJobsKind, collect_active_jobs_from_all_queries};
2222
use rustc_session::config::{
2323
Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple,
2424
};
@@ -253,9 +253,11 @@ internal compiler error: query cycle handler thread panicked, aborting process";
253253
unsafe { &*(session_globals as *const SessionGlobals) },
254254
|| {
255255
// Ensure there were no errors collecting all active jobs.
256-
// We need the complete map to ensure we find a cycle to break.
257-
collect_active_jobs_from_all_queries(tcx, false).expect(
258-
"failed to collect active queries in deadlock handler",
256+
// We need the complete map to ensure we find a cycle to
257+
// break.
258+
collect_active_jobs_from_all_queries(
259+
tcx,
260+
CollectActiveJobsKind::FullNoContention,
259261
)
260262
},
261263
);

compiler/rustc_query_impl/src/execution.rs

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_middle::query::{
1515
use rustc_middle::ty::TyCtxt;
1616
use rustc_middle::verify_ich::incremental_verify_ich;
1717
use rustc_span::{DUMMY_SP, Span};
18+
use tracing::warn;
1819

1920
use crate::collect_active_jobs_from_all_queries;
2021
use 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`.
4058
pub(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)

compiler/rustc_query_impl/src/job.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_middle::ty::TyCtxt;
1414
use rustc_session::Session;
1515
use rustc_span::{DUMMY_SP, Span};
1616

17-
use crate::collect_active_jobs_from_all_queries;
17+
use crate::{CollectActiveJobsKind, collect_active_jobs_from_all_queries};
1818

1919
/// Map from query job IDs to job information collected by
2020
/// `collect_active_jobs_from_all_queries`.
@@ -385,8 +385,7 @@ pub fn print_query_stack<'tcx>(
385385
let mut count_total = 0;
386386

387387
// Make use of a partial query job map if we fail to take locks collecting active queries.
388-
let job_map: QueryJobMap<'_> = collect_active_jobs_from_all_queries(tcx, false)
389-
.unwrap_or_else(|partial_job_map| partial_job_map);
388+
let job_map = collect_active_jobs_from_all_queries(tcx, CollectActiveJobsKind::PartialAllowed);
390389

391390
if let Some(ref mut file) = file {
392391
let _ = writeln!(file, "\n\nquery stack during panic:");

compiler/rustc_query_impl/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_middle::ty::TyCtxt;
1818
use rustc_span::Span;
1919

2020
pub use crate::dep_kind_vtables::make_dep_kind_vtables;
21+
pub use crate::execution::CollectActiveJobsKind;
2122
pub use crate::job::{QueryJobMap, break_query_cycles, print_query_stack};
2223
use crate::profiling_support::QueryKeyStringCache;
2324

compiler/rustc_query_impl/src/plumbing.rs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,10 @@ use rustc_span::def_id::LOCAL_CRATE;
3333
use crate::error::{QueryOverflow, QueryOverflowNote};
3434
use crate::execution::{all_inactive, force_query};
3535
use crate::job::find_dep_kind_root;
36-
use crate::{GetQueryVTable, collect_active_jobs_from_all_queries};
36+
use crate::{CollectActiveJobsKind, GetQueryVTable, collect_active_jobs_from_all_queries};
3737

3838
fn depth_limit_error<'tcx>(tcx: TyCtxt<'tcx>, job: QueryJobId) {
39-
let job_map =
40-
collect_active_jobs_from_all_queries(tcx, true).expect("failed to collect active queries");
39+
let job_map = collect_active_jobs_from_all_queries(tcx, CollectActiveJobsKind::Full);
4140
let (info, depth) = find_dep_kind_root(job, job_map);
4241

4342
let suggested_limit = match tcx.recursion_limit() {
@@ -522,24 +521,20 @@ macro_rules! define_queries {
522521
/// complete map is needed and no deadlock is possible at this call site.
523522
pub fn collect_active_jobs_from_all_queries<'tcx>(
524523
tcx: TyCtxt<'tcx>,
525-
require_complete: bool,
526-
) -> Result<QueryJobMap<'tcx>, QueryJobMap<'tcx>> {
527-
let mut job_map_out = QueryJobMap::default();
528-
let mut complete = true;
524+
collect_kind: CollectActiveJobsKind,
525+
) -> QueryJobMap<'tcx> {
526+
let mut job_map = QueryJobMap::default();
529527

530528
$(
531-
let res = crate::execution::gather_active_jobs(
532-
&tcx.query_system.query_vtables.$name,
529+
crate::execution::gather_active_jobs(
533530
tcx,
534-
require_complete,
535-
&mut job_map_out,
531+
&tcx.query_system.query_vtables.$name,
532+
collect_kind,
533+
&mut job_map,
536534
);
537-
if res.is_none() {
538-
complete = false;
539-
}
540535
)*
541536

542-
if complete { Ok(job_map_out) } else { Err(job_map_out) }
537+
job_map
543538
}
544539

545540
/// All self-profiling events generated by the query engine use

0 commit comments

Comments
 (0)