|
@@ -0,0 +1,60 @@
|
|
|
+# Copyright (C) 2010 Internet Systems Consortium.
|
|
|
+#
|
|
|
+# Permission to use, copy, modify, and distribute this software for any
|
|
|
+# purpose with or without fee is hereby granted, provided that the above
|
|
|
+# copyright notice and this permission notice appear in all copies.
|
|
|
+#
|
|
|
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
|
|
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
|
|
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
|
|
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
|
|
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
|
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
+
|
|
|
+import threading
|
|
|
+import socket
|
|
|
+import select
|
|
|
+
|
|
|
+class ServeMixIn():
|
|
|
+ '''Mix-In class to override the function serve_forever()
|
|
|
+ and shutdown() in class socketserver.
|
|
|
+ '''
|
|
|
+ _serving = False
|
|
|
+ _is_shut_down = threading.Event()
|
|
|
+ _read_sock, _write_sock = socket.socketpair()
|
|
|
+
|
|
|
+ def serve_forever(self, poll_interval=0.5):
|
|
|
+ ''' Override the serve_forever() in class BaseServer.
|
|
|
+ use one socket pair to wake up the select when shutdown()
|
|
|
+ is called in anther thread.
|
|
|
+ '''
|
|
|
+ self._serving = True
|
|
|
+ self._is_shut_down.clear()
|
|
|
+ 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:
|
|
|
+ continue
|
|
|
+ if r:
|
|
|
+ if self._read_sock in r:
|
|
|
+ break
|
|
|
+ else:
|
|
|
+ self._handle_request_noblock()
|
|
|
+
|
|
|
+ self._is_shut_down.set()
|
|
|
+
|
|
|
+ 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.
|
|
|
+ '''
|
|
|
+ self._serving = False
|
|
|
+ self._write_sock.send(b'anydata') # make self._read_sock readable.
|
|
|
+ self._is_shut_down.wait()
|
|
|
+
|