(original) (raw)
changeset: 100537:e590c632c9fa user: Victor Stinner victor.stinner@gmail.com date: Mon Mar 14 22:07:55 2016 +0100 files: Include/pystate.h Parser/pgenmain.c Python/fileutils.c Python/pylifecycle.c Python/pystate.c description: Add more checks on the GIL Issue #10915, #15751, #26558: * PyGILState_Check() now returns 1 (success) before the creation of the GIL and after the destruction of the GIL. It allows to use the function early in Python initialization and late in Python finalization. * 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() and _Py_write() diff -r 7534eb7bd57e -r e590c632c9fa Include/pystate.h --- a/Include/pystate.h Mon Mar 14 21:55:43 2016 +0100 +++ b/Include/pystate.h Mon Mar 14 22:07:55 2016 +0100 @@ -247,6 +247,10 @@ * 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 7534eb7bd57e -r e590c632c9fa Parser/pgenmain.c --- a/Parser/pgenmain.c Mon Mar 14 21:55:43 2016 +0100 +++ b/Parser/pgenmain.c Mon Mar 14 22:07:55 2016 +0100 @@ -37,6 +37,14 @@ exit(sts); } +#ifdef WITH_THREAD +/* Needed by obmalloc.c */ +int PyGILState_Check(void) +{ + return 1; +} +#endif + int main(int argc, char **argv) { diff -r 7534eb7bd57e -r e590c632c9fa Python/fileutils.c --- a/Python/fileutils.c Mon Mar 14 21:55:43 2016 +0100 +++ b/Python/fileutils.c Mon Mar 14 22:07:55 2016 +0100 @@ -683,6 +683,10 @@ { 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 @@ 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 @@ 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 @@ DWORD ftype; #endif +#ifdef WITH_THREAD + assert(PyGILState_Check()); +#endif + if (!_PyVerify_fd(fd)) { PyErr_SetFromErrno(PyExc_OSError); return -1; diff -r 7534eb7bd57e -r e590c632c9fa Python/pylifecycle.c --- a/Python/pylifecycle.c Mon Mar 14 21:55:43 2016 +0100 +++ b/Python/pylifecycle.c Mon Mar 14 22:07:55 2016 +0100 @@ -692,6 +692,7 @@ /* Delete current thread. After this, many C API calls become crashy. */ PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); #ifdef Py_TRACE_REFS @@ -743,6 +744,10 @@ if (!initialized) Py_FatalError("Py_NewInterpreter: call Py_Initialize first"); + /* Issue #10915, #15751: The GIL API doesn't work with multiple + interpreters: disable PyGILState_Check(). */ + _PyGILState_check_enabled = 0; + interp = PyInterpreterState_New(); if (interp == NULL) return NULL; diff -r 7534eb7bd57e -r e590c632c9fa Python/pystate.c --- a/Python/pystate.c Mon Mar 14 21:55:43 2016 +0100 +++ b/Python/pystate.c Mon Mar 14 22:07:55 2016 +0100 @@ -34,6 +34,8 @@ 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 @@ 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 @@ 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 @@ _PyGILState_Fini(void) { PyThread_delete_key(autoTLSkey); + autoTLSkey = -1; autoInterpreterState = NULL; } @@ -784,8 +787,19 @@ 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 /victor.stinner@gmail.com