diff Lib/SocketServer.py @ 45551:cc220745e4e5 legacy-trunk

Prevent SocketServer.ForkingMixIn from waiting on child processes that it didn't create, in most cases. When there are max_children handlers running, it will still wait for any child process, not just handler processes.
author Jeffrey Yasskin <jyasskin@gmail.com>
date Thu, 28 Feb 2008 18:03:15 +0000
parents e518e39f4a9e
children a8754c0db53f
line wrap: on
line diff
--- a/Lib/SocketServer.py	Thu Feb 28 14:03:03 2008 +0000
+++ b/Lib/SocketServer.py	Thu Feb 28 18:03:15 2008 +0000
@@ -440,18 +440,30 @@
 
     def collect_children(self):
         """Internal routine to wait for children that have exited."""
-        while self.active_children:
-            if len(self.active_children) < self.max_children:
-                options = os.WNOHANG
-            else:
-                # If the maximum number of children are already
-                # running, block while waiting for a child to exit
-                options = 0
+        if self.active_children is None: return
+        while len(self.active_children) >= self.max_children:
+            # XXX: This will wait for any child process, not just ones
+            # spawned by this library. This could confuse other
+            # libraries that expect to be able to wait for their own
+            # children.
             try:
-                pid, status = os.waitpid(0, options)
+                pid, status = os.waitpid(0, options=0)
             except os.error:
                 pid = None
-            if not pid: break
+            if pid not in self.active_children: continue
+            self.active_children.remove(pid)
+
+        # XXX: This loop runs more system calls than it ought
+        # to. There should be a way to put the active_children into a
+        # process group and then use os.waitpid(-pgid) to wait for any
+        # of that set, but I couldn't find a way to allocate pgids
+        # that couldn't collide.
+        for child in self.active_children:
+            try:
+                pid, status = os.waitpid(child, os.WNOHANG)
+            except os.error:
+                pid = None
+            if not pid: continue
             try:
                 self.active_children.remove(pid)
             except ValueError, e: