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.

107 lines
3.1KB

  1. import traceback
  2. import eventlet.hubs
  3. from eventlet.support import greenlets as greenlet
  4. import six
  5. """ If true, captures a stack trace for each timer when constructed. This is
  6. useful for debugging leaking timers, to find out where the timer was set up. """
  7. _g_debug = False
  8. class Timer(object):
  9. def __init__(self, seconds, cb, *args, **kw):
  10. """Create a timer.
  11. seconds: The minimum number of seconds to wait before calling
  12. cb: The callback to call when the timer has expired
  13. *args: The arguments to pass to cb
  14. **kw: The keyword arguments to pass to cb
  15. This timer will not be run unless it is scheduled in a runloop by
  16. calling timer.schedule() or runloop.add_timer(timer).
  17. """
  18. self.seconds = seconds
  19. self.tpl = cb, args, kw
  20. self.called = False
  21. if _g_debug:
  22. self.traceback = six.StringIO()
  23. traceback.print_stack(file=self.traceback)
  24. @property
  25. def pending(self):
  26. return not self.called
  27. def __repr__(self):
  28. secs = getattr(self, 'seconds', None)
  29. cb, args, kw = getattr(self, 'tpl', (None, None, None))
  30. retval = "Timer(%s, %s, *%s, **%s)" % (
  31. secs, cb, args, kw)
  32. if _g_debug and hasattr(self, 'traceback'):
  33. retval += '\n' + self.traceback.getvalue()
  34. return retval
  35. def copy(self):
  36. cb, args, kw = self.tpl
  37. return self.__class__(self.seconds, cb, *args, **kw)
  38. def schedule(self):
  39. """Schedule this timer to run in the current runloop.
  40. """
  41. self.called = False
  42. self.scheduled_time = eventlet.hubs.get_hub().add_timer(self)
  43. return self
  44. def __call__(self, *args):
  45. if not self.called:
  46. self.called = True
  47. cb, args, kw = self.tpl
  48. try:
  49. cb(*args, **kw)
  50. finally:
  51. try:
  52. del self.tpl
  53. except AttributeError:
  54. pass
  55. def cancel(self):
  56. """Prevent this timer from being called. If the timer has already
  57. been called or canceled, has no effect.
  58. """
  59. if not self.called:
  60. self.called = True
  61. eventlet.hubs.get_hub().timer_canceled(self)
  62. try:
  63. del self.tpl
  64. except AttributeError:
  65. pass
  66. # No default ordering in 3.x. heapq uses <
  67. # FIXME should full set be added?
  68. def __lt__(self, other):
  69. return id(self) < id(other)
  70. class LocalTimer(Timer):
  71. def __init__(self, *args, **kwargs):
  72. self.greenlet = greenlet.getcurrent()
  73. Timer.__init__(self, *args, **kwargs)
  74. @property
  75. def pending(self):
  76. if self.greenlet is None or self.greenlet.dead:
  77. return False
  78. return not self.called
  79. def __call__(self, *args):
  80. if not self.called:
  81. self.called = True
  82. if self.greenlet is not None and self.greenlet.dead:
  83. return
  84. cb, args, kw = self.tpl
  85. cb(*args, **kw)
  86. def cancel(self):
  87. self.greenlet = None
  88. Timer.cancel(self)