mirror of
https://github.com/python/cpython.git
synced 2025-10-09 16:34:44 +00:00
gh-116522: Refactor _PyThreadState_DeleteExcept
(#117131)
Split `_PyThreadState_DeleteExcept` into two functions: - `_PyThreadState_RemoveExcept` removes all thread states other than one passed as an argument. It returns the removed thread states as a linked list. - `_PyThreadState_DeleteList` deletes those dead thread states. It may call destructors, so we want to "start the world" before calling `_PyThreadState_DeleteList` to avoid potential deadlocks.
This commit is contained in:
parent
50369e6c34
commit
1f72fb5447
5 changed files with 41 additions and 23 deletions
|
@ -1763,15 +1763,17 @@ PyThreadState_DeleteCurrent(void)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete all thread states except the one passed as argument.
|
||||
* Note that, if there is a current thread state, it *must* be the one
|
||||
* passed as argument. Also, this won't touch any other interpreters
|
||||
* than the current one, since we don't know which thread state should
|
||||
* be kept in those other interpreters.
|
||||
*/
|
||||
void
|
||||
_PyThreadState_DeleteExcept(PyThreadState *tstate)
|
||||
// Unlinks and removes all thread states from `tstate->interp`, with the
|
||||
// exception of the one passed as an argument. However, it does not delete
|
||||
// these thread states. Instead, it returns the removed thread states as a
|
||||
// linked list.
|
||||
//
|
||||
// Note that if there is a current thread state, it *must* be the one
|
||||
// passed as argument. Also, this won't touch any interpreters other
|
||||
// than the current one, since we don't know which thread state should
|
||||
// be kept in those other interpreters.
|
||||
PyThreadState *
|
||||
_PyThreadState_RemoveExcept(PyThreadState *tstate)
|
||||
{
|
||||
assert(tstate != NULL);
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
|
@ -1783,8 +1785,7 @@ _PyThreadState_DeleteExcept(PyThreadState *tstate)
|
|||
|
||||
HEAD_LOCK(runtime);
|
||||
/* Remove all thread states, except tstate, from the linked list of
|
||||
thread states. This will allow calling PyThreadState_Clear()
|
||||
without holding the lock. */
|
||||
thread states. */
|
||||
PyThreadState *list = interp->threads.head;
|
||||
if (list == tstate) {
|
||||
list = tstate->next;
|
||||
|
@ -1799,11 +1800,19 @@ _PyThreadState_DeleteExcept(PyThreadState *tstate)
|
|||
interp->threads.head = tstate;
|
||||
HEAD_UNLOCK(runtime);
|
||||
|
||||
_PyEval_StartTheWorldAll(runtime);
|
||||
return list;
|
||||
}
|
||||
|
||||
// Deletes the thread states in the linked list `list`.
|
||||
//
|
||||
// This is intended to be used in conjunction with _PyThreadState_RemoveExcept.
|
||||
void
|
||||
_PyThreadState_DeleteList(PyThreadState *list)
|
||||
{
|
||||
// The world can't be stopped because we PyThreadState_Clear() can
|
||||
// call destructors.
|
||||
assert(!_PyRuntime.stoptheworld.world_stopped);
|
||||
|
||||
/* Clear and deallocate all stale thread states. Even if this
|
||||
executes Python code, we should be safe since it executes
|
||||
in the current thread, not one of the stale threads. */
|
||||
PyThreadState *p, *next;
|
||||
for (p = list; p; p = next) {
|
||||
next = p->next;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue