diff Python/pystate.c @ 83630:847692b9902a

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).
author Antoine Pitrou <solipsis@pitrou.net>
date Sun, 05 May 2013 23:47:09 +0200
parents 2e92d1567ad7
children 375d4fed4cf2
line wrap: on
line diff
--- a/Python/pystate.c	Sun May 05 22:12:34 2013 +0100
+++ b/Python/pystate.c	Sun May 05 23:47:09 2013 +0200
@@ -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)
 {