@@ -93,6 +93,28 @@ pub struct JobQueue<'a, 'cfg> {
9393///
9494/// It is created from JobQueue when we have fully assembled the crate graph
9595/// (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.
96118struct DrainState < ' a , ' cfg > {
97119 // This is the length of the DependencyQueue when starting out
98120 total_units : usize ,
@@ -212,11 +234,11 @@ impl<'a> JobState<'a> {
212234 }
213235
214236 pub fn stdout ( & self , stdout : String ) {
215- self . messages . push ( Message :: Stdout ( stdout) ) ;
237+ self . messages . push_bounded ( Message :: Stdout ( stdout) ) ;
216238 }
217239
218240 pub fn stderr ( & self , stderr : String ) {
219- self . messages . push ( Message :: Stderr ( stderr) ) ;
241+ self . messages . push_bounded ( Message :: Stderr ( stderr) ) ;
220242 }
221243
222244 /// A method used to signal to the coordinator thread that the rmeta file
@@ -341,7 +363,10 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
341363 let state = DrainState {
342364 total_units : self . queue . len ( ) ,
343365 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 ) ) ,
345370 active : HashMap :: new ( ) ,
346371 compiled : HashSet :: new ( ) ,
347372 documented : HashSet :: new ( ) ,
@@ -370,6 +395,9 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
370395 // Create a helper thread to manage the diagnostics for rustfix if
371396 // necessary.
372397 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.
373401 let _diagnostic_server = cx
374402 . bcx
375403 . build_config
@@ -578,10 +606,7 @@ impl<'a, 'cfg> DrainState<'a, 'cfg> {
578606 // to run above to calculate CPU usage over time. To do this we
579607 // listen for a message with a timeout, and on timeout we run the
580608 // 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 ( ) ;
585610 info ! (
586611 "tokens in use: {}, rustc_tokens: {:?}, waiting_rustcs: {:?} (events this tick: {})" ,
587612 self . tokens. len( ) ,
@@ -815,15 +840,10 @@ impl<'a, 'cfg> DrainState<'a, 'cfg> {
815840 } ;
816841
817842 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 ( ) ,
826845 }
846+ scope. spawn ( move |_| doit ( ) ) ;
827847
828848 Ok ( ( ) )
829849 }
0 commit comments