@@ -2422,33 +2422,61 @@ _Py_IsInterpreterFinalizing(PyInterpreterState *interp)
2422
2422
static void
2423
2423
finalize_subinterpreters (void )
2424
2424
{
2425
+ PyThreadState * final_tstate = _PyThreadState_GET ();
2425
2426
PyInterpreterState * main_interp = _PyInterpreterState_Main ();
2426
- assert (_PyInterpreterState_GET () == main_interp );
2427
+ assert (final_tstate -> interp == main_interp );
2427
2428
_PyRuntimeState * runtime = main_interp -> runtime ;
2428
2429
struct pyinterpreters * interpreters = & runtime -> interpreters ;
2429
2430
2430
- /* Clean up all remaining subinterpreters . */
2431
+ /* Get the first interpreter in the list . */
2431
2432
HEAD_LOCK (runtime );
2432
2433
PyInterpreterState * interp = interpreters -> head ;
2433
2434
if (interp == main_interp ) {
2434
2435
interp = interp -> next ;
2435
2436
}
2436
2437
HEAD_UNLOCK (runtime );
2437
- if (interp != NULL ) {
2438
- (void )PyErr_WarnEx (
2439
- PyExc_RuntimeWarning ,
2440
- "remaining subinterpreters; "
2441
- "destroy them with _interpreters.destroy()" ,
2442
- 0 );
2438
+
2439
+ /* Bail out if there are no subinterpreters left. */
2440
+ if (interp == NULL ) {
2441
+ return ;
2443
2442
}
2443
+
2444
+ /* Warn the user if they forgot to clean up subinterpreters. */
2445
+ (void )PyErr_WarnEx (
2446
+ PyExc_RuntimeWarning ,
2447
+ "remaining subinterpreters; "
2448
+ "destroy them with _interpreters.destroy()" ,
2449
+ 0 );
2450
+
2451
+ /* Swap out the current tstate, which we know must belong
2452
+ to the main interpreter. */
2453
+ _PyThreadState_Detach (final_tstate );
2454
+
2455
+ /* Clean up all remaining subinterpreters. */
2444
2456
while (interp != NULL ) {
2445
- /* Destroy the subinterpreter. */
2446
2457
assert (!_PyInterpreterState_IsRunningMain (interp ));
2447
- PyThreadState * tstate =
2448
- _PyThreadState_NewBound (interp , _PyThreadState_WHENCE_FINI );
2449
- PyThreadState * save_tstate = PyThreadState_Swap (tstate );
2458
+
2459
+ /* Find the tstate to use for fini. We assume the interpreter
2460
+ will have at most one tstate at this point. */
2461
+ PyThreadState * tstate = interp -> threads .head ;
2462
+ if (tstate != NULL ) {
2463
+ /* Ideally we would be able to use tstate as-is, and rely
2464
+ on it being in a ready state: no exception set, not
2465
+ running anything (tstate->current_frame), matching the
2466
+ current thread ID (tstate->thread_id). To play it safe,
2467
+ we always delete it and use a fresh tstate instead. */
2468
+ assert (tstate != final_tstate );
2469
+ _PyThreadState_Attach (tstate );
2470
+ PyThreadState_Clear (tstate );
2471
+ _PyThreadState_Detach (tstate );
2472
+ PyThreadState_Delete (tstate );
2473
+ }
2474
+ tstate = _PyThreadState_NewBound (interp , _PyThreadState_WHENCE_FINI );
2475
+
2476
+ /* Destroy the subinterpreter. */
2477
+ _PyThreadState_Attach (tstate );
2450
2478
Py_EndInterpreter (tstate );
2451
- ( void ) PyThreadState_Swap ( save_tstate );
2479
+ assert ( _PyThreadState_GET () == NULL );
2452
2480
2453
2481
/* Advance to the next interpreter. */
2454
2482
HEAD_LOCK (runtime );
@@ -2458,6 +2486,9 @@ finalize_subinterpreters(void)
2458
2486
}
2459
2487
HEAD_UNLOCK (runtime );
2460
2488
}
2489
+
2490
+ /* Switch back to the main interpreter. */
2491
+ _PyThreadState_Attach (final_tstate );
2461
2492
}
2462
2493
2463
2494
0 commit comments