Browse Source

Refine the logic of serve_forever() and shutdown().

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac352@3298 e5f2f494-b856-4b98-b285-d166d9295462
Likun Zhang 14 years ago
parent
commit
f8facdc96e

+ 16 - 30
src/lib/python/isc/utils/serve_mixin.py

@@ -21,7 +21,7 @@ SOCK_DATA = b'somedata'
 class ServeMixIn:
     '''Mix-In class to override the function serve_forever()
     and shutdown() in class socketserver::TCPServer.
-      serve_forever() in socketserver::TCPServer use polling
+      serve_forever() in socketserver.TCPServer use polling
     for checking request, which reduces the responsiveness to
     the shutdown request and wastes cpu at all other times.
       ServeMixIn should be used together with socketserver.TCPServer
@@ -31,53 +31,39 @@ class ServeMixIn:
     explicitely in derived class.
     '''
     def __init__(self):
-        self.__serving = False
         self.__read_sock, self.__write_sock = socket.socketpair()
-        self.__serve_thread = None
+        self.__is_shut_down = threading.Event()
 
     def serve_forever(self, poll_interval=None):
         ''' Override the serve_forever([poll_interval]) in class
-        socketserver.TCPServer by using the socketpair to wake up
-        instead of polling.
+        socketserver.TCPServer. use the socketpair to wake up
+        the select when shutdown() is called in anther thread.
           Note, parameter 'poll_interval' is just used to keep the
         interface, it's never used in this function.
         '''        
-        self.__serving = True
-        started_event = threading.Event()
-
-        self.__serve_thread = threading.Thread(target=self.__serve_forever, \
-                                               args=(started_event,))
-        self.__serve_thread.start()
-        
-        started_event.wait() # wait until the thread has started
-        return self.__serve_thread
-
-    def __serve_forever(self, syn_event):
-        '''Use one socket pair to wake up the select when shutdown() 
-        is called in anther thread.
-        '''        
-        self.__serving = True
-        syn_event.set()
-
-        while self.__serving:
+        while True:
             # block until the self.socket or self.__read_sock is readable
             try:
                 r, w, e = select.select([self, self.__read_sock], [], [])
-            except select.error:
+            except select.error as err:
+                if err.args[0] == EINTR:
                     continue
+                else:
+                    sys.stderr.write("Error with select(), %s\n", err)
+                    break
             
             if self.__read_sock in r:
                 break
             else:
                 self._handle_request_noblock()
 
+        self.__is_shut_down.set()                
+
     def shutdown(self):
-        '''Stops the self.__serve_thread( self.__serve_forever loop).
-        when self.__serve_thread is running, it will block until the 
-        self.__serve_thread terminate.
+        '''Stops the serve_forever loop.
+        Blocks until the loop has finished, the function should be called
+        in another thread when serve_forever is running, or it will block.
         '''
-        self.__serving = False
         self.__write_sock.send(SOCK_DATA) # make self.__read_sock readable.
-        if self.__serve_thread:
-            self.__serve_thread.join() # wait until the serve thread terminate
+        self.__is_shut_down.wait()  # wait until the serve thread terminate
 

+ 4 - 1
src/lib/python/isc/utils/tests/serve_mixin_test.py

@@ -46,7 +46,9 @@ class TestServeMixIn(unittest.TestCase):
         # use port 0 to select an arbitrary unused port.
         server = MyServer(('127.0.0.1', 0), MyHandler)
         ip, port = server.server_address
-        server_thread = server.serve_forever()
+        server_thread = threading.Thread(target=server.serve_forever)
+        server_thread.setDaemon(True)
+        server_thread.start()
 
         msg = b'senddata'
         self.assertEqual(msg, send_and_get_reply(ip, port, msg))
@@ -55,6 +57,7 @@ class TestServeMixIn(unittest.TestCase):
         # Now shutdown the server
         server.shutdown()
         # Sleep a while, make sure the thread has finished.
+        time.sleep(0.1)
         self.assertFalse(server_thread.is_alive())
 
 if __name__== "__main__":