diff options
author | Victor Stinner <vstinner@python.org> | 2020-11-13 14:44:42 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-13 14:44:42 +0100 |
commit | d96a7a83133250377219227b5cfab4dbdddc5d3a (patch) | |
tree | 5f040cee144aa498889578d7a1ef12d9751c7f89 /Python/ceval.c | |
parent | bpo-38823: Fix compiler warning in _ctypes on Windows (GH-23258) (diff) | |
download | cpython-d96a7a83133250377219227b5cfab4dbdddc5d3a.tar.gz cpython-d96a7a83133250377219227b5cfab4dbdddc5d3a.tar.bz2 cpython-d96a7a83133250377219227b5cfab4dbdddc5d3a.zip |
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.
Diffstat (limited to 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index d6b786dc2cd..3d65e161302 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -203,13 +203,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); + } } @@ -559,10 +564,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. */ @@ -662,7 +679,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; @@ -948,6 +965,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; } |