55#include "pycore_pyerrors.h" // _PyErr_Fetch()
66#include "pycore_pylifecycle.h" // _PyErr_Print()
77#include "pycore_initconfig.h" // _PyStatus_OK()
8+ #include "pycore_interp.h" // _Py_RunGC()
89#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
910
1011/*
@@ -69,7 +70,8 @@ COMPUTE_EVAL_BREAKER(PyInterpreterState *interp,
6970 && _Py_ThreadCanHandleSignals (interp ))
7071 | (_Py_atomic_load_relaxed_int32 (& ceval2 -> pending .calls_to_do )
7172 && _Py_ThreadCanHandlePendingCalls ())
72- | ceval2 -> pending .async_exc );
73+ | ceval2 -> pending .async_exc
74+ | _Py_atomic_load_relaxed_int32 (& ceval2 -> gc_scheduled ));
7375}
7476
7577
@@ -938,6 +940,7 @@ _Py_HandlePending(PyThreadState *tstate)
938940{
939941 _PyRuntimeState * const runtime = & _PyRuntime ;
940942 struct _ceval_runtime_state * ceval = & runtime -> ceval ;
943+ struct _ceval_state * interp_ceval_state = & tstate -> interp -> ceval ;
941944
942945 /* Pending signals */
943946 if (_Py_atomic_load_relaxed_int32 (& ceval -> signals_pending )) {
@@ -947,20 +950,26 @@ _Py_HandlePending(PyThreadState *tstate)
947950 }
948951
949952 /* Pending calls */
950- struct _ceval_state * ceval2 = & tstate -> interp -> ceval ;
951- if (_Py_atomic_load_relaxed_int32 (& ceval2 -> pending .calls_to_do )) {
953+ if (_Py_atomic_load_relaxed_int32 (& interp_ceval_state -> pending .calls_to_do )) {
952954 if (make_pending_calls (tstate -> interp ) != 0 ) {
953955 return -1 ;
954956 }
955957 }
956958
959+ /* GC scheduled to run */
960+ if (_Py_atomic_load_relaxed_int32 (& interp_ceval_state -> gc_scheduled )) {
961+ _Py_atomic_store_relaxed (& interp_ceval_state -> gc_scheduled , 0 );
962+ COMPUTE_EVAL_BREAKER (tstate -> interp , ceval , interp_ceval_state );
963+ _Py_RunGC (tstate );
964+ }
965+
957966 /* GIL drop request */
958- if (_Py_atomic_load_relaxed_int32 (& ceval2 -> gil_drop_request )) {
967+ if (_Py_atomic_load_relaxed_int32 (& interp_ceval_state -> gil_drop_request )) {
959968 /* Give another thread a chance */
960969 if (_PyThreadState_Swap (& runtime -> gilstate , NULL ) != tstate ) {
961970 Py_FatalError ("tstate mix-up" );
962971 }
963- drop_gil (ceval , ceval2 , tstate );
972+ drop_gil (ceval , interp_ceval_state , tstate );
964973
965974 /* Other threads may run now */
966975
@@ -981,16 +990,17 @@ _Py_HandlePending(PyThreadState *tstate)
981990 return -1 ;
982991 }
983992
984- #ifdef MS_WINDOWS
985- // bpo-42296: On Windows, _PyEval_SignalReceived() can be called in a
986- // different thread than the Python thread, in which case
993+
994+ // It is possible that some of the conditions that trigger the eval breaker
995+ // are called in a different thread than the Python thread. An example of
996+ // this is bpo-42296: On Windows, _PyEval_SignalReceived() can be called in
997+ // a different thread than the Python thread, in which case
987998 // _Py_ThreadCanHandleSignals() is wrong. Recompute eval_breaker in the
988999 // current Python thread with the correct _Py_ThreadCanHandleSignals()
9891000 // value. It prevents to interrupt the eval loop at every instruction if
9901001 // the current Python thread cannot handle signals (if
9911002 // _Py_ThreadCanHandleSignals() is false).
992- COMPUTE_EVAL_BREAKER (tstate -> interp , ceval , ceval2 );
993- #endif
1003+ COMPUTE_EVAL_BREAKER (tstate -> interp , ceval , interp_ceval_state );
9941004
9951005 return 0 ;
9961006}
0 commit comments