changeset: 100526:6391cfbf5d25 tag: tip user: Victor Stinner date: Mon Mar 14 15:40:14 2016 +0100 files: Include/pystate.h Parser/pgenmain.c Python/fileutils.c Python/pylifecycle.c Python/pystate.c description: Issue #26558: add more checks on the GIL * PyGILState_Check() now returns 1 (success) before the creation of the GIL and after the destruction of the GIL * Add a flag to disable PyGILState_Check(). Disable PyGILState_Check() when Py_NewInterpreter() is called * Add assert(PyGILState_Check()) to: - _Py_dup() - _Py_fstat() - _Py_read() - _Py_write() diff -r c24630367767 -r 6391cfbf5d25 Include/pystate.h --- a/Include/pystate.h Mon Mar 14 16:53:12 2016 +0100 +++ b/Include/pystate.h Mon Mar 14 15:40:14 2016 +0100 @@ -247,6 +247,10 @@ PyAPI_FUNC(PyThreadState *) PyGILState_G * currently holds the GIL, 0 otherwise */ #ifndef Py_LIMITED_API +/* Issue #26558: Flag to disable PyGILState_Check(). + If set, PyGILState_Check() always return 1. */ +PyAPI_DATA(int) _PyGILState_check_enabled; + PyAPI_FUNC(int) PyGILState_Check(void); #endif diff -r c24630367767 -r 6391cfbf5d25 Parser/pgenmain.c --- a/Parser/pgenmain.c Mon Mar 14 16:53:12 2016 +0100 +++ b/Parser/pgenmain.c Mon Mar 14 15:40:14 2016 +0100 @@ -37,6 +37,14 @@ Py_Exit(int sts) exit(sts); } +#ifdef WITH_THREAD +/* Needed by obmalloc.c */ +int PyGILState_Check(void) +{ + return 1; +} +#endif + int main(int argc, char **argv) { diff -r c24630367767 -r 6391cfbf5d25 Python/fileutils.c --- a/Python/fileutils.c Mon Mar 14 16:53:12 2016 +0100 +++ b/Python/fileutils.c Mon Mar 14 15:40:14 2016 +0100 @@ -683,6 +683,10 @@ int { int res; +#ifdef WITH_THREAD + assert(PyGILState_Check()); +#endif + Py_BEGIN_ALLOW_THREADS res = _Py_fstat_noraise(fd, status); Py_END_ALLOW_THREADS @@ -1164,6 +1168,10 @@ Py_ssize_t int err; int async_err = 0; +#ifdef WITH_THREAD + assert(PyGILState_Check()); +#endif + /* _Py_read() must not be called with an exception set, otherwise the * caller may think that read() was interrupted by a signal and the signal * handler raised an exception. */ @@ -1319,6 +1327,10 @@ static Py_ssize_t Py_ssize_t _Py_write(int fd, const void *buf, size_t count) { +#ifdef WITH_THREAD + assert(PyGILState_Check()); +#endif + /* _Py_write() must not be called with an exception set, otherwise the * caller may think that write() was interrupted by a signal and the signal * handler raised an exception. */ @@ -1468,6 +1480,10 @@ int DWORD ftype; #endif +#ifdef WITH_THREAD + assert(PyGILState_Check()); +#endif + if (!_PyVerify_fd(fd)) { PyErr_SetFromErrno(PyExc_OSError); return -1; diff -r c24630367767 -r 6391cfbf5d25 Python/pylifecycle.c --- a/Python/pylifecycle.c Mon Mar 14 16:53:12 2016 +0100 +++ b/Python/pylifecycle.c Mon Mar 14 15:40:14 2016 +0100 @@ -326,6 +326,9 @@ void Py_FatalError("Py_Initialize: can't make first thread"); (void) PyThreadState_Swap(tstate); + /* Python GIL is ready: we can start to check the GIL */ + _PyGILState_check_enabled = 1; + #ifdef WITH_THREAD /* We can't call _PyEval_FiniThreads() in Py_FinalizeEx because destroying the GIL might fail when it is being referenced from @@ -692,6 +695,7 @@ Py_FinalizeEx(void) /* Delete current thread. After this, many C API calls become crashy. */ PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); #ifdef Py_TRACE_REFS @@ -743,6 +747,10 @@ Py_NewInterpreter(void) if (!initialized) Py_FatalError("Py_NewInterpreter: call Py_Initialize first"); + /* Issue #26558: Disable PyGILState_Check() when multiple interpreters + are used. */ + _PyGILState_check_enabled = 0; + interp = PyInterpreterState_New(); if (interp == NULL) return NULL; diff -r c24630367767 -r 6391cfbf5d25 Python/pystate.c --- a/Python/pystate.c Mon Mar 14 16:53:12 2016 +0100 +++ b/Python/pystate.c Mon Mar 14 15:40:14 2016 +0100 @@ -34,6 +34,8 @@ to avoid the expense of doing their own extern "C" { #endif +int _PyGILState_check_enabled = 1; + #ifdef WITH_THREAD #include "pythread.h" static PyThread_type_lock head_mutex = NULL; /* Protects interp->tstate_head */ @@ -45,7 +47,7 @@ static PyThread_type_lock head_mutex = N GILState implementation */ static PyInterpreterState *autoInterpreterState = NULL; -static int autoTLSkey = 0; +static int autoTLSkey = -1; #else #define HEAD_INIT() /* Nothing */ #define HEAD_LOCK() /* Nothing */ @@ -449,10 +451,10 @@ PyThreadState_DeleteCurrent() if (tstate == NULL) Py_FatalError( "PyThreadState_DeleteCurrent: no current tstate"); - SET_TSTATE(NULL); + tstate_delete_common(tstate); if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) PyThread_delete_key_value(autoTLSkey); - tstate_delete_common(tstate); + SET_TSTATE(NULL); PyEval_ReleaseLock(); } #endif /* WITH_THREAD */ @@ -716,6 +718,7 @@ void _PyGILState_Fini(void) { PyThread_delete_key(autoTLSkey); + autoTLSkey = -1; autoInterpreterState = NULL; } @@ -784,8 +787,19 @@ PyGILState_GetThisThreadState(void) int PyGILState_Check(void) { - PyThreadState *tstate = GET_TSTATE(); - return tstate && (tstate == PyGILState_GetThisThreadState()); + PyThreadState *tstate; + + if (!_PyGILState_check_enabled) + return 1; + + if (autoTLSkey == -1) + return 1; + + tstate = GET_TSTATE(); + if (tstate == NULL) + return 0; + + return (tstate == PyGILState_GetThisThreadState()); } PyGILState_STATE