[Python-checkins] bpo-42296: On Windows, fix CTRL+C regression (GH-23257)

miss-islington webhook-mailer at python.org
Fri Nov 13 09:11:42 EST 2020


https://github.com/python/cpython/commit/e5729aef6ff67ae7ed05dffc0855477823826191
commit: e5729aef6ff67ae7ed05dffc0855477823826191
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2020年11月13日T06:11:38-08:00
summary:
bpo-42296: On Windows, fix CTRL+C regression (GH-23257)
On Windows, fix a regression in signal handling which prevented to
interrupt a program using CTRL+C. The signal handler can be run in a
thread different than the Python thread, in which case the test
deciding if the thread can handle signals is wrong.
On Windows, _PyEval_SignalReceived() now always sets eval_breaker to
1 since it cannot test _Py_ThreadCanHandleSignals(), and
 eval_frame_handle_pending() always calls
 _Py_ThreadCanHandleSignals() to recompute eval_breaker.
(cherry picked from commit d96a7a83133250377219227b5cfab4dbdddc5d3a)
Co-authored-by: Victor Stinner <vstinner at python.org>
files:
A Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst
M Python/ceval.c
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst
new file mode 100644
index 0000000000000..841a26e791ea0
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-13-13-53-11.bpo-42296.DuGrLJ.rst	
@@ -0,0 +1,4 @@
+On Windows, fix a regression in signal handling which prevented to interrupt
+a program using CTRL+C. The signal handler can be run in a thread different
+than the Python thread, in which case the test deciding if the thread can
+handle signals is wrong.
diff --git a/Python/ceval.c b/Python/ceval.c
index 3392cd0365a28..91e879e804204 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -196,13 +196,18 @@ UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp)
 
 
 static inline void
-SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp)
+SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp, int force)
 {
 struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
 struct _ceval_state *ceval2 = &interp->ceval;
 _Py_atomic_store_relaxed(&ceval->signals_pending, 1);
- /* eval_breaker is not set to 1 if thread_can_handle_signals() is false */
- COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
+ if (force) {
+ _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1);
+ }
+ else {
+ /* eval_breaker is not set to 1 if thread_can_handle_signals() is false */
+ COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
+ }
 }
 
 
@@ -491,10 +496,22 @@ PyEval_RestoreThread(PyThreadState *tstate)
 void
 _PyEval_SignalReceived(PyInterpreterState *interp)
 {
+#ifdef MS_WINDOWS
+ // bpo-42296: On Windows, _PyEval_SignalReceived() is called from a signal
+ // handler which can run in a thread different than the Python thread, in
+ // which case _Py_ThreadCanHandleSignals() is wrong. Ignore
+ // _Py_ThreadCanHandleSignals() and always set eval_breaker to 1.
+ //
+ // The next eval_frame_handle_pending() call will call
+ // _Py_ThreadCanHandleSignals() to recompute eval_breaker.
+ int force = 1;
+#else
+ int force = 0;
+#endif
 /* bpo-30703: Function called when the C signal handler of Python gets a
 signal. We cannot queue a callback using _PyEval_AddPendingCall() since
 that function is not async-signal-safe. */
- SIGNAL_PENDING_SIGNALS(interp);
+ SIGNAL_PENDING_SIGNALS(interp, force);
 }
 
 /* Push one item onto the queue while holding the lock. */
@@ -594,7 +611,7 @@ handle_signals(PyThreadState *tstate)
 UNSIGNAL_PENDING_SIGNALS(tstate->interp);
 if (_PyErr_CheckSignalsTstate(tstate) < 0) {
 /* On failure, re-schedule a call to handle_signals(). */
- SIGNAL_PENDING_SIGNALS(tstate->interp);
+ SIGNAL_PENDING_SIGNALS(tstate->interp, 0);
 return -1;
 }
 return 0;
@@ -883,6 +900,17 @@ eval_frame_handle_pending(PyThreadState *tstate)
 return -1;
 }
 
+#ifdef MS_WINDOWS
+ // bpo-42296: On Windows, _PyEval_SignalReceived() can be called in a
+ // different thread than the Python thread, in which case
+ // _Py_ThreadCanHandleSignals() is wrong. Recompute eval_breaker in the
+ // current Python thread with the correct _Py_ThreadCanHandleSignals()
+ // value. It prevents to interrupt the eval loop at every instruction if
+ // the current Python thread cannot handle signals (if
+ // _Py_ThreadCanHandleSignals() is false).
+ COMPUTE_EVAL_BREAKER(tstate->interp, ceval, ceval2);
+#endif
+
 return 0;
 }
 


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /