You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
5.5KB

  1. import sys
  2. import traceback
  3. import types
  4. from eventlet.support import greenlets as greenlet
  5. import six
  6. from eventlet.hubs.hub import BaseHub, READ, WRITE
  7. try:
  8. import event
  9. except ImportError:
  10. event = None
  11. def is_available():
  12. return event is not None
  13. class event_wrapper(object):
  14. def __init__(self, impl=None, seconds=None):
  15. self.impl = impl
  16. self.seconds = seconds
  17. def __repr__(self):
  18. if self.impl is not None:
  19. return repr(self.impl)
  20. else:
  21. return object.__repr__(self)
  22. def __str__(self):
  23. if self.impl is not None:
  24. return str(self.impl)
  25. else:
  26. return object.__str__(self)
  27. def cancel(self):
  28. if self.impl is not None:
  29. self.impl.delete()
  30. self.impl = None
  31. @property
  32. def pending(self):
  33. return bool(self.impl and self.impl.pending())
  34. class Hub(BaseHub):
  35. SYSTEM_EXCEPTIONS = (KeyboardInterrupt, SystemExit)
  36. def __init__(self):
  37. super(Hub, self).__init__()
  38. event.init()
  39. self.signal_exc_info = None
  40. self.signal(
  41. 2,
  42. lambda signalnum, frame: self.greenlet.parent.throw(KeyboardInterrupt))
  43. self.events_to_add = []
  44. def dispatch(self):
  45. loop = event.loop
  46. while True:
  47. for e in self.events_to_add:
  48. if e is not None and e.impl is not None and e.seconds is not None:
  49. e.impl.add(e.seconds)
  50. e.seconds = None
  51. self.events_to_add = []
  52. result = loop()
  53. if getattr(event, '__event_exc', None) is not None:
  54. # only have to do this because of bug in event.loop
  55. t = getattr(event, '__event_exc')
  56. setattr(event, '__event_exc', None)
  57. assert getattr(event, '__event_exc') is None
  58. six.reraise(t[0], t[1], t[2])
  59. if result != 0:
  60. return result
  61. def run(self):
  62. while True:
  63. try:
  64. self.dispatch()
  65. except greenlet.GreenletExit:
  66. break
  67. except self.SYSTEM_EXCEPTIONS:
  68. raise
  69. except:
  70. if self.signal_exc_info is not None:
  71. self.schedule_call_global(
  72. 0, greenlet.getcurrent().parent.throw, *self.signal_exc_info)
  73. self.signal_exc_info = None
  74. else:
  75. self.squelch_timer_exception(None, sys.exc_info())
  76. def abort(self, wait=True):
  77. self.schedule_call_global(0, self.greenlet.throw, greenlet.GreenletExit)
  78. if wait:
  79. assert self.greenlet is not greenlet.getcurrent(
  80. ), "Can't abort with wait from inside the hub's greenlet."
  81. self.switch()
  82. def _getrunning(self):
  83. return bool(self.greenlet)
  84. def _setrunning(self, value):
  85. pass # exists for compatibility with BaseHub
  86. running = property(_getrunning, _setrunning)
  87. def add(self, evtype, fileno, real_cb, real_tb, mac):
  88. # this is stupid: pyevent won't call a callback unless it's a function,
  89. # so we have to force it to be one here
  90. if isinstance(real_cb, types.BuiltinMethodType):
  91. def cb(_d):
  92. real_cb(_d)
  93. else:
  94. cb = real_cb
  95. if evtype is READ:
  96. evt = event.read(fileno, cb, fileno)
  97. elif evtype is WRITE:
  98. evt = event.write(fileno, cb, fileno)
  99. return super(Hub, self).add(evtype, fileno, evt, real_tb, mac)
  100. def signal(self, signalnum, handler):
  101. def wrapper():
  102. try:
  103. handler(signalnum, None)
  104. except:
  105. self.signal_exc_info = sys.exc_info()
  106. event.abort()
  107. return event_wrapper(event.signal(signalnum, wrapper))
  108. def remove(self, listener):
  109. super(Hub, self).remove(listener)
  110. listener.cb.delete()
  111. def remove_descriptor(self, fileno):
  112. for lcontainer in six.itervalues(self.listeners):
  113. listener = lcontainer.pop(fileno, None)
  114. if listener:
  115. try:
  116. listener.cb.delete()
  117. except self.SYSTEM_EXCEPTIONS:
  118. raise
  119. except:
  120. traceback.print_exc()
  121. def schedule_call_local(self, seconds, cb, *args, **kwargs):
  122. current = greenlet.getcurrent()
  123. if current is self.greenlet:
  124. return self.schedule_call_global(seconds, cb, *args, **kwargs)
  125. event_impl = event.event(_scheduled_call_local, (cb, args, kwargs, current))
  126. wrapper = event_wrapper(event_impl, seconds=seconds)
  127. self.events_to_add.append(wrapper)
  128. return wrapper
  129. schedule_call = schedule_call_local
  130. def schedule_call_global(self, seconds, cb, *args, **kwargs):
  131. event_impl = event.event(_scheduled_call, (cb, args, kwargs))
  132. wrapper = event_wrapper(event_impl, seconds=seconds)
  133. self.events_to_add.append(wrapper)
  134. return wrapper
  135. def _version_info(self):
  136. baseversion = event.__version__
  137. return baseversion
  138. def _scheduled_call(event_impl, handle, evtype, arg):
  139. cb, args, kwargs = arg
  140. try:
  141. cb(*args, **kwargs)
  142. finally:
  143. event_impl.delete()
  144. def _scheduled_call_local(event_impl, handle, evtype, arg):
  145. cb, args, kwargs, caller_greenlet = arg
  146. try:
  147. if not caller_greenlet.dead:
  148. cb(*args, **kwargs)
  149. finally:
  150. event_impl.delete()