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