Skip to main content

rustc_middle/query/
job.rs

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(#[automatically_derived]
impl<I: ::core::clone::Clone> ::core::clone::Clone for QueryInfo<I> {
    #[inline]
    fn clone(&self) -> QueryInfo<I> {
        QueryInfo {
            span: ::core::clone::Clone::clone(&self.span),
            frame: ::core::clone::Clone::clone(&self.frame),
        }
    }
}Clone, #[automatically_derived]
impl<I: ::core::fmt::Debug> ::core::fmt::Debug for QueryInfo<I> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "QueryInfo",
            "span", &self.span, "frame", &&self.frame)
    }
}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(#[automatically_derived]
impl ::core::marker::Copy for QueryJobId { }Copy, #[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_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<NonZero<u64>>;
    }
}Eq, #[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)]
29pub struct QueryJobId(pub NonZero<u64>);
30
31/// Represents an active query job.
32#[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)]
33pub struct QueryJob<'tcx> {
34    pub id: QueryJobId,
35
36    /// The span corresponding to the reason for which this query was required.
37    pub span: Span,
38
39    /// The parent query job which created this job and is implicitly waiting on it.
40    pub parent: Option<QueryJobId>,
41
42    /// The latch that is used to wait on this job.
43    pub latch: Option<QueryLatch<'tcx>>,
44}
45
46impl<'tcx> QueryJob<'tcx> {
47    /// Creates a new query job.
48    #[inline]
49    pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
50        QueryJob { id, span, parent, latch: None }
51    }
52
53    pub fn latch(&mut self) -> QueryLatch<'tcx> {
54        if self.latch.is_none() {
55            self.latch = Some(QueryLatch::new());
56        }
57        self.latch.as_ref().unwrap().clone()
58    }
59
60    /// Signals to waiters that the query is complete.
61    ///
62    /// This does nothing for single threaded rustc,
63    /// as there are no concurrent jobs which could be waiting on us
64    #[inline]
65    pub fn signal_complete(self) {
66        if let Some(latch) = self.latch {
67            latch.set();
68        }
69    }
70}
71
72#[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",
            "query", &self.query, "condvar", &self.condvar, "span",
            &self.span, "cycle", &&self.cycle)
    }
}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(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for QueryLatchInfo<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "QueryLatchInfo", "complete", &self.complete, "waiters",
            &&self.waiters)
    }
}Debug)]
81pub struct QueryLatchInfo<'tcx> {
82    pub complete: bool,
83    pub waiters: Vec<Arc<QueryWaiter<'tcx>>>,
84}
85
86#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for QueryLatch<'tcx> {
    #[inline]
    fn clone(&self) -> QueryLatch<'tcx> {
        QueryLatch { info: ::core::clone::Clone::clone(&self.info) }
    }
}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",
            "info", &&self.info)
    }
}Debug)]
87pub struct QueryLatch<'tcx> {
88    pub info: Arc<Mutex<QueryLatchInfo<'tcx>>>,
89}
90
91impl<'tcx> QueryLatch<'tcx> {
92    fn new() -> Self {
93        QueryLatch {
94            info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
95        }
96    }
97
98    /// Awaits for the query job to complete.
99    pub fn wait_on(
100        &self,
101        tcx: TyCtxt<'tcx>,
102        query: Option<QueryJobId>,
103        span: Span,
104    ) -> Result<(), CycleError<QueryStackDeferred<'tcx>>> {
105        let waiter =
106            Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() });
107        self.wait_on_inner(tcx, &waiter);
108        // FIXME: Get rid of this lock. We have ownership of the QueryWaiter
109        // although another thread may still have a Arc reference so we cannot
110        // use Arc::get_mut
111        let mut cycle = waiter.cycle.lock();
112        match cycle.take() {
113            None => Ok(()),
114            Some(cycle) => Err(cycle),
115        }
116    }
117
118    /// Awaits the caller on this latch by blocking the current thread.
119    fn wait_on_inner(&self, tcx: TyCtxt<'tcx>, waiter: &Arc<QueryWaiter<'tcx>>) {
120        let mut info = self.info.lock();
121        if !info.complete {
122            // We push the waiter on to the `waiters` list. It can be accessed inside
123            // the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
124            // Both of these will remove it from the `waiters` list before resuming
125            // this thread.
126            info.waiters.push(Arc::clone(waiter));
127
128            // If this detects a deadlock and the deadlock handler wants to resume this thread
129            // we have to be in the `wait` call. This is ensured by the deadlock handler
130            // getting the self.info lock.
131            rustc_thread_pool::mark_blocked();
132            tcx.jobserver_proxy.release_thread();
133            waiter.condvar.wait(&mut info);
134            // Release the lock before we potentially block in `acquire_thread`
135            drop(info);
136            tcx.jobserver_proxy.acquire_thread();
137        }
138    }
139
140    /// Sets the latch and resumes all waiters on it
141    fn set(&self) {
142        let mut info = self.info.lock();
143        if true {
    if !!info.complete {
        ::core::panicking::panic("assertion failed: !info.complete")
    };
};debug_assert!(!info.complete);
144        info.complete = true;
145        let registry = rustc_thread_pool::Registry::current();
146        for waiter in info.waiters.drain(..) {
147            rustc_thread_pool::mark_unblocked(&registry);
148            waiter.condvar.notify_one();
149        }
150    }
151
152    /// Removes a single waiter from the list of waiters.
153    /// This is used to break query cycles.
154    pub fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter<'tcx>> {
155        let mut info = self.info.lock();
156        if true {
    if !!info.complete {
        ::core::panicking::panic("assertion failed: !info.complete")
    };
};debug_assert!(!info.complete);
157        // Remove the waiter from the list of waiters
158        info.waiters.remove(waiter)
159    }
160}