https://github.com/python/cpython/commit/4aab0c4ea2c569fce374a05cdd3b91009944f82b
commit: 4aab0c4ea2c569fce374a05cdd3b91009944f82b
branch: main
author: Pieter Eendebak <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-10-31T17:39:25+05:30
summary:

gh-157746: Make PyErr_CheckSignals() cheap when no signal is pending (#157748)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-09-25-11-05-00.gh-issue-157746.q7Lk3d.rst
M Modules/signalmodule.c
M Python/ceval_gil.c

diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-25-11-05-00.gh-issue-157746.q7Lk3d.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-25-11-05-00.gh-issue-157746.q7Lk3d.rst
new file mode 100644
index 000000000000000..eb9e95defa3d6c2
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-25-11-05-00.gh-issue-157746.q7Lk3d.rst
@@ -0,0 +1,3 @@
+Reduce the overhead of :c:func:`PyErr_CheckSignals` when no signal is
+pending: the cheap flag checks are now done before the main-thread check and
+the remote debugger configuration lookup.
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index bc5aef55648e071..addf6b456b1f95c 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -1796,25 +1796,18 @@ PyErr_CheckSignals(void)
     _PyRunRemoteDebugger(tstate);
 #endif
 
-    if (_Py_ThreadCanHandleSignals(tstate->interp)) {
-        if (_PyErr_CheckSignalsTstate(tstate) < 0) {
-            return -1;
-        }
+    if (_PyErr_CheckSignalsTstate(tstate) < 0) {
+        return -1;
     }
 
     return 0;
 }
 
 
-/* Declared in cpython/pyerrors.h */
-int
-_PyErr_CheckSignalsTstate(PyThreadState *tstate)
+// Out of line, to keep the common case of _PyErr_CheckSignalsTstate() cheap.
+Py_NO_INLINE static int
+run_tripped_handlers(PyThreadState *tstate)
 {
-    _Py_CHECK_EMSCRIPTEN_SIGNALS();
-    if (!_Py_atomic_load_int(&is_tripped)) {
-        return 0;
-    }
-
     /*
      * The is_tripped variable is meant to speed up the calls to
      * PyErr_CheckSignals (both directly or via pending calls) when no
@@ -1895,6 +1888,20 @@ _PyErr_CheckSignalsTstate(PyThreadState *tstate)
 }
 
 
+/* Declared in pycore_pyerrors.h */
+int
+_PyErr_CheckSignalsTstate(PyThreadState *tstate)
+{
+    _Py_CHECK_EMSCRIPTEN_SIGNALS();
+    if (!_Py_atomic_load_int(&is_tripped)) {
+        return 0;
+    }
+    if (!_Py_ThreadCanHandleSignals(tstate->interp)) {
+        return 0;
+    }
+    return run_tripped_handlers(tstate);
+}
+
 
 int
 _PyErr_CheckSignals(void)
diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c
index 49b2ede4ed3e60f..91c75cdd2ed4133 100644
--- a/Python/ceval_gil.c
+++ b/Python/ceval_gil.c
@@ -830,9 +830,6 @@ handle_signals(PyThreadState *tstate)
 {
     assert(_PyThreadState_CheckConsistency(tstate));
     _Py_unset_eval_breaker_bit(tstate, _PY_SIGNALS_PENDING_BIT);
-    if (!_Py_ThreadCanHandleSignals(tstate->interp)) {
-        return 0;
-    }
     if (_PyErr_CheckSignalsTstate(tstate) < 0) {
         /* On failure, re-schedule a call to handle_signals(). */
         _Py_set_eval_breaker_bit(tstate, _PY_SIGNALS_PENDING_BIT);
@@ -1258,10 +1255,11 @@ static inline void run_remote_debugger_script(PyObject 
*path)
 
 int _PyRunRemoteDebugger(PyThreadState *tstate)
 {
+    if (tstate->remote_debugger_support.debugger_pending_call != 1) {
+        return 0;
+    }
     const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
-    if (config->remote_debug == 1
-         && tstate->remote_debugger_support.debugger_pending_call == 1)
-    {
+    if (config->remote_debug == 1) {
         tstate->remote_debugger_support.debugger_pending_call = 0;
 
         // Immediately make a copy in case of a race with another debugger

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to