Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8a1be61

Browse files
committed
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()
1 parent 08572f6 commit 8a1be61

5 files changed

Lines changed: 52 additions & 5 deletions

File tree

Include/pystate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,10 @@ PyAPI_FUNC(PyThreadState *) PyGILState_GetThisThreadState(void);
247247
* currently holds the GIL, 0 otherwise
248248
*/
249249
#ifndef Py_LIMITED_API
250+
/* Issue #26558: Flag to disable PyGILState_Check().
251+
If set, PyGILState_Check() always return 1. */
252+
PyAPI_DATA(int) _PyGILState_check_enabled;
253+
250254
PyAPI_FUNC(int) PyGILState_Check(void);
251255
#endif
252256

Parser/pgenmain.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ Py_Exit(int sts)
3737
exit(sts);
3838
}
3939

40+
#ifdef WITH_THREAD
41+
/* Needed by obmalloc.c */
42+
int PyGILState_Check(void)
43+
{
44+
return 1;
45+
}
46+
#endif
47+
4048
int
4149
main(int argc, char **argv)
4250
{

Python/fileutils.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,10 @@ _Py_fstat(int fd, struct _Py_stat_struct *status)
683683
{
684684
int res;
685685

686+
#ifdef WITH_THREAD
687+
assert(PyGILState_Check());
688+
#endif
689+
686690
Py_BEGIN_ALLOW_THREADS
687691
res = _Py_fstat_noraise(fd, status);
688692
Py_END_ALLOW_THREADS
@@ -1164,6 +1168,10 @@ _Py_read(int fd, void *buf, size_t count)
11641168
int err;
11651169
int async_err = 0;
11661170

1171+
#ifdef WITH_THREAD
1172+
assert(PyGILState_Check());
1173+
#endif
1174+
11671175
/* _Py_read() must not be called with an exception set, otherwise the
11681176
* caller may think that read() was interrupted by a signal and the signal
11691177
* handler raised an exception. */
@@ -1319,6 +1327,10 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
13191327
Py_ssize_t
13201328
_Py_write(int fd, const void *buf, size_t count)
13211329
{
1330+
#ifdef WITH_THREAD
1331+
assert(PyGILState_Check());
1332+
#endif
1333+
13221334
/* _Py_write() must not be called with an exception set, otherwise the
13231335
* caller may think that write() was interrupted by a signal and the signal
13241336
* handler raised an exception. */
@@ -1468,6 +1480,10 @@ _Py_dup(int fd)
14681480
DWORD ftype;
14691481
#endif
14701482

1483+
#ifdef WITH_THREAD
1484+
assert(PyGILState_Check());
1485+
#endif
1486+
14711487
if (!_PyVerify_fd(fd)) {
14721488
PyErr_SetFromErrno(PyExc_OSError);
14731489
return -1;

Python/pylifecycle.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ Py_FinalizeEx(void)
692692

693693
/* Delete current thread. After this, many C API calls become crashy. */
694694
PyThreadState_Swap(NULL);
695+
695696
PyInterpreterState_Delete(interp);
696697

697698
#ifdef Py_TRACE_REFS
@@ -743,6 +744,10 @@ Py_NewInterpreter(void)
743744
if (!initialized)
744745
Py_FatalError("Py_NewInterpreter: call Py_Initialize first");
745746

747+
/* Issue #10915, #15751: The GIL API doesn't work with multiple
748+
interpreters: disable PyGILState_Check(). */
749+
_PyGILState_check_enabled = 0;
750+
746751
interp = PyInterpreterState_New();
747752
if (interp == NULL)
748753
return NULL;

Python/pystate.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ to avoid the expense of doing their own locking).
3434
extern "C" {
3535
#endif
3636

37+
int _PyGILState_check_enabled = 1;
38+
3739
#ifdef WITH_THREAD
3840
#include "pythread.h"
3941
static PyThread_type_lock head_mutex = NULL; /* Protects interp->tstate_head */
@@ -45,7 +47,7 @@ static PyThread_type_lock head_mutex = NULL; /* Protects interp->tstate_head */
4547
GILState implementation
4648
*/
4749
static PyInterpreterState *autoInterpreterState = NULL;
48-
static int autoTLSkey = 0;
50+
static int autoTLSkey = -1;
4951
#else
5052
#define HEAD_INIT() /* Nothing */
5153
#define HEAD_LOCK() /* Nothing */
@@ -449,10 +451,10 @@ PyThreadState_DeleteCurrent()
449451
if (tstate == NULL)
450452
Py_FatalError(
451453
"PyThreadState_DeleteCurrent: no current tstate");
452-
SET_TSTATE(NULL);
454+
tstate_delete_common(tstate);
453455
if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate)
454456
PyThread_delete_key_value(autoTLSkey);
455-
tstate_delete_common(tstate);
457+
SET_TSTATE(NULL);
456458
PyEval_ReleaseLock();
457459
}
458460
#endif /* WITH_THREAD */
@@ -716,6 +718,7 @@ void
716718
_PyGILState_Fini(void)
717719
{
718720
PyThread_delete_key(autoTLSkey);
721+
autoTLSkey = -1;
719722
autoInterpreterState = NULL;
720723
}
721724

@@ -784,8 +787,19 @@ PyGILState_GetThisThreadState(void)
784787
int
785788
PyGILState_Check(void)
786789
{
787-
PyThreadState *tstate = GET_TSTATE();
788-
return tstate && (tstate == PyGILState_GetThisThreadState());
790+
PyThreadState *tstate;
791+
792+
if (!_PyGILState_check_enabled)
793+
return 1;
794+
795+
if (autoTLSkey == -1)
796+
return 1;
797+
798+
tstate = GET_TSTATE();
799+
if (tstate == NULL)
800+
return 0;
801+
802+
return (tstate == PyGILState_GetThisThreadState());
789803
}
790804

791805
PyGILState_STATE

0 commit comments

Comments
 (0)