Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
let query_map = rustc_span::set_session_globals_then(unsafe { &*(session_globals as *const SessionGlobals) }, || {
// Ensure there was no errors collecting all active jobs.
// We need the complete map to ensure we find a cycle to break.
QueryCtxt::new(tcx).collect_active_jobs().expect("failed to collect active queries in deadlock handler")
QueryCtxt::new(tcx).try_collect_active_jobs().expect("failed to collect active queries in deadlock handler")
});
break_query_cycles(query_map, &registry);
})
Expand Down
37 changes: 31 additions & 6 deletions compiler/rustc_query_impl/src/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ impl<'tcx> QueryCtxt<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
QueryCtxt { tcx }
}

fn collect_active_jobs(self) -> QueryMap<QueryStackDeferred<'tcx>> {
let mut jobs = QueryMap::default();

for collect in super::COLLECT_ACTIVE_JOBS.iter() {
collect(self.tcx, &mut jobs)
}
jobs
}
}

impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
Expand Down Expand Up @@ -91,7 +100,7 @@ impl<'tcx> QueryContext for QueryCtxt<'tcx> {
/// Returns a query map representing active query jobs.
/// It returns an incomplete map as an error if it fails
/// to take locks.
fn collect_active_jobs(
fn try_collect_active_jobs(
self,
) -> Result<QueryMap<QueryStackDeferred<'tcx>>, QueryMap<QueryStackDeferred<'tcx>>> {
let mut jobs = QueryMap::default();
Expand Down Expand Up @@ -163,11 +172,7 @@ impl<'tcx> QueryContext for QueryCtxt<'tcx> {
}

fn depth_limit_error(self, job: QueryJobId) {
// FIXME: `collect_active_jobs` expects no locks to be held, which doesn't hold for this call.
let query_map = match self.collect_active_jobs() {
Ok(query_map) => query_map,
Err(query_map) => query_map,
};
let query_map = self.collect_active_jobs();
let (info, depth) = job.find_dep_kind_root(query_map);

let suggested_limit = match self.recursion_limit() {
Expand Down Expand Up @@ -757,6 +762,22 @@ macro_rules! define_queries {
res
}

pub(crate) fn collect_active_jobs<'tcx>(
tcx: TyCtxt<'tcx>,
qmap: &mut QueryMap<QueryStackDeferred<'tcx>>,
) {
let make_query = |tcx, key| {
let kind = rustc_middle::dep_graph::dep_kinds::$name;
let name = stringify!($name);
$crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name)
};
tcx.query_system.states.$name.collect_active_jobs(
tcx,
make_query,
qmap,
);
}

pub(crate) fn alloc_self_profile_query_strings<'tcx>(
tcx: TyCtxt<'tcx>,
string_cache: &mut QueryKeyStringCache
Expand Down Expand Up @@ -819,6 +840,10 @@ macro_rules! define_queries {
] =
&[$(query_impl::$name::try_collect_active_jobs),*];

const COLLECT_ACTIVE_JOBS: &[
for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<QueryStackDeferred<'tcx>>)
] = &[$(query_impl::$name::collect_active_jobs),*];

const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[
for<'tcx> fn(TyCtxt<'tcx>, &mut QueryKeyStringCache)
] = &[$(query_impl::$name::alloc_self_profile_query_strings),*];
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_query_system/src/query/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
let mut count_total = 0;

// Make use of a partial query map if we fail to take locks collecting active queries.
let query_map = match qcx.collect_active_jobs() {
let query_map = match qcx.try_collect_active_jobs() {
Ok(query_map) => query_map,
Err(query_map) => query_map,
};
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_query_system/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ pub trait QueryContext: HasDepContext {
/// Get the query information from the TLS context.
fn current_query_job(self) -> Option<QueryJobId>;

fn collect_active_jobs(self) -> Result<QueryMap<Self::QueryInfo>, QueryMap<Self::QueryInfo>>;
fn try_collect_active_jobs(
self,
) -> Result<QueryMap<Self::QueryInfo>, QueryMap<Self::QueryInfo>>;

fn lift_query_info(self, info: &Self::QueryInfo) -> QueryStackFrameExtra;

Expand Down
26 changes: 25 additions & 1 deletion compiler/rustc_query_system/src/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,30 @@ where

Some(())
}

pub fn collect_active_jobs<Qcx: Copy>(
&self,
qcx: Qcx,
make_query: fn(Qcx, K) -> QueryStackFrame<I>,
jobs: &mut QueryMap<I>,
) {
let mut active = Vec::new();

for shard in self.active.lock_shards() {
for (k, v) in shard.iter() {
if let QueryResult::Started(ref job) = *v {
active.push((*k, (*job).clone()));
}
}
}

// Call `make_query` while we're not holding a `self.active` lock as `make_query` may call
// queries leading to a deadlock.
for (key, job) in active {
let query = make_query(qcx, key);
jobs.insert(job.id, QueryJobInfo { query, job });
}
}
}

impl<K, I> Default for QueryState<K, I> {
Expand Down Expand Up @@ -271,7 +295,7 @@ where
{
// Ensure there was no errors collecting all active jobs.
// We need the complete map to ensure we find a cycle to break.
let query_map = qcx.collect_active_jobs().ok().expect("failed to collect active queries");
let query_map = qcx.try_collect_active_jobs().ok().expect("failed to collect active queries");

let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span);
(mk_cycle(query, qcx, error.lift(qcx)), None)
Expand Down
Loading