@@ -518,16 +518,26 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
518
518
return Ok ( SchedulingAction :: ExecuteTimeoutCallback ) ;
519
519
}
520
520
// No callbacks scheduled, pick a regular thread to execute.
521
- // We need to pick a new thread for execution.
522
- for ( id, thread) in self . threads . iter_enumerated ( ) {
521
+ // The active thread blocked or yielded. So we go search for another enabled thread.
522
+ // Curcially, we start searching at the current active thread ID, rather than at 0, since we
523
+ // want to avoid always scheduling threads 0 and 1 without ever making progress in thread 2.
524
+ //
525
+ // `skip(N)` means we start iterating at thread N, so we skip 1 more to start just *after*
526
+ // the active thread. Then after that we look at `take(N)`, i.e., the threads *before* the
527
+ // active thread.
528
+ let threads = self
529
+ . threads
530
+ . iter_enumerated ( )
531
+ . skip ( self . active_thread . index ( ) + 1 )
532
+ . chain ( self . threads . iter_enumerated ( ) . take ( self . active_thread . index ( ) ) ) ;
533
+ for ( id, thread) in threads {
534
+ debug_assert_ne ! ( self . active_thread, id) ;
523
535
if thread. state == ThreadState :: Enabled {
524
- if !self . yield_active_thread || id != self . active_thread {
525
- self . active_thread = id;
526
- if let Some ( data_race) = data_race {
527
- data_race. thread_set_active ( self . active_thread ) ;
528
- }
529
- break ;
536
+ self . active_thread = id;
537
+ if let Some ( data_race) = data_race {
538
+ data_race. thread_set_active ( self . active_thread ) ;
530
539
}
540
+ break ;
531
541
}
532
542
}
533
543
self . yield_active_thread = false ;
0 commit comments