From 6d69509bb6777d7b253d3371f0069d30e9930056 Mon Sep 17 00:00:00 2001 From: "Paul J. Davis" Date: Tue, 14 Jun 2011 16:17:47 -0400 Subject: [PATCH] Avoid race condition in dict iteration. Its possible that when iterating Arbiter.WORKERS in manage_workers we get interupted to handle a SIGCHLD which will pop the child PID from the dict which results in a "dict changed size while iterating error. Reported on IRC. Simple fix is to just copy the dict into a list that we iterate. --- gunicorn/arbiter.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/gunicorn/arbiter.py b/gunicorn/arbiter.py index 3460ff9f..acac4eba 100644 --- a/gunicorn/arbiter.py +++ b/gunicorn/arbiter.py @@ -419,12 +419,10 @@ class Arbiter(object): if len(self.WORKERS.keys()) < self.num_workers: self.spawn_workers() - num_to_kill = len(self.WORKERS) - self.num_workers - for i in range(num_to_kill, 0, -1): - pid, age = 0, sys.maxint - for (wpid, worker) in self.WORKERS.iteritems(): - if worker.age < age: - pid, age = wpid, worker.age + workers = self.WORKERS.items() + workers.sort(key=lambda w: w.age) + while len(workers) > self.num_workers: + (pid, _) = workers.pop(0) self.kill_worker(pid, signal.SIGQUIT) def spawn_worker(self):