mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
Issue #17094: Clear stale thread states after fork().
Note that this is a potentially disruptive change since it may release some system resources which would otherwise remain perpetually alive (e.g. database connections kept in thread-local storage).
This commit is contained in:
parent
39b17c513a
commit
8408cea0cd
5 changed files with 88 additions and 8 deletions
|
@ -362,29 +362,28 @@ PyEval_ReleaseThread(PyThreadState *tstate)
|
|||
drop_gil(tstate);
|
||||
}
|
||||
|
||||
/* This function is called from PyOS_AfterFork to ensure that newly
|
||||
created child processes don't hold locks referring to threads which
|
||||
are not running in the child process. (This could also be done using
|
||||
pthread_atfork mechanism, at least for the pthreads implementation.) */
|
||||
/* This function is called from PyOS_AfterFork to destroy all threads which are
|
||||
* not running in the child process, and clear internal locks which might be
|
||||
* held by those threads. (This could also be done using pthread_atfork
|
||||
* mechanism, at least for the pthreads implementation.) */
|
||||
|
||||
void
|
||||
PyEval_ReInitThreads(void)
|
||||
{
|
||||
_Py_IDENTIFIER(_after_fork);
|
||||
PyObject *threading, *result;
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
PyThreadState *current_tstate = PyThreadState_GET();
|
||||
|
||||
if (!gil_created())
|
||||
return;
|
||||
recreate_gil();
|
||||
pending_lock = PyThread_allocate_lock();
|
||||
take_gil(tstate);
|
||||
take_gil(current_tstate);
|
||||
main_thread = PyThread_get_thread_ident();
|
||||
|
||||
/* Update the threading module with the new state.
|
||||
*/
|
||||
tstate = PyThreadState_GET();
|
||||
threading = PyMapping_GetItemString(tstate->interp->modules,
|
||||
threading = PyMapping_GetItemString(current_tstate->interp->modules,
|
||||
"threading");
|
||||
if (threading == NULL) {
|
||||
/* threading not imported */
|
||||
|
@ -397,6 +396,9 @@ PyEval_ReInitThreads(void)
|
|||
else
|
||||
Py_DECREF(result);
|
||||
Py_DECREF(threading);
|
||||
|
||||
/* Destroy all threads except the current one */
|
||||
_PyThreadState_DeleteExcept(current_tstate);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -414,6 +414,53 @@ PyThreadState_DeleteCurrent()
|
|||
#endif /* WITH_THREAD */
|
||||
|
||||
|
||||
/*
|
||||
* 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 interpreteres.
|
||||
*/
|
||||
void
|
||||
_PyThreadState_DeleteExcept(PyThreadState *tstate)
|
||||
{
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
PyThreadState *p, *next, *garbage;
|
||||
HEAD_LOCK();
|
||||
/* Remove all thread states, except tstate, from the linked list of
|
||||
thread states. This will allow calling PyThreadState_Clear()
|
||||
without holding the lock.
|
||||
XXX This would be simpler with a doubly-linked list. */
|
||||
garbage = interp->tstate_head;
|
||||
interp->tstate_head = tstate;
|
||||
if (garbage == tstate) {
|
||||
garbage = garbage->next;
|
||||
tstate->next = NULL;
|
||||
}
|
||||
else {
|
||||
for (p = garbage; p; p = p->next) {
|
||||
if (p->next == tstate) {
|
||||
p->next = tstate->next;
|
||||
tstate->next = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tstate->next != NULL)
|
||||
Py_FatalError("_PyThreadState_DeleteExcept: tstate not found "
|
||||
"in interpreter thread states");
|
||||
HEAD_UNLOCK();
|
||||
/* 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. */
|
||||
for (p = garbage; p; p = next) {
|
||||
next = p->next;
|
||||
PyThreadState_Clear(p);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PyThreadState *
|
||||
PyThreadState_Get(void)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue