@@ -763,68 +763,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
763763
764764 DISPATCH ();
765765
766- handle_eval_breaker :
767-
768- /* Do periodic things, like check for signals and async I/0.
769- * We need to do reasonably frequently, but not too frequently.
770- * All loops should include a check of the eval breaker.
771- * We also check on return from any builtin function.
772- *
773- * ## More Details ###
774- *
775- * The eval loop (this function) normally executes the instructions
776- * of a code object sequentially. However, the runtime supports a
777- * number of out-of-band execution scenarios that may pause that
778- * sequential execution long enough to do that out-of-band work
779- * in the current thread using the current PyThreadState.
780- *
781- * The scenarios include:
782- *
783- * - cyclic garbage collection
784- * - GIL drop requests
785- * - "async" exceptions
786- * - "pending calls" (some only in the main thread)
787- * - signal handling (only in the main thread)
788- *
789- * When the need for one of the above is detected, the eval loop
790- * pauses long enough to handle the detected case. Then, if doing
791- * so didn't trigger an exception, the eval loop resumes executing
792- * the sequential instructions.
793- *
794- * To make this work, the eval loop periodically checks if any
795- * of the above needs to happen. The individual checks can be
796- * expensive if computed each time, so a while back we switched
797- * to using pre-computed, per-interpreter variables for the checks,
798- * and later consolidated that to a single "eval breaker" variable
799- * (now a PyInterpreterState field).
800- *
801- * For the longest time, the eval breaker check would happen
802- * frequently, every 5 or so times through the loop, regardless
803- * of what instruction ran last or what would run next. Then, in
804- * early 2021 (gh-18334, commit 4958f5d), we switched to checking
805- * the eval breaker less frequently, by hard-coding the check to
806- * specific places in the eval loop (e.g. certain instructions).
807- * The intent then was to check after returning from calls
808- * and on the back edges of loops.
809- *
810- * In addition to being more efficient, that approach keeps
811- * the eval loop from running arbitrary code between instructions
812- * that don't handle that well. (See gh-74174.)
813- *
814- * Currently, the eval breaker check happens here at the
815- * "handle_eval_breaker" label. Some instructions come here
816- * explicitly (goto) and some indirectly. Notably, the check
817- * happens on back edges in the control flow graph, which
818- * pretty much applies to all loops and most calls.
819- * (See bytecodes.c for exact information.)
820- *
821- * One consequence of this approach is that it might not be obvious
822- * how to force any specific thread to pick up the eval breaker,
823- * or for any specific thread to not pick it up. Mostly this
824- * involves judicious uses of locks and careful ordering of code,
825- * while avoiding code that might trigger the eval breaker
826- * until so desired.
827- */
828766 if (_Py_HandlePending (tstate ) != 0 ) {
829767 goto error ;
830768 }
@@ -2796,13 +2734,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
27962734 PyThreadState * tstate = _PyThreadState_GET ();
27972735 _PyUOpExecutorObject * self = (_PyUOpExecutorObject * )executor ;
27982736
2799- // Equivalent to CHECK_EVAL_BREAKER()
2800- _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY ();
2801- if (_Py_atomic_load_relaxed_int32 (& tstate -> interp -> ceval .eval_breaker )) {
2802- if (_Py_HandlePending (tstate ) != 0 ) {
2803- goto error ;
2804- }
2805- }
2737+ CHECK_EVAL_BREAKER ();
28062738
28072739 OBJECT_STAT_INC (optimization_traces_executed );
28082740 _Py_CODEUNIT * ip_offset = (_Py_CODEUNIT * )_PyFrame_GetCode (frame )-> co_code_adaptive ;
0 commit comments