1use std::fmt::Debug;
2use std::hash::Hash;
3use std::num::NonZero;
4use std::sync::Arc;
5
6use parking_lot::{Condvar, Mutex};
7use rustc_span::Span;
8
9use crate::query::plumbing::CycleError;
10use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra};
11use crate::ty::TyCtxt;
12
13/// Represents a span and a query key.
14#[derive(Clone, Debug)]
15pub struct QueryInfo<I> {
16 /// The span corresponding to the reason for which this query was required.
17 pub span: Span,
18 pub frame: QueryStackFrame<I>,
19}
20
21impl<'tcx> QueryInfo<QueryStackDeferred<'tcx>> {
22 pub(crate) fn lift(&self) -> QueryInfo<QueryStackFrameExtra> {
23 QueryInfo { span: self.span, frame: self.frame.lift() }
24 }
25}
26
27/// A value uniquely identifying an active query job.
28#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
29pub struct QueryJobId(pub NonZero<u64>);
30
31/// Represents an active query job.
…lines 32–70 unchanged (39 lines)
71
72#[derive(Debug)]
73pub struct QueryWaiter<'tcx> {
74 pub query: Option<QueryJobId>,
75 pub condvar: Condvar,
76 pub span: Span,
77 pub cycle: Mutex<Option<CycleError<QueryStackDeferred<'tcx>>>>,
78}
79
80#[derive(Clone, Debug)]
81pub struct QueryLatch<'tcx> {
82 /// The `Option` is `Some(..)` when the job is active, and `None` once completed.
83 pub waiters: Arc<Mutex<Option<Vec<Arc<QueryWaiter<'tcx>>>>>>,
…lines 84–90 unchanged (7 lines)
91 /// Awaits for the query job to complete.
92 pub fn wait_on(
93 &self,
94 tcx: TyCtxt<'tcx>,
95 query: Option<QueryJobId>,
96 span: Span,
97 ) -> Result<(), CycleError<QueryStackDeferred<'tcx>>> {
98 let mut waiters_guard = self.waiters.lock();
99 let Some(waiters) = &mut *waiters_guard else {
100 return Ok(()); // already complete
101 };
102
103 let waiter =
104 Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() });
105
106 // We push the waiter on to the `waiters` list. It can be accessed inside
107 // the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
108 // Both of these will remove it from the `waiters` list before resuming
109 // this thread.
110 waiters.push(Arc::clone(&waiter));
111
112 // Awaits the caller on this latch by blocking the current thread.
113 // If this detects a deadlock and the deadlock handler wants to resume this thread
114 // we have to be in the `wait` call. This is ensured by the deadlock handler
115 // getting the self.info lock.
116 rustc_thread_pool::mark_blocked();
117 tcx.jobserver_proxy.release_thread();
118 waiter.condvar.wait(&mut waiters_guard);
119 // Release the lock before we potentially block in `acquire_thread`
120 drop(waiters_guard);
121 tcx.jobserver_proxy.acquire_thread();
122
123 // FIXME: Get rid of this lock. We have ownership of the QueryWaiter
124 // although another thread may still have a Arc reference so we cannot
125 // use Arc::get_mut
126 let mut cycle = waiter.cycle.lock();
127 match cycle.take() {
128 None => Ok(()),
129 Some(cycle) => Err(cycle),
130 }
131 }
132
133 /// Sets the latch and resumes all waiters on it
134 fn set(&self) {
135 let mut waiters_guard = self.waiters.lock();
136 let waiters = waiters_guard.take().unwrap(); // mark the latch as complete
137 let registry = rustc_thread_pool::Registry::current();
…lines 138–153 unchanged (16 lines)