[Python-checkins] cpython: Fix closes issue #11109 - socketserver.ForkingMixIn leaves zombies, also fails

senthil.kumaran python-checkins at python.org
Wed May 25 18:26:46 CEST 2011


http://hg.python.org/cpython/rev/e2363b1c4bca
changeset:   70377:e2363b1c4bca
parent:      70375:db6971ddceee
user:        Senthil Kumaran <senthil at uthcode.com>
date:        Thu May 26 00:22:59 2011 +0800
summary:
  Fix closes issue #11109 -  socketserver.ForkingMixIn leaves zombies, also fails to reap all zombies in one pass.

A new method called service_action is made available in BaseServer, called by
serve_forever loop. This useful in cases where Mixins can use it for cleanup
action. ForkingMixin class uses service_action to collect the zombie child
processes. Initial Patch by Justin Wark.

files:
  Doc/library/socketserver.rst |  15 ++++++++++++++-
  Lib/socketserver.py          |  22 ++++++++++++++++++++--
  2 files changed, 34 insertions(+), 3 deletions(-)


diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst
--- a/Doc/library/socketserver.rst
+++ b/Doc/library/socketserver.rst
@@ -153,8 +153,21 @@
 .. method:: BaseServer.serve_forever(poll_interval=0.5)
 
    Handle requests until an explicit :meth:`shutdown` request.  Polls for
-   shutdown every *poll_interval* seconds.
+   shutdown every *poll_interval* seconds. It also calls
+   :meth:`service_actions` which may be used by a subclass or Mixin to provide
+   various cleanup actions. For e.g. ForkingMixin class uses
+   :meth:`service_actions` to cleanup the zombie child processes.
 
+   .. versionchanged:: 3.3
+       Added service_actions call to the serve_forever method.
+
+
+.. method:: BaseServer.service_actions()
+
+   This is called by the serve_forever loop. This method is can be overridden
+   by Mixin's to add cleanup or service specific actions.
+
+   .. versionadded:: 3.3
 
 .. method:: BaseServer.shutdown()
 
diff --git a/Lib/socketserver.py b/Lib/socketserver.py
--- a/Lib/socketserver.py
+++ b/Lib/socketserver.py
@@ -82,7 +82,7 @@
 data is stored externally (e.g. in the file system), a synchronous
 class will essentially render the service "deaf" while one request is
 being handled -- which may be for a very long time if a client is slow
-to reqd all the data it has requested.  Here a threading or forking
+to recv all the data it has requested.  Here a threading or forking
 server is appropriate.
 
 In some cases, it may be appropriate to process part of a request
@@ -170,6 +170,7 @@
     - process_request(request, client_address)
     - shutdown_request(request)
     - close_request(request)
+    - service_actions()
     - handle_error()
 
     Methods for derived classes:
@@ -225,6 +226,8 @@
                 r, w, e = select.select([self], [], [], poll_interval)
                 if self in r:
                     self._handle_request_noblock()
+
+                self.service_actions()
         finally:
             self.__shutdown_request = False
             self.__is_shut_down.set()
@@ -239,6 +242,14 @@
         self.__shutdown_request = True
         self.__is_shut_down.wait()
 
+    def service_actions(self):
+        """Called by the serve_forever() loop.
+
+        May be overridden by a subclass / Mixin to implement any code that
+        needs to be run during the loop.
+        """
+        pass
+
     # The distinction between handling, getting, processing and
     # finishing a request is fairly arbitrary.  Remember:
     #
@@ -539,9 +550,15 @@
         """
         self.collect_children()
 
+    def service_actions(self):
+        """Collect the zombie child processes regularly in the ForkingMixin.
+
+        service_actions is called in the BaseServer's serve_forver loop.
+        """
+        self.collect_children()
+
     def process_request(self, request, client_address):
         """Fork a new subprocess to process the request."""
-        self.collect_children()
         pid = os.fork()
         if pid:
             # Parent process
@@ -549,6 +566,7 @@
                 self.active_children = []
             self.active_children.append(pid)
             self.close_request(request)
+            return
         else:
             # Child process.
             # This must never return, hence os._exit()!

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list