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).
diff --git a/Python/ceval.c b/Python/ceval.c
index cbc0fab..d32b6fb 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -362,29 +362,28 @@
     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 @@
     else
         Py_DECREF(result);
     Py_DECREF(threading);
+
+    /* Destroy all threads except the current one */
+    _PyThreadState_DeleteExcept(current_tstate);
 }
 
 #else
diff --git a/Python/pystate.c b/Python/pystate.c
index 7003893..2a6f16c 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -414,6 +414,53 @@
 #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)
 {