@@ -93,6 +93,28 @@ pub struct JobQueue<'a, 'cfg> {
93
93
///
94
94
/// It is created from JobQueue when we have fully assembled the crate graph
95
95
/// (i.e., all package dependencies are known).
96
+ ///
97
+ /// # Message queue
98
+ ///
99
+ /// Each thread running a process uses the message queue to send messages back
100
+ /// to the main thread. The main thread coordinates everything, and handles
101
+ /// printing output.
102
+ ///
103
+ /// It is important to be careful which messages use `push` vs `push_bounded`.
104
+ /// `push` is for priority messages (like tokens, or "finished") where the
105
+ /// sender shouldn't block. We want to handle those so real work can proceed
106
+ /// ASAP.
107
+ ///
108
+ /// `push_bounded` is only for messages being printed to stdout/stderr. Being
109
+ /// bounded prevents a flood of messages causing a large amount of memory
110
+ /// being used.
111
+ ///
112
+ /// `push` also avoids blocking which helps avoid deadlocks. For example, when
113
+ /// the diagnostic server thread is dropped, it waits for the thread to exit.
114
+ /// But if the thread is blocked on a full queue, and there is a critical
115
+ /// error, the drop will deadlock. This should be fixed at some point in the
116
+ /// future. The jobserver thread has a similar problem, though it will time
117
+ /// out after 1 second.
96
118
struct DrainState < ' a , ' cfg > {
97
119
// This is the length of the DependencyQueue when starting out
98
120
total_units : usize ,
@@ -212,11 +234,11 @@ impl<'a> JobState<'a> {
212
234
}
213
235
214
236
pub fn stdout ( & self , stdout : String ) {
215
- self . messages . push ( Message :: Stdout ( stdout) ) ;
237
+ self . messages . push_bounded ( Message :: Stdout ( stdout) ) ;
216
238
}
217
239
218
240
pub fn stderr ( & self , stderr : String ) {
219
- self . messages . push ( Message :: Stderr ( stderr) ) ;
241
+ self . messages . push_bounded ( Message :: Stderr ( stderr) ) ;
220
242
}
221
243
222
244
/// A method used to signal to the coordinator thread that the rmeta file
@@ -341,7 +363,10 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
341
363
let state = DrainState {
342
364
total_units : self . queue . len ( ) ,
343
365
queue : self . queue ,
344
- messages : Arc :: new ( Queue :: new ( ) ) ,
366
+ // 100 here is somewhat arbitrary. It is a few screenfulls of
367
+ // output, and hopefully at most a few megabytes of memory for
368
+ // typical messages.
369
+ messages : Arc :: new ( Queue :: new ( 100 ) ) ,
345
370
active : HashMap :: new ( ) ,
346
371
compiled : HashSet :: new ( ) ,
347
372
documented : HashSet :: new ( ) ,
@@ -370,6 +395,9 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
370
395
// Create a helper thread to manage the diagnostics for rustfix if
371
396
// necessary.
372
397
let messages = state. messages . clone ( ) ;
398
+ // It is important that this uses `push` instead of `push_bounded` for
399
+ // now. If someone wants to fix this to be bounded, the `drop`
400
+ // implementation needs to be changed to avoid possible deadlocks.
373
401
let _diagnostic_server = cx
374
402
. bcx
375
403
. build_config
@@ -578,10 +606,7 @@ impl<'a, 'cfg> DrainState<'a, 'cfg> {
578
606
// to run above to calculate CPU usage over time. To do this we
579
607
// listen for a message with a timeout, and on timeout we run the
580
608
// previous parts of the loop again.
581
- let mut events = Vec :: new ( ) ;
582
- while let Some ( event) = self . messages . try_pop ( ) {
583
- events. push ( event) ;
584
- }
609
+ let mut events = self . messages . try_pop_all ( ) ;
585
610
info ! (
586
611
"tokens in use: {}, rustc_tokens: {:?}, waiting_rustcs: {:?} (events this tick: {})" ,
587
612
self . tokens. len( ) ,
@@ -815,15 +840,10 @@ impl<'a, 'cfg> DrainState<'a, 'cfg> {
815
840
} ;
816
841
817
842
match fresh {
818
- Freshness :: Fresh => {
819
- self . timings . add_fresh ( ) ;
820
- doit ( ) ;
821
- }
822
- Freshness :: Dirty => {
823
- self . timings . add_dirty ( ) ;
824
- scope. spawn ( move |_| doit ( ) ) ;
825
- }
843
+ Freshness :: Fresh => self . timings . add_fresh ( ) ,
844
+ Freshness :: Dirty => self . timings . add_dirty ( ) ,
826
845
}
846
+ scope. spawn ( move |_| doit ( ) ) ;
827
847
828
848
Ok ( ( ) )
829
849
}
0 commit comments