mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
GH-96071: fix deadlock in PyGILState_Ensure (GH-96124)
Alternative of #96107
This commit is contained in:
parent
822955c166
commit
e0d54a4a79
2 changed files with 17 additions and 11 deletions
|
@ -0,0 +1 @@
|
||||||
|
Fix a deadlock in :c:func:`PyGILState_Ensure` when allocating new thread state. Patch by Kumar Aditya.
|
|
@ -810,7 +810,15 @@ new_threadstate(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate;
|
PyThreadState *tstate;
|
||||||
_PyRuntimeState *runtime = interp->runtime;
|
_PyRuntimeState *runtime = interp->runtime;
|
||||||
|
// We don't need to allocate a thread state for the main interpreter
|
||||||
|
// (the common case), but doing it later for the other case revealed a
|
||||||
|
// reentrancy problem (deadlock). So for now we always allocate before
|
||||||
|
// taking the interpreters lock. See GH-96071.
|
||||||
|
PyThreadState *new_tstate = alloc_threadstate();
|
||||||
|
int used_newtstate;
|
||||||
|
if (new_tstate == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
/* We serialize concurrent creation to protect global state. */
|
/* We serialize concurrent creation to protect global state. */
|
||||||
HEAD_LOCK(runtime);
|
HEAD_LOCK(runtime);
|
||||||
|
|
||||||
|
@ -822,18 +830,15 @@ new_threadstate(PyInterpreterState *interp)
|
||||||
if (old_head == NULL) {
|
if (old_head == NULL) {
|
||||||
// It's the interpreter's initial thread state.
|
// It's the interpreter's initial thread state.
|
||||||
assert(id == 1);
|
assert(id == 1);
|
||||||
|
used_newtstate = 0;
|
||||||
tstate = &interp->_initial_thread;
|
tstate = &interp->_initial_thread;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Every valid interpreter must have at least one thread.
|
// Every valid interpreter must have at least one thread.
|
||||||
assert(id > 1);
|
assert(id > 1);
|
||||||
assert(old_head->prev == NULL);
|
assert(old_head->prev == NULL);
|
||||||
|
used_newtstate = 1;
|
||||||
tstate = alloc_threadstate();
|
tstate = new_tstate;
|
||||||
if (tstate == NULL) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
// Set to _PyThreadState_INIT.
|
// Set to _PyThreadState_INIT.
|
||||||
memcpy(tstate,
|
memcpy(tstate,
|
||||||
&initial._main_interpreter._initial_thread,
|
&initial._main_interpreter._initial_thread,
|
||||||
|
@ -844,11 +849,11 @@ new_threadstate(PyInterpreterState *interp)
|
||||||
init_threadstate(tstate, interp, id, old_head);
|
init_threadstate(tstate, interp, id, old_head);
|
||||||
|
|
||||||
HEAD_UNLOCK(runtime);
|
HEAD_UNLOCK(runtime);
|
||||||
|
if (!used_newtstate) {
|
||||||
|
// Must be called with lock unlocked to avoid re-entrancy deadlock.
|
||||||
|
PyMem_RawFree(new_tstate);
|
||||||
|
}
|
||||||
return tstate;
|
return tstate;
|
||||||
|
|
||||||
error:
|
|
||||||
HEAD_UNLOCK(runtime);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyThreadState *
|
PyThreadState *
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue