serve_mixin.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. # Copyright (C) 2010 Internet Systems Consortium.
  2. #
  3. # Permission to use, copy, modify, and distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
  8. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  9. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  10. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  12. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  14. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. import threading
  16. import socket
  17. import select
  18. class ServeMixIn():
  19. '''Mix-In class to override the function serve_forever()
  20. and shutdown() in class socketserver.
  21. '''
  22. _serving = False
  23. _is_shut_down = threading.Event()
  24. _read_sock, _write_sock = socket.socketpair()
  25. def serve_forever(self, poll_interval=0.5):
  26. ''' Override the serve_forever() in class BaseServer.
  27. use one socket pair to wake up the select when shutdown()
  28. is called in anther thread.
  29. '''
  30. self._serving = True
  31. self._is_shut_down.clear()
  32. while self._serving:
  33. # block until the self.socket or self._read_sock is readable
  34. try:
  35. r, w, e = select.select([self, self._read_sock], [], [])
  36. except select.error as err:
  37. if err.args[0] != EINTR:
  38. raise
  39. else:
  40. continue
  41. if r:
  42. if self._read_sock in r:
  43. break
  44. else:
  45. self._handle_request_noblock()
  46. self._is_shut_down.set()
  47. def shutdown(self):
  48. '''Stops the serve_forever loop.
  49. Blocks until the loop has finished, the function should be called
  50. in another thread when serve_forever is running, or it will block.
  51. '''
  52. self._serving = False
  53. self._write_sock.send(b'anydata') # make self._read_sock readable.
  54. self._is_shut_down.wait()