diff options
Diffstat (limited to 'Lib/socketserver.py')
| -rw-r--r-- | Lib/socketserver.py | 81 | 
1 files changed, 44 insertions, 37 deletions
diff --git a/Lib/socketserver.py b/Lib/socketserver.py index 8332fdf66d..5cb89bea19 100644 --- a/Lib/socketserver.py +++ b/Lib/socketserver.py @@ -131,7 +131,6 @@ __version__ = "0.4"  import socket  import select -import sys  import os  import errno  try: @@ -139,10 +138,10 @@ try:  except ImportError:      import dummy_threading as threading -__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer", -           "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler", -           "StreamRequestHandler","DatagramRequestHandler", -           "ThreadingMixIn", "ForkingMixIn"] +__all__ = ["BaseServer", "TCPServer", "UDPServer", "ForkingUDPServer", +           "ForkingTCPServer", "ThreadingUDPServer", "ThreadingTCPServer", +           "BaseRequestHandler", "StreamRequestHandler", +           "DatagramRequestHandler", "ThreadingMixIn", "ForkingMixIn"]  if hasattr(socket, "AF_UNIX"):      __all__.extend(["UnixStreamServer","UnixDatagramServer",                      "ThreadingUnixStreamServer", @@ -299,7 +298,7 @@ class BaseServer:          """          try:              request, client_address = self.get_request() -        except socket.error: +        except OSError:              return          if self.verify_request(request, client_address):              try: @@ -427,8 +426,12 @@ class TCPServer(BaseServer):          self.socket = socket.socket(self.address_family,                                      self.socket_type)          if bind_and_activate: -            self.server_bind() -            self.server_activate() +            try: +                self.server_bind() +                self.server_activate() +            except: +                self.server_close() +                raise      def server_bind(self):          """Called by constructor to bind the socket. @@ -479,7 +482,7 @@ class TCPServer(BaseServer):              #explicitly shutdown.  socket.close() merely releases              #the socket and waits for GC to perform the actual close.              request.shutdown(socket.SHUT_WR) -        except socket.error: +        except OSError:              pass #some platforms may raise ENOTCONN here          self.close_request(request) @@ -524,35 +527,39 @@ class ForkingMixIn:      def collect_children(self):          """Internal routine to wait for children that have exited.""" -        if self.active_children is None: return +        if self.active_children is None: +            return + +        # If we're above the max number of children, wait and reap them until +        # we go back below threshold. Note that we use waitpid(-1) below to be +        # able to collect children in size(<defunct children>) syscalls instead +        # of size(<children>): the downside is that this might reap children +        # which we didn't spawn, which is why we only resort to this when we're +        # above max_children.          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, 0) -            except os.error: -                pid = None -            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 +                pid, _ = os.waitpid(-1, 0) +                self.active_children.discard(pid) +            except InterruptedError: +                pass +            except ChildProcessError: +                # we don't have any children, we're done +                self.active_children.clear() +            except OSError: +                break + +        # Now reap all defunct children. +        for pid in self.active_children.copy():              try: -                self.active_children.remove(pid) -            except ValueError as e: -                raise ValueError('%s. x=%d and list=%r' % (e.message, pid, -                                                           self.active_children)) +                pid, _ = os.waitpid(pid, os.WNOHANG) +                # if the child hasn't exited yet, pid will be 0 and ignored by +                # discard() below +                self.active_children.discard(pid) +            except ChildProcessError: +                # someone else reaped it +                self.active_children.discard(pid) +            except OSError: +                pass      def handle_timeout(self):          """Wait for zombies after self.timeout seconds of inactivity. @@ -574,8 +581,8 @@ class ForkingMixIn:          if pid:              # Parent process              if self.active_children is None: -                self.active_children = [] -            self.active_children.append(pid) +                self.active_children = set() +            self.active_children.add(pid)              self.close_request(request)              return          else:  | 
