Skip to content

Commit f28dfdd

Browse files
committed
Issue #17912: Use a doubly linked-list for thread states.
1 parent 04e70d1 commit f28dfdd

File tree

2 files changed

+18
-41
lines changed

2 files changed

+18
-41
lines changed

Include/pystate.h

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ typedef struct _ts PyThreadState;
6969
typedef struct _ts {
7070
/* See Python/ceval.c for comments explaining most fields */
7171

72+
struct _ts *prev;
7273
struct _ts *next;
7374
PyInterpreterState *interp;
7475

Python/pystate.c

+17-41
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,10 @@ new_threadstate(PyInterpreterState *interp, int init)
213213
_PyThreadState_Init(tstate);
214214

215215
HEAD_LOCK();
216+
tstate->prev = NULL;
216217
tstate->next = interp->tstate_head;
218+
if (tstate->next)
219+
tstate->next->prev = tstate;
217220
interp->tstate_head = tstate;
218221
HEAD_UNLOCK();
219222
}
@@ -349,35 +352,18 @@ static void
349352
tstate_delete_common(PyThreadState *tstate)
350353
{
351354
PyInterpreterState *interp;
352-
PyThreadState **p;
353-
PyThreadState *prev_p = NULL;
354355
if (tstate == NULL)
355356
Py_FatalError("PyThreadState_Delete: NULL tstate");
356357
interp = tstate->interp;
357358
if (interp == NULL)
358359
Py_FatalError("PyThreadState_Delete: NULL interp");
359360
HEAD_LOCK();
360-
for (p = &interp->tstate_head; ; p = &(*p)->next) {
361-
if (*p == NULL)
362-
Py_FatalError(
363-
"PyThreadState_Delete: invalid tstate");
364-
if (*p == tstate)
365-
break;
366-
/* Sanity check. These states should never happen but if
367-
* they do we must abort. Otherwise we'll end up spinning in
368-
* in a tight loop with the lock held. A similar check is done
369-
* in thread.c find_key(). */
370-
if (*p == prev_p)
371-
Py_FatalError(
372-
"PyThreadState_Delete: small circular list(!)"
373-
" and tstate not found.");
374-
prev_p = *p;
375-
if ((*p)->next == interp->tstate_head)
376-
Py_FatalError(
377-
"PyThreadState_Delete: circular list(!) and"
378-
" tstate not found.");
379-
}
380-
*p = tstate->next;
361+
if (tstate->prev)
362+
tstate->prev->next = tstate->next;
363+
else
364+
interp->tstate_head = tstate->next;
365+
if (tstate->next)
366+
tstate->next->prev = tstate->prev;
381367
HEAD_UNLOCK();
382368
free(tstate);
383369
}
@@ -429,26 +415,16 @@ _PyThreadState_DeleteExcept(PyThreadState *tstate)
429415
HEAD_LOCK();
430416
/* Remove all thread states, except tstate, from the linked list of
431417
thread states. This will allow calling PyThreadState_Clear()
432-
without holding the lock.
433-
XXX This would be simpler with a doubly-linked list. */
418+
without holding the lock. */
434419
garbage = interp->tstate_head;
420+
if (garbage == tstate)
421+
garbage = tstate->next;
422+
if (tstate->prev)
423+
tstate->prev->next = tstate->next;
424+
if (tstate->next)
425+
tstate->next->prev = tstate->prev;
426+
tstate->prev = tstate->next = NULL;
435427
interp->tstate_head = tstate;
436-
if (garbage == tstate) {
437-
garbage = garbage->next;
438-
tstate->next = NULL;
439-
}
440-
else {
441-
for (p = garbage; p; p = p->next) {
442-
if (p->next == tstate) {
443-
p->next = tstate->next;
444-
tstate->next = NULL;
445-
break;
446-
}
447-
}
448-
}
449-
if (tstate->next != NULL)
450-
Py_FatalError("_PyThreadState_DeleteExcept: tstate not found "
451-
"in interpreter thread states");
452428
HEAD_UNLOCK();
453429
/* Clear and deallocate all stale thread states. Even if this
454430
executes Python code, we should be safe since it executes

0 commit comments

Comments
 (0)