--- /dev/null
+import traceback
+
+from eventlet.support import greenlets as greenlet, six
+from eventlet.hubs import get_hub
+
+""" If true, captures a stack trace for each timer when constructed. This is
+useful for debugging leaking timers, to find out where the timer was set up. """
+_g_debug = False
+
+
+class Timer(object):
+ def __init__(self, seconds, cb, *args, **kw):
+ """Create a timer.
+ seconds: The minimum number of seconds to wait before calling
+ cb: The callback to call when the timer has expired
+ *args: The arguments to pass to cb
+ **kw: The keyword arguments to pass to cb
+
+ This timer will not be run unless it is scheduled in a runloop by
+ calling timer.schedule() or runloop.add_timer(timer).
+ """
+ self.seconds = seconds
+ self.tpl = cb, args, kw
+ self.called = False
+ if _g_debug:
+ self.traceback = six.StringIO()
+ traceback.print_stack(file=self.traceback)
+
+ @property
+ def pending(self):
+ return not self.called
+
+ def __repr__(self):
+ secs = getattr(self, 'seconds', None)
+ cb, args, kw = getattr(self, 'tpl', (None, None, None))
+ retval = "Timer(%s, %s, *%s, **%s)" % (
+ secs, cb, args, kw)
+ if _g_debug and hasattr(self, 'traceback'):
+ retval += '\n' + self.traceback.getvalue()
+ return retval
+
+ def copy(self):
+ cb, args, kw = self.tpl
+ return self.__class__(self.seconds, cb, *args, **kw)
+
+ def schedule(self):
+ """Schedule this timer to run in the current runloop.
+ """
+ self.called = False
+ self.scheduled_time = get_hub().add_timer(self)
+ return self
+
+ def __call__(self, *args):
+ if not self.called:
+ self.called = True
+ cb, args, kw = self.tpl
+ try:
+ cb(*args, **kw)
+ finally:
+ try:
+ del self.tpl
+ except AttributeError:
+ pass
+
+ def cancel(self):
+ """Prevent this timer from being called. If the timer has already
+ been called or canceled, has no effect.
+ """
+ if not self.called:
+ self.called = True
+ get_hub().timer_canceled(self)
+ try:
+ del self.tpl
+ except AttributeError:
+ pass
+
+ # No default ordering in 3.x. heapq uses <
+ # FIXME should full set be added?
+ def __lt__(self, other):
+ return id(self) < id(other)
+
+
+class LocalTimer(Timer):
+
+ def __init__(self, *args, **kwargs):
+ self.greenlet = greenlet.getcurrent()
+ Timer.__init__(self, *args, **kwargs)
+
+ @property
+ def pending(self):
+ if self.greenlet is None or self.greenlet.dead:
+ return False
+ return not self.called
+
+ def __call__(self, *args):
+ if not self.called:
+ self.called = True
+ if self.greenlet is not None and self.greenlet.dead:
+ return
+ cb, args, kw = self.tpl
+ cb(*args, **kw)
+
+ def cancel(self):
+ self.greenlet = None
+ Timer.cancel(self)