1use std::fmt::Debug;
2use std::hash::Hash;
3use std::num::NonZero;
4use std::sync::Arc;
56use parking_lot::{Condvar, Mutex};
7use rustc_data_structures::hash_table::HashTable;
8use rustc_data_structures::sharded::Sharded;
9use rustc_span::Span;
1011use crate::queries::TaggedQueryKey;
1213/// A value uniquely identifying an active query job.
14#[derive(#[automatically_derived]
impl ::core::marker::Copy for QueryJobId { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for QueryJobId { }
#[automatically_derived]
impl ::core::clone::Clone for QueryJobId {
#[inline]
fn clone(&self) -> QueryJobId {
let _: ::core::clone::AssertParamIsClone<NonZero<u64>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::cmp::Eq for QueryJobId {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<NonZero<u64>>;
}
}Eq, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for QueryJobId { }
#[automatically_derived]
impl ::core::cmp::PartialEq for QueryJobId {
#[inline]
fn eq(&self, other: &QueryJobId) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::hash::Hash for QueryJobId {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for QueryJobId {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "QueryJobId",
&&self.0)
}
}Debug)]
15pub struct QueryJobId(pub NonZero<u64>);
1617/// Represents an active query job.
18#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for QueryJob<'tcx> {
#[inline]
fn clone(&self) -> QueryJob<'tcx> {
QueryJob {
id: ::core::clone::Clone::clone(&self.id),
span: ::core::clone::Clone::clone(&self.span),
parent: ::core::clone::Clone::clone(&self.parent),
latch: ::core::clone::Clone::clone(&self.latch),
}
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for QueryJob<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f, "QueryJob",
"id", &self.id, "span", &self.span, "parent", &self.parent,
"latch", &&self.latch)
}
}Debug)]
19pub struct QueryJob<'tcx> {
20pub id: QueryJobId,
2122/// The span corresponding to the reason for which this query was required.
23pub span: Span,
2425/// The parent query job which created this job and is implicitly waiting on it.
26pub parent: Option<QueryJobId>,
2728/// The latch that is used to wait on this job.
29pub latch: Option<QueryLatch<'tcx>>,
30}
3132impl<'tcx> QueryJob<'tcx> {
33/// Creates a new query job.
34#[inline]
35pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
36QueryJob { id, span, parent, latch: None }
37 }
3839pub fn latch(&mut self) -> QueryLatch<'tcx> {
40self.latch.get_or_insert_with(QueryLatch::new).clone()
41 }
4243/// Signals to waiters that the query is complete.
44 ///
45 /// This does nothing for single threaded rustc,
46 /// as there are no concurrent jobs which could be waiting on us
47#[inline]
48pub fn signal_complete(self) {
49if let Some(latch) = self.latch {
50latch.set();
51 }
52 }
53}
5455/// For a particular query and key, tracks the status of a query evaluation
56/// that has started, but has not yet finished successfully.
57///
58/// (Successful query evaluation for a key is represented by an entry in the
59/// query's in-memory cache.)
60pub enum ActiveKeyStatus<'tcx> {
61/// Some thread is already evaluating the query for this key.
62 ///
63 /// The enclosed [`QueryJob`] can be used to wait for it to finish.
64Started(QueryJob<'tcx>),
6566/// The query panicked. Queries trying to wait on this will raise a fatal error which will
67 /// silently panic.
68Poisoned,
69}
7071/// For a particular query, keeps track of "active" keys, i.e. keys whose
72/// evaluation has started but has not yet finished successfully.
73///
74/// (Successful query evaluation for a key is represented by an entry in the
75/// query's in-memory cache.)
76pub struct QueryState<'tcx, K> {
77pub active: Sharded<HashTable<(K, ActiveKeyStatus<'tcx>)>>,
78}
7980impl<'tcx, K> Defaultfor QueryState<'tcx, K> {
81fn default() -> QueryState<'tcx, K> {
82QueryState { active: Default::default() }
83 }
84}
8586/// Description of a frame in the query stack.
87///
88/// This is mostly used in case of cycles for error reporting.
89#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for QueryStackFrame<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"QueryStackFrame", "span", &self.span, "tagged_key",
&&self.tagged_key)
}
}Debug)]
90pub struct QueryStackFrame<'tcx> {
91pub span: Span,
9293/// The query and key of the query method call that this stack frame
94 /// corresponds to.
95 ///
96 /// Code that doesn't care about the specific key can still use this to
97 /// check which query it's for, or obtain the query's name.
98pub tagged_key: TaggedQueryKey<'tcx>,
99}
100101#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for QueryCycle<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "QueryCycle",
"usage", &self.usage, "frames", &&self.frames)
}
}Debug)]
102pub struct QueryCycle<'tcx> {
103/// The query and related span that uses the cycle.
104pub usage: Option<QueryStackFrame<'tcx>>,
105106/// The span here corresponds to the reason for which this query was required.
107pub frames: Vec<QueryStackFrame<'tcx>>,
108}
109110#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for QueryWaiter<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f, "QueryWaiter",
"parent", &self.parent, "condvar", &self.condvar, "span",
&self.span, "cycle", &&self.cycle)
}
}Debug)]
111pub struct QueryWaiter<'tcx> {
112pub parent: Option<QueryJobId>,
113pub condvar: Condvar,
114pub span: Span,
115pub cycle: Mutex<Option<QueryCycle<'tcx>>>,
116}
117118#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for QueryLatch<'tcx> {
#[inline]
fn clone(&self) -> QueryLatch<'tcx> {
QueryLatch { waiters: ::core::clone::Clone::clone(&self.waiters) }
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for QueryLatch<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f, "QueryLatch",
"waiters", &&self.waiters)
}
}Debug)]
119pub struct QueryLatch<'tcx> {
120/// The `Option` is `Some(..)` when the job is active, and `None` once completed.
121pub waiters: Arc<Mutex<Option<Vec<Arc<QueryWaiter<'tcx>>>>>>,
122}
123124impl<'tcx> QueryLatch<'tcx> {
125fn new() -> Self {
126QueryLatch { waiters: Arc::new(Mutex::new(Some(Vec::new()))) }
127 }
128129/// Awaits for the query job to complete.
130pub fn wait_on(&self, query: Option<QueryJobId>, span: Span) -> Result<(), QueryCycle<'tcx>> {
131let mut waiters_guard = self.waiters.lock();
132let Some(waiters) = &mut *waiters_guardelse {
133return Ok(()); // already complete
134};
135136let waiter = Arc::new(QueryWaiter {
137 parent: query,
138span,
139 cycle: Mutex::new(None),
140 condvar: Condvar::new(),
141 });
142143// We push the waiter on to the `waiters` list. It can be accessed inside
144 // the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
145 // Both of these will remove it from the `waiters` list before resuming
146 // this thread.
147waiters.push(Arc::clone(&waiter));
148149// Awaits the caller on this latch by blocking the current thread.
150 // If this detects a deadlock and the deadlock handler wants to resume this thread
151 // we have to be in the `wait` call. This is ensured by the deadlock handler
152 // getting the self.info lock.
153rustc_thread_pool::mark_blocked_and_wait(|| {
154waiter.condvar.wait(&mut waiters_guard);
155// Release the lock before we potentially block when acquiring jobserver token.
156drop(waiters_guard);
157 });
158159// FIXME: Get rid of this lock. We have ownership of the QueryWaiter
160 // although another thread may still have a Arc reference so we cannot
161 // use Arc::get_mut
162let mut cycle = waiter.cycle.lock();
163match cycle.take() {
164None => Ok(()),
165Some(cycle) => Err(cycle),
166 }
167 }
168169/// Sets the latch and resumes all waiters on it
170fn set(&self) {
171let mut waiters_guard = self.waiters.lock();
172let waiters = waiters_guard.take().unwrap(); // mark the latch as complete
173let registry = rustc_thread_pool::Registry::current();
174for waiter in waiters {
175 rustc_thread_pool::mark_unblocked(®istry);
176 waiter.condvar.notify_one();
177 }
178 }
179180/// Removes a single waiter from the list of waiters.
181 /// This is used to break query cycles.
182pub fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter<'tcx>> {
183let mut waiters_guard = self.waiters.lock();
184let waiters = waiters_guard.as_mut().expect("non-empty waiters vec");
185// Remove the waiter from the list of waiters
186waiters.remove(waiter)
187 }
188}