[svn] commit: r3270 - in /branches/trac352/src/lib/python/isc/utils: serve_mixin.py tests/serve_mixin_test.py
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Oct 19 08:39:49 UTC 2010
Author: zhanglikun
Date: Tue Oct 19 08:39:48 2010
New Revision: 3270
Log:
Fix the potential race condition problem and change the code according jinmei's review result.
Modified:
branches/trac352/src/lib/python/isc/utils/serve_mixin.py
branches/trac352/src/lib/python/isc/utils/tests/serve_mixin_test.py
Modified: branches/trac352/src/lib/python/isc/utils/serve_mixin.py
==============================================================================
--- branches/trac352/src/lib/python/isc/utils/serve_mixin.py (original)
+++ branches/trac352/src/lib/python/isc/utils/serve_mixin.py Tue Oct 19 08:39:48 2010
@@ -20,7 +20,10 @@
SOCK_DATA = b'somedata'
class ServeMixIn:
'''Mix-In class to override the function serve_forever()
- and shutdown() in class socketserver.TCPServer.
+ and shutdown() in class socketserver::TCPServer.
+ 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
or some derived classes of it, and ServeMixIn must be the first
base class in multiple inheritance, eg. MyClass(ServeMixIn,
@@ -29,42 +32,52 @@
'''
def __init__(self):
self.__serving = False
- self.__is_shut_down = threading.Event()
self.__read_sock, self.__write_sock = socket.socketpair()
+ self.__serve_thread = None
- def serve_forever(self, poll_interval=0.5):
- ''' Override the serve_forever([poll_interval]) in class
- socketserver.TCPServer. use one socket pair to wake up
- the select when shutdown() is called in anther thread.
+ 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 pulling.
Note, parameter 'poll_interval' is just used to keep the
interface, it's never used in this function.
'''
self.__serving = True
- self.__is_shut_down.clear()
+ 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:
# block until the self.socket or self.__read_sock is readable
try:
r, w, e = select.select([self, self.__read_sock], [], [])
- except select.error as err:
- if err.args[0] != EINTR:
- raise
- else:
+ except select.error:
continue
- if r:
- if (self.__read_sock in r) and \
- (self.__read_sock.recv(len(SOCK_DATA)) == SOCK_DATA):
- break
- else:
- self._handle_request_noblock()
-
- self.__is_shut_down.set()
+
+ if self.__read_sock in r:
+ break
+ else:
+ self._handle_request_noblock()
def shutdown(self):
- '''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.
+ '''Stops the self.__serve_thread( self.__serve_forever loop).
+ when self.__serve_thread is running, it will block until the
+ self.__serve_thread terminate.
'''
self.__serving = False
self.__write_sock.send(SOCK_DATA) # make self.__read_sock readable.
- self.__is_shut_down.wait()
+ if self.__serve_thread:
+ self.__serve_thread.join() # wait until the serve thread terminate
Modified: branches/trac352/src/lib/python/isc/utils/tests/serve_mixin_test.py
==============================================================================
--- branches/trac352/src/lib/python/isc/utils/tests/serve_mixin_test.py (original)
+++ branches/trac352/src/lib/python/isc/utils/tests/serve_mixin_test.py Tue Oct 19 08:39:48 2010
@@ -46,9 +46,7 @@
# use port 0 to select an arbitrary unused port.
server = MyServer(('127.0.0.1', 0), MyHandler)
ip, port = server.server_address
- server_thread = threading.Thread(target=server.serve_forever)
- server_thread.setDaemon(True)
- server_thread.start()
+ server_thread = server.serve_forever()
msg = b'senddata'
self.assertEqual(msg, send_and_get_reply(ip, port, msg))
@@ -57,7 +55,6 @@
# 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__":
More information about the bind10-changes
mailing list