Skip to content

Commit 3d9dc83

Browse files
fix deadlock
1 parent 2d9f252 commit 3d9dc83

File tree

1 file changed

+13
-11
lines changed

1 file changed

+13
-11
lines changed

Python/pystate.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,12 @@ new_threadstate(PyInterpreterState *interp)
810810
{
811811
PyThreadState *tstate;
812812
_PyRuntimeState *runtime = interp->runtime;
813-
813+
// Allocate eagerly without lock
814+
PyThreadState *new_tstate = alloc_threadstate();
815+
int used_newtstate;
816+
if (new_tstate == NULL) {
817+
return NULL;
818+
}
814819
/* We serialize concurrent creation to protect global state. */
815820
HEAD_LOCK(runtime);
816821

@@ -822,18 +827,15 @@ new_threadstate(PyInterpreterState *interp)
822827
if (old_head == NULL) {
823828
// It's the interpreter's initial thread state.
824829
assert(id == 1);
825-
830+
used_newtstate = 0;
826831
tstate = &interp->_initial_thread;
827832
}
828833
else {
829834
// Every valid interpreter must have at least one thread.
830835
assert(id > 1);
831836
assert(old_head->prev == NULL);
832-
833-
tstate = alloc_threadstate();
834-
if (tstate == NULL) {
835-
goto error;
836-
}
837+
used_newtstate = 1;
838+
tstate = new_tstate;
837839
// Set to _PyThreadState_INIT.
838840
memcpy(tstate,
839841
&initial._main_interpreter._initial_thread,
@@ -844,11 +846,11 @@ new_threadstate(PyInterpreterState *interp)
844846
init_threadstate(tstate, interp, id, old_head);
845847

846848
HEAD_UNLOCK(runtime);
849+
if (!used_newtstate) {
850+
// Must be called with lock unlocked to avoid re-entrancy deadlock.
851+
PyMem_RawFree(new_tstate);
852+
}
847853
return tstate;
848-
849-
error:
850-
HEAD_UNLOCK(runtime);
851-
return NULL;
852854
}
853855

854856
PyThreadState *

0 commit comments

Comments
 (0)