@@ -1999,6 +1999,7 @@ resolve_final_tstate(_PyRuntimeState *runtime)
1999
1999
}
2000
2000
else {
2001
2001
/* Fall back to the current tstate. It's better than nothing. */
2002
+ // XXX No it's not
2002
2003
main_tstate = tstate ;
2003
2004
}
2004
2005
}
@@ -2044,6 +2045,16 @@ _Py_Finalize(_PyRuntimeState *runtime)
2044
2045
2045
2046
_PyAtExit_Call (tstate -> interp );
2046
2047
2048
+ /* Clean up any lingering subinterpreters.
2049
+
2050
+ Two preconditions need to be met here:
2051
+
2052
+ - This has to happen before _PyRuntimeState_SetFinalizing is
2053
+ called, or else threads might get prematurely blocked.
2054
+ - The world must not be stopped, as finalizers can run.
2055
+ */
2056
+ finalize_subinterpreters ();
2057
+
2047
2058
assert (_PyThreadState_GET () == tstate );
2048
2059
2049
2060
/* Copy the core config, PyInterpreterState_Delete() free
@@ -2131,9 +2142,6 @@ _Py_Finalize(_PyRuntimeState *runtime)
2131
2142
_PyImport_FiniExternal (tstate -> interp );
2132
2143
finalize_modules (tstate );
2133
2144
2134
- /* Clean up any lingering subinterpreters. */
2135
- finalize_subinterpreters ();
2136
-
2137
2145
/* Print debug stats if any */
2138
2146
_PyEval_Fini ();
2139
2147
@@ -2414,9 +2422,8 @@ Py_NewInterpreter(void)
2414
2422
return tstate ;
2415
2423
}
2416
2424
2417
- /* Delete an interpreter and its last thread. This requires that the
2418
- given thread state is current, that the thread has no remaining
2419
- frames, and that it is its interpreter's only remaining thread.
2425
+ /* Delete an interpreter. This requires that the given thread state
2426
+ is current, and that the thread has no remaining frames.
2420
2427
It is a fatal error to violate these constraints.
2421
2428
2422
2429
(Py_FinalizeEx() doesn't have these constraints -- it zaps
@@ -2446,15 +2453,20 @@ Py_EndInterpreter(PyThreadState *tstate)
2446
2453
_Py_FinishPendingCalls (tstate );
2447
2454
2448
2455
_PyAtExit_Call (tstate -> interp );
2449
-
2450
- if (tstate != interp -> threads .head || tstate -> next != NULL ) {
2451
- Py_FatalError ("not the last thread" );
2452
- }
2453
-
2456
+ _PyRuntimeState * runtime = interp -> runtime ;
2457
+ _PyEval_StopTheWorldAll (runtime );
2454
2458
/* Remaining daemon threads will automatically exit
2455
2459
when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
2456
2460
_PyInterpreterState_SetFinalizing (interp , tstate );
2457
2461
2462
+ PyThreadState * list = _PyThreadState_RemoveExcept (tstate );
2463
+ for (PyThreadState * p = list ; p != NULL ; p = p -> next ) {
2464
+ _PyThreadState_SetShuttingDown (p );
2465
+ }
2466
+
2467
+ _PyEval_StartTheWorldAll (runtime );
2468
+ _PyThreadState_DeleteList (list , /*is_after_fork=*/ 0 );
2469
+
2458
2470
// XXX Call something like _PyImport_Disable() here?
2459
2471
2460
2472
_PyImport_FiniExternal (tstate -> interp );
@@ -2484,6 +2496,8 @@ finalize_subinterpreters(void)
2484
2496
PyInterpreterState * main_interp = _PyInterpreterState_Main ();
2485
2497
assert (final_tstate -> interp == main_interp );
2486
2498
_PyRuntimeState * runtime = main_interp -> runtime ;
2499
+ assert (!runtime -> stoptheworld .world_stopped );
2500
+ assert (_PyRuntimeState_GetFinalizing (runtime ) == NULL );
2487
2501
struct pyinterpreters * interpreters = & runtime -> interpreters ;
2488
2502
2489
2503
/* Get the first interpreter in the list. */
@@ -2512,27 +2526,17 @@ finalize_subinterpreters(void)
2512
2526
2513
2527
/* Clean up all remaining subinterpreters. */
2514
2528
while (interp != NULL ) {
2515
- assert (!_PyInterpreterState_IsRunningMain (interp ));
2516
-
2517
- /* Find the tstate to use for fini. We assume the interpreter
2518
- will have at most one tstate at this point. */
2519
- PyThreadState * tstate = interp -> threads .head ;
2520
- if (tstate != NULL ) {
2521
- /* Ideally we would be able to use tstate as-is, and rely
2522
- on it being in a ready state: no exception set, not
2523
- running anything (tstate->current_frame), matching the
2524
- current thread ID (tstate->thread_id). To play it safe,
2525
- we always delete it and use a fresh tstate instead. */
2526
- assert (tstate != final_tstate );
2527
- _PyThreadState_Attach (tstate );
2528
- PyThreadState_Clear (tstate );
2529
- _PyThreadState_Detach (tstate );
2530
- PyThreadState_Delete (tstate );
2529
+ /* Make a tstate for finalization. */
2530
+ PyThreadState * tstate = _PyThreadState_NewBound (interp , _PyThreadState_WHENCE_FINI );
2531
+ if (tstate == NULL ) {
2532
+ // XXX Some graceful way to always get a thread state?
2533
+ Py_FatalError ("thread state allocation failed" );
2531
2534
}
2532
- tstate = _PyThreadState_NewBound (interp , _PyThreadState_WHENCE_FINI );
2533
2535
2534
- /* Destroy the subinterpreter. */
2536
+ /* Enter the subinterpreter. */
2535
2537
_PyThreadState_Attach (tstate );
2538
+
2539
+ /* Destroy the subinterpreter. */
2536
2540
Py_EndInterpreter (tstate );
2537
2541
assert (_PyThreadState_GET () == NULL );
2538
2542
0 commit comments