summaryrefslogtreecommitdiffstats
path: root/Python/pystate.c
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2013-05-05 21:47:09 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2013-05-05 21:47:09 (GMT)
commit8408cea0cdc0ccd5900acd99a9a51dd9161ae319 (patch)
tree0dcb39ac0cf5fc5e293941763a31bd2472dd004b /Python/pystate.c
parent39b17c513ae7b9baecdc8292876683647186fee4 (diff)
downloadcpython-8408cea0cdc0ccd5900acd99a9a51dd9161ae319.zip
cpython-8408cea0cdc0ccd5900acd99a9a51dd9161ae319.tar.gz
cpython-8408cea0cdc0ccd5900acd99a9a51dd9161ae319.tar.bz2
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).
Diffstat (limited to 'Python/pystate.c')
-rw-r--r--Python/pystate.c47
1 files changed, 47 insertions, 0 deletions
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 @@ 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)
{