Skip to content

Commit f82d4f9

Browse files
rootroot
root
authored and
root
committed
notify only one waiter at a deadlock hanlder
1 parent 979f18e commit f82d4f9

File tree

1 file changed

+8
-6
lines changed
  • compiler/rustc_query_system/src/query

1 file changed

+8
-6
lines changed

compiler/rustc_query_system/src/query/job.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ where
378378
fn remove_cycle(
379379
query_map: &QueryMap,
380380
jobs: &mut Vec<QueryJobId>,
381-
wakelist: &mut Vec<Arc<QueryWaiter>>,
381+
wakelist: &Mutex<Vec<Arc<QueryWaiter>>>,
382382
) -> bool {
383383
let mut visited = FxHashSet::default();
384384
let mut stack = Vec::new();
@@ -466,7 +466,7 @@ fn remove_cycle(
466466
*waiter.cycle.lock() = Some(error);
467467

468468
// Put the waiter on the list of things to resume
469-
wakelist.push(waiter);
469+
wakelist.lock().push(waiter);
470470

471471
true
472472
} else {
@@ -480,25 +480,27 @@ fn remove_cycle(
480480
/// There may be multiple cycles involved in a deadlock, so this searches
481481
/// all active queries for cycles before finally resuming all the waiters at once.
482482
pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) {
483-
let mut wakelist = Vec::new();
483+
static WAKELIST: Mutex<Vec<Arc<QueryWaiter>>> = Mutex::new(Vec::new());
484484
let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect();
485485

486486
let mut found_cycle = false;
487487

488488
while jobs.len() > 0 {
489-
if remove_cycle(&query_map, &mut jobs, &mut wakelist) {
489+
if remove_cycle(&query_map, &mut jobs, &WAKELIST) {
490490
found_cycle = true;
491491
}
492492
}
493493

494+
let mut wake = WAKELIST.lock();
495+
494496
// Check that a cycle was found. It is possible for a deadlock to occur without
495497
// a query cycle if a query which can be waited on uses Rayon to do multithreading
496498
// internally. Such a query (X) may be executing on 2 threads (A and B) and A may
497499
// wait using Rayon on B. Rayon may then switch to executing another query (Y)
498500
// which in turn will wait on X causing a deadlock. We have a false dependency from
499501
// X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
500502
// only considers the true dependency and won't detect a cycle.
501-
if !found_cycle {
503+
if !found_cycle && wake.is_empty() {
502504
panic!(
503505
"deadlock detected as we're unable to find a query cycle to break\n\
504506
current query map:\n{:#?}",
@@ -507,7 +509,7 @@ pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry)
507509
}
508510

509511
// FIXME: Ensure this won't cause a deadlock before we return
510-
for waiter in wakelist.into_iter() {
512+
if let Some(waiter) = wake.pop() {
511513
waiter.notify(registry);
512514
}
513515
}

0 commit comments

Comments
 (0)