@@ -24,6 +24,11 @@ use rustc_session::config::EntryFnType;
24
24
use crate :: shims:: tls;
25
25
use crate :: * ;
26
26
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
+
27
32
#[ derive( Copy , Clone , Debug , PartialEq ) ]
28
33
pub enum AlignmentCheck {
29
34
/// Do not check alignment.
@@ -180,6 +185,10 @@ enum MainThreadState {
180
185
#[ default]
181
186
Running ,
182
187
TlsDtors ( tls:: TlsDtorsState ) ,
188
+ Yield {
189
+ remaining : u32 ,
190
+ } ,
191
+ Done ,
183
192
}
184
193
185
194
impl MainThreadState {
@@ -196,22 +205,36 @@ impl MainThreadState {
196
205
match state. on_stack_empty ( this) ? {
197
206
Poll :: Pending => { } // just keep going
198
207
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
+ }
213
215
}
214
216
} ,
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
+ }
215
238
}
216
239
Ok ( Poll :: Pending )
217
240
}
0 commit comments