@@ -24,6 +24,11 @@ use rustc_session::config::EntryFnType;
2424use crate :: shims:: tls;
2525use crate :: * ;
2626
27+ /// When the main thread would exit, we will yield to any other thread that is ready to execute.
28+ /// But we must only do that a finite number of times, or a background thread running `loop {}`
29+ /// will hang the program.
30+ const MAIN_THREAD_YIELDS_AT_SHUTDOWN : u32 = 1_000 ;
31+
2732#[ derive( Copy , Clone , Debug , PartialEq ) ]
2833pub enum AlignmentCheck {
2934 /// Do not check alignment.
@@ -180,6 +185,10 @@ enum MainThreadState {
180185 #[ default]
181186 Running ,
182187 TlsDtors ( tls:: TlsDtorsState ) ,
188+ Yield {
189+ remaining : u32 ,
190+ } ,
191+ Done ,
183192}
184193
185194impl MainThreadState {
@@ -196,22 +205,36 @@ impl MainThreadState {
196205 match state. on_stack_empty ( this) ? {
197206 Poll :: Pending => { } // just keep going
198207 Poll :: Ready ( ( ) ) => {
199- // Need to call `thread_terminated` ourselves since we are not going to
200- // return to the scheduler loop.
201- this. thread_terminated ( ) ?;
202- // Raise exception to stop program execution.
203- let ret_place = MPlaceTy :: from_aligned_ptr (
204- this. machine . main_fn_ret_place . unwrap ( ) . ptr ,
205- this. machine . layouts . isize ,
206- ) ;
207- let exit_code =
208- this. read_scalar ( & ret_place. into ( ) ) ?. to_machine_isize ( this) ?;
209- throw_machine_stop ! ( TerminationInfo :: Exit {
210- code: exit_code,
211- leak_check: true
212- } ) ;
208+ // Give background threads a chance to finish by yielding the main thread a
209+ // couple of times -- but only if we would also preempt threads randomly.
210+ if this. machine . preemption_rate > 0.0 {
211+ * self = Yield { remaining : MAIN_THREAD_YIELDS_AT_SHUTDOWN } ;
212+ } else {
213+ * self = Done ;
214+ }
213215 }
214216 } ,
217+ Yield { remaining } =>
218+ match remaining. checked_sub ( 1 ) {
219+ None => * self = Done ,
220+ Some ( new_remaining) => {
221+ * remaining = new_remaining;
222+ this. yield_active_thread ( ) ;
223+ }
224+ } ,
225+ Done => {
226+ // Figure out exit code.
227+ let ret_place = MPlaceTy :: from_aligned_ptr (
228+ this. machine . main_fn_ret_place . unwrap ( ) . ptr ,
229+ this. machine . layouts . isize ,
230+ ) ;
231+ let exit_code = this. read_scalar ( & ret_place. into ( ) ) ?. to_machine_isize ( this) ?;
232+ // Need to call `thread_terminated` ourselves since we are not going to
233+ // return to the scheduler loop.
234+ this. thread_terminated ( ) ?;
235+ // Stop interpreter loop.
236+ throw_machine_stop ! ( TerminationInfo :: Exit { code: exit_code, leak_check: true } ) ;
237+ }
215238 }
216239 Ok ( Poll :: Pending )
217240 }
0 commit comments