--- /dev/null
+# Copyright 2008 James Bunton <jamesbunton@fastmail.fm>
+# Licensed for distribution under the GPL version 2, check COPYING for details
+# asyncore.loop() with delayed function calls
+
+import asyncore
+import heapq
+import signal
+import time
+
+tasks = []
+running = False
+
+class Task(object):
+ def __init__(self, delay, func, args=[], kwargs={}):
+ self.time = time.time() + delay
+ self.func = lambda: func(*args, **kwargs)
+
+ def __cmp__(self, other):
+ return cmp(self.time, other.time)
+
+ def __call__(self):
+ f = self.func
+ self.func = None
+ if f:
+ return f()
+
+ def cancel(self):
+ assert self.func is not None
+ self.func = None
+
+def schedule(delay, func, args=[], kwargs={}):
+ task = Task(delay, func, args, kwargs)
+ heapq.heappush(tasks, task)
+ return task
+
+def loop(timeout=30.0, use_poll=False):
+ global running
+ running = True
+ oldhandler = signal.signal(signal.SIGTERM, exit)
+
+ while running:
+ now = time.time()
+ while tasks and tasks[0].time < now:
+ task = heapq.heappop(tasks)
+ task()
+
+ t = timeout
+ if tasks:
+ t = max(min(t, tasks[0].time - now), 0)
+
+ asyncore.loop(timeout=t, count=1, use_poll=use_poll)
+
+ signal.signal(signal.SIGTERM, oldhandler)
+
+def exit(*args):
+ global running
+ running = False
+
+__all__ = ("schedule", "loop", "exit")
+