diff --git a/src/librustc/ty/maps/job.rs b/src/librustc/ty/maps/job.rs
index adc06a9e457..8b8f8420163 100644
--- a/src/librustc/ty/maps/job.rs
+++ b/src/librustc/ty/maps/job.rs
@@ -194,19 +194,25 @@ impl<'tcx> QueryLatch<'tcx> {
}
}
+ /// Awaits the caller on this latch by blocking the current thread.
fn await(&self, waiter: &mut QueryWaiter<'tcx>) {
let mut info = self.info.lock();
if !info.complete {
+ // We push the waiter on to the `waiters` list. It can be accessed inside
+ // the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
+ // Both of these will remove it from the `waiters` list before resuming
+ // this thread.
info.waiters.push(waiter);
- let condvar = &waiter.condvar;
+
// If this detects a deadlock and the deadlock handler want to resume this thread
// we have to be in the `wait` call. This is ensured by the deadlock handler
// getting the self.info lock.
rayon_core::mark_blocked();
- condvar.wait(&mut info);
+ waiter.condvar.wait(&mut info);
}
}
+ /// Sets the latch and resumes all waiters on it
fn set(&self) {
let mut info = self.info.lock();
debug_assert!(!info.complete);
@@ -219,46 +225,56 @@ impl<'tcx> QueryLatch<'tcx> {
}
}
- fn resume_waiter(
+ /// Remove a single waiter from the list of waiters.
+ /// This is used to break query cycles.
+ fn extract_waiter(
&self,
waiter: usize,
- error: CycleError<'tcx>
) -> *mut QueryWaiter<'tcx> {
let mut info = self.info.lock();
debug_assert!(!info.complete);
// Remove the waiter from the list of waiters
- let waiter = info.waiters.remove(waiter);
-
- // Set the cycle error it will be picked it up when resumed
- unsafe {
- (*waiter).cycle = Some(error);
- }
-
- waiter
+ info.waiters.remove(waiter)
}
}
+/// A pointer to an active query job. This is used to give query jobs an identity.
#[cfg(parallel_queries)]
type Ref<'tcx> = *const QueryJob<'tcx>;
+/// A resumable waiter of a query. The usize is the index into waiters in the query's latch
#[cfg(parallel_queries)]
type Waiter<'tcx> = (Ref<'tcx>, usize);
+/// Visits all the non-resumable and resumable waiters of a query.
+/// Only waiters in a query are visited.
+/// `visit` is called for every waiter and is passed a query waiting on `query_ref`
+/// and a span indicating the reason the query waited on `query_ref`.
+/// If `visit` returns Some, this function returns.
+/// For visits of non-resumable waiters it returns the return value of `visit`.
+/// For visits of resumable waiters it returns Some(Some(Waiter)) which has the
+/// required information to resume the waiter.
+/// If all `visit` calls returns None, this function also returns None.
#[cfg(parallel_queries)]
fn visit_waiters<'tcx, F>(query_ref: Ref<'tcx>, mut visit: F) -> Option