[Python-checkins] bpo-39984: trip_signal() uses PyGILState_GetThisThreadState() (GH-19061)

Victor Stinner webhook-mailer at python.org
Wed Mar 18 14:28:58 EDT 2020


https://github.com/python/cpython/commit/8849e5962ba481d5d414b3467a256aba2134b4da
commit: 8849e5962ba481d5d414b3467a256aba2134b4da
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-03-18T19:28:53+01:00
summary:

bpo-39984: trip_signal() uses PyGILState_GetThisThreadState() (GH-19061)

bpo-37127, bpo-39984:

* trip_signal() and Py_AddPendingCall() now get the current Python
  thread state using PyGILState_GetThisThreadState() rather than
  _PyRuntimeState_GetThreadState() to be able to get it even if the
  GIL is released.
* _PyEval_SignalReceived() now expects tstate rather than ceval.
* Remove ceval parameter of _PyEval_AddPendingCall(): ceval is now
  get from tstate parameter.

files:
M Include/internal/pycore_ceval.h
M Modules/signalmodule.c
M Python/ceval.c

diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index 4e5ae17d63d68..ccfb9abed7244 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -19,11 +19,9 @@ extern void _Py_FinishPendingCalls(PyThreadState *tstate);
 extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *);
 extern void _PyEval_InitState(struct _ceval_state *);
 extern void _PyEval_FiniThreads(PyThreadState *tstate);
-PyAPI_FUNC(void) _PyEval_SignalReceived(
-    struct _ceval_runtime_state *ceval);
+PyAPI_FUNC(void) _PyEval_SignalReceived(PyThreadState *tstate);
 PyAPI_FUNC(int) _PyEval_AddPendingCall(
     PyThreadState *tstate,
-    struct _ceval_runtime_state *ceval,
     int (*func)(void *),
     void *arg);
 PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyThreadState *tstate);
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index a197673746240..10285313967b5 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -259,10 +259,14 @@ trip_signal(int sig_num)
        cleared in PyErr_CheckSignals() before .tripped. */
     _Py_atomic_store(&is_tripped, 1);
 
+    /* Get the Python thread state using PyGILState API, since
+       _PyThreadState_GET() returns NULL if the GIL is released.
+       For example, signal.raise_signal() releases the GIL. */
+    PyThreadState *tstate = PyGILState_GetThisThreadState();
+    assert(tstate != NULL);
+
     /* Notify ceval.c */
-    _PyRuntimeState *runtime = &_PyRuntime;
-    PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
-    _PyEval_SignalReceived(&runtime->ceval);
+    _PyEval_SignalReceived(tstate);
 
     /* And then write to the wakeup fd *after* setting all the globals and
        doing the _PyEval_SignalReceived. We used to write to the wakeup fd
@@ -302,7 +306,7 @@ trip_signal(int sig_num)
                 {
                     /* Py_AddPendingCall() isn't signal-safe, but we
                        still use it for this exceptional case. */
-                    _PyEval_AddPendingCall(tstate, &runtime->ceval,
+                    _PyEval_AddPendingCall(tstate,
                                            report_wakeup_send_error,
                                            (void *)(intptr_t) last_error);
                 }
@@ -321,7 +325,7 @@ trip_signal(int sig_num)
                 {
                     /* Py_AddPendingCall() isn't signal-safe, but we
                        still use it for this exceptional case. */
-                    _PyEval_AddPendingCall(tstate, &runtime->ceval,
+                    _PyEval_AddPendingCall(tstate,
                                            report_wakeup_write_error,
                                            (void *)(intptr_t)errno);
                 }
diff --git a/Python/ceval.c b/Python/ceval.c
index 8958e1445db6b..2f65ea28e7abf 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -436,8 +436,9 @@ PyEval_RestoreThread(PyThreadState *tstate)
 */
 
 void
-_PyEval_SignalReceived(struct _ceval_runtime_state *ceval)
+_PyEval_SignalReceived(PyThreadState *tstate)
 {
+    struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
     /* bpo-30703: Function called when the C signal handler of Python gets a
        signal. We cannot queue a callback using Py_AddPendingCall() since
        that function is not async-signal-safe. */
@@ -482,9 +483,9 @@ _pop_pending_call(struct _pending_calls *pending,
 
 int
 _PyEval_AddPendingCall(PyThreadState *tstate,
-                       struct _ceval_runtime_state *ceval,
                        int (*func)(void *), void *arg)
 {
+    struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
     struct _pending_calls *pending = &ceval->pending;
 
     PyThread_acquire_lock(pending->lock, WAIT_LOCK);
@@ -511,9 +512,12 @@ _PyEval_AddPendingCall(PyThreadState *tstate,
 int
 Py_AddPendingCall(int (*func)(void *), void *arg)
 {
-    _PyRuntimeState *runtime = &_PyRuntime;
-    PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
-    return _PyEval_AddPendingCall(tstate, &runtime->ceval, func, arg);
+    /* Get the Python thread state using PyGILState API, since
+       _PyThreadState_GET() returns NULL if the GIL is released.
+       Py_AddPendingCall() doesn't require the caller to hold the GIL. */
+    PyThreadState *tstate = PyGILState_GetThisThreadState();
+    assert(tstate != NULL);
+    return _PyEval_AddPendingCall(tstate, func, arg);
 }
 
 static int



More information about the Python-checkins mailing list