bpo-36475: Finalize PyEval_AcquireLock() and PyEval_AcquireThread() properly (GH-12667)

PyEval_AcquireLock() and PyEval_AcquireThread() now
terminate the current thread if called while the interpreter is
finalizing, making them consistent with PyEval_RestoreThread(),
Py_END_ALLOW_THREADS, and PyGILState_Ensure().
This commit is contained in:
Joannah Nanjekye 2019-04-29 04:38:45 -04:00 committed by Victor Stinner
parent 254b309c80
commit f781d202a2
4 changed files with 51 additions and 12 deletions

View file

@ -76,6 +76,7 @@ static PyObject * special_lookup(PyObject *, _Py_Identifier *);
static int check_args_iterable(PyObject *func, PyObject *vararg);
static void format_kwargs_error(PyObject *func, PyObject *kwargs);
static void format_awaitable_error(PyTypeObject *, int);
static inline void exit_thread_if_finalizing(PyThreadState *);
#define NAME_ERROR_MSG \
"name '%.200s' is not defined"
@ -203,6 +204,17 @@ _PyEval_FiniThreads(void)
}
}
static inline void
exit_thread_if_finalizing(PyThreadState *tstate)
{
/* _Py_Finalizing is protected by the GIL */
if (_Py_IsFinalizing() && !_Py_CURRENTLY_FINALIZING(tstate)) {
drop_gil(tstate);
PyThread_exit_thread();
Py_UNREACHABLE();
}
}
void
PyEval_AcquireLock(void)
{
@ -210,6 +222,7 @@ PyEval_AcquireLock(void)
if (tstate == NULL)
Py_FatalError("PyEval_AcquireLock: current thread state is NULL");
take_gil(tstate);
exit_thread_if_finalizing(tstate);
}
void
@ -230,6 +243,7 @@ PyEval_AcquireThread(PyThreadState *tstate)
/* Check someone has called PyEval_InitThreads() to create the lock */
assert(gil_created());
take_gil(tstate);
exit_thread_if_finalizing(tstate);
if (PyThreadState_Swap(tstate) != NULL)
Py_FatalError(
"PyEval_AcquireThread: non-NULL old thread state");
@ -298,12 +312,7 @@ PyEval_RestoreThread(PyThreadState *tstate)
int err = errno;
take_gil(tstate);
/* _Py_Finalizing is protected by the GIL */
if (_Py_IsFinalizing() && !_Py_CURRENTLY_FINALIZING(tstate)) {
drop_gil(tstate);
PyThread_exit_thread();
Py_UNREACHABLE();
}
exit_thread_if_finalizing(tstate);
errno = err;
PyThreadState_Swap(tstate);
@ -1083,12 +1092,7 @@ main_loop:
take_gil(tstate);
/* Check if we should make a quick exit. */
if (_Py_IsFinalizing() &&
!_Py_CURRENTLY_FINALIZING(tstate))
{
drop_gil(tstate);
PyThread_exit_thread();
}
exit_thread_if_finalizing(tstate);
if (PyThreadState_Swap(tstate) != NULL)
Py_FatalError("ceval: orphan tstate");