25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
3.9KB

  1. import errno
  2. import sys
  3. from eventlet import patcher, support
  4. from eventlet.hubs import hub
  5. select = patcher.original('select')
  6. time = patcher.original('time')
  7. def is_available():
  8. return hasattr(select, 'poll')
  9. class Hub(hub.BaseHub):
  10. def __init__(self, clock=None):
  11. super(Hub, self).__init__(clock)
  12. self.EXC_MASK = select.POLLERR | select.POLLHUP
  13. self.READ_MASK = select.POLLIN | select.POLLPRI
  14. self.WRITE_MASK = select.POLLOUT
  15. self.poll = select.poll()
  16. def add(self, evtype, fileno, cb, tb, mac):
  17. listener = super(Hub, self).add(evtype, fileno, cb, tb, mac)
  18. self.register(fileno, new=True)
  19. return listener
  20. def remove(self, listener):
  21. super(Hub, self).remove(listener)
  22. self.register(listener.fileno)
  23. def register(self, fileno, new=False):
  24. mask = 0
  25. if self.listeners[self.READ].get(fileno):
  26. mask |= self.READ_MASK | self.EXC_MASK
  27. if self.listeners[self.WRITE].get(fileno):
  28. mask |= self.WRITE_MASK | self.EXC_MASK
  29. try:
  30. if mask:
  31. if new:
  32. self.poll.register(fileno, mask)
  33. else:
  34. try:
  35. self.poll.modify(fileno, mask)
  36. except (IOError, OSError):
  37. self.poll.register(fileno, mask)
  38. else:
  39. try:
  40. self.poll.unregister(fileno)
  41. except (KeyError, IOError, OSError):
  42. # raised if we try to remove a fileno that was
  43. # already removed/invalid
  44. pass
  45. except ValueError:
  46. # fileno is bad, issue 74
  47. self.remove_descriptor(fileno)
  48. raise
  49. def remove_descriptor(self, fileno):
  50. super(Hub, self).remove_descriptor(fileno)
  51. try:
  52. self.poll.unregister(fileno)
  53. except (KeyError, ValueError, IOError, OSError):
  54. # raised if we try to remove a fileno that was
  55. # already removed/invalid
  56. pass
  57. def do_poll(self, seconds):
  58. # poll.poll expects integral milliseconds
  59. return self.poll.poll(int(seconds * 1000.0))
  60. def wait(self, seconds=None):
  61. readers = self.listeners[self.READ]
  62. writers = self.listeners[self.WRITE]
  63. if not readers and not writers:
  64. if seconds:
  65. time.sleep(seconds)
  66. return
  67. try:
  68. presult = self.do_poll(seconds)
  69. except (IOError, select.error) as e:
  70. if support.get_errno(e) == errno.EINTR:
  71. return
  72. raise
  73. SYSTEM_EXCEPTIONS = self.SYSTEM_EXCEPTIONS
  74. if self.debug_blocking:
  75. self.block_detect_pre()
  76. # Accumulate the listeners to call back to prior to
  77. # triggering any of them. This is to keep the set
  78. # of callbacks in sync with the events we've just
  79. # polled for. It prevents one handler from invalidating
  80. # another.
  81. callbacks = set()
  82. noop = hub.noop # shave getattr
  83. for fileno, event in presult:
  84. if event & self.READ_MASK:
  85. callbacks.add((readers.get(fileno, noop), fileno))
  86. if event & self.WRITE_MASK:
  87. callbacks.add((writers.get(fileno, noop), fileno))
  88. if event & select.POLLNVAL:
  89. self.remove_descriptor(fileno)
  90. continue
  91. if event & self.EXC_MASK:
  92. callbacks.add((readers.get(fileno, noop), fileno))
  93. callbacks.add((writers.get(fileno, noop), fileno))
  94. for listener, fileno in callbacks:
  95. try:
  96. listener.cb(fileno)
  97. except SYSTEM_EXCEPTIONS:
  98. raise
  99. except:
  100. self.squelch_exception(fileno, sys.exc_info())
  101. support.clear_sys_exc_info()
  102. if self.debug_blocking:
  103. self.block_detect_post()