Merged revisions 61038,61042-61045,61047,61050,61053,61055-61056,61061-61062,61066,61068,61070,61083,61085,61092-61097,61103-61108 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r61105 | andrew.kuchling | 2008-02-28 15:03:03 +0100 (Thu, 28 Feb 2008) | 1 line

  #2169: make generated HTML more valid
........
  r61106 | jeffrey.yasskin | 2008-02-28 19:03:15 +0100 (Thu, 28 Feb 2008) | 4 lines

  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.
........
  r61107 | raymond.hettinger | 2008-02-28 20:41:24 +0100 (Thu, 28 Feb 2008) | 1 line

  Document impending updates to itertools.
........
  r61108 | martin.v.loewis | 2008-02-28 20:44:22 +0100 (Thu, 28 Feb 2008) | 1 line

  Add 2.6aN uuids.
........
diff --git a/Lib/SimpleHTTPServer.py b/Lib/SimpleHTTPServer.py
index deedd4b..beb0a39 100644
--- a/Lib/SimpleHTTPServer.py
+++ b/Lib/SimpleHTTPServer.py
@@ -109,8 +109,9 @@
         list.sort(key=lambda a: a.lower())
         f = StringIO()
         displaypath = cgi.escape(urllib.unquote(self.path))
-        f.write("<title>Directory listing for %s</title>\n" % displaypath)
-        f.write("<h2>Directory listing for %s</h2>\n" % displaypath)
+        f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
+        f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
+        f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
         f.write("<hr>\n<ul>\n")
         for name in list:
             fullname = os.path.join(path, name)
@@ -124,7 +125,7 @@
                 # Note: a link to a directory displays with @ and links with /
             f.write('<li><a href="%s">%s</a>\n'
                     % (urllib.quote(linkname), cgi.escape(displayname)))
-        f.write("</ul>\n<hr>\n")
+        f.write("</ul>\n<hr>\n</body>\n</html>\n")
         length = f.tell()
         f.seek(0)
         self.send_response(200)
diff --git a/Lib/SocketServer.py b/Lib/SocketServer.py
index 9c5d4c2..47d8728 100644
--- a/Lib/SocketServer.py
+++ b/Lib/SocketServer.py
@@ -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 as e:
diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py
index 25734fd..658056c 100644
--- a/Lib/test/test_socketserver.py
+++ b/Lib/test/test_socketserver.py
@@ -2,6 +2,7 @@
 Test suite for SocketServer.py.
 """
 
+import contextlib
 import errno
 import imp
 import os
@@ -109,6 +110,18 @@
         if verbose: print("thread: done")
 
 
+@contextlib.contextmanager
+def simple_subprocess(testcase):
+    pid = os.fork()
+    if pid == 0:
+        # Don't throw an exception; it would be caught by the test harness.
+        os._exit(72)
+    yield None
+    pid2, status = os.waitpid(pid, 0)
+    testcase.assertEquals(pid2, pid)
+    testcase.assertEquals(72 << 8, status)
+
+
 class SocketServerTest(unittest.TestCase):
     """Test all socket servers."""
 
@@ -211,10 +224,11 @@
                         self.stream_examine)
 
     if HAVE_FORKING:
-        def test_ThreadingTCPServer(self):
-            self.run_server(SocketServer.ForkingTCPServer,
-                            SocketServer.StreamRequestHandler,
-                            self.stream_examine)
+        def test_ForkingTCPServer(self):
+            with simple_subprocess(self):
+                self.run_server(SocketServer.ForkingTCPServer,
+                                SocketServer.StreamRequestHandler,
+                                self.stream_examine)
 
     if HAVE_UNIX_SOCKETS:
         def test_UnixStreamServer(self):
@@ -229,9 +243,10 @@
 
         if HAVE_FORKING:
             def test_ForkingUnixStreamServer(self):
-                self.run_server(ForkingUnixStreamServer,
-                                SocketServer.StreamRequestHandler,
-                                self.stream_examine)
+                with simple_subprocess(self):
+                    self.run_server(ForkingUnixStreamServer,
+                                    SocketServer.StreamRequestHandler,
+                                    self.stream_examine)
 
     def test_UDPServer(self):
         self.run_server(SocketServer.UDPServer,
@@ -245,9 +260,10 @@
 
     if HAVE_FORKING:
         def test_ForkingUDPServer(self):
-            self.run_server(SocketServer.ForkingUDPServer,
-                            SocketServer.DatagramRequestHandler,
-                            self.dgram_examine)
+            with simple_subprocess(self):
+                self.run_server(SocketServer.ForkingUDPServer,
+                                SocketServer.DatagramRequestHandler,
+                                self.dgram_examine)
 
     # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
     # client address so this cannot work: