tabs -> spaces
[bg-scripts] / asyncsched.py
1 # Copyright 2008 James Bunton <jamesbunton@fastmail.fm>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
3 # asyncore.loop() with delayed function calls
4
5 import asyncore, select
6 import heapq
7 import signal
8 import time
9
10 tasks = []
11 running = False
12
13 class Task(object):
14 def __init__(self, delay, func, args=[], kwargs={}):
15 self.time = time.time() + delay
16 self.func = lambda: func(*args, **kwargs)
17
18 def __cmp__(self, other):
19 return cmp(self.time, other.time)
20
21 def __call__(self):
22 f = self.func
23 self.func = None
24 if f:
25 return f()
26
27 def cancel(self):
28 assert self.func is not None
29 self.func = None
30
31 def schedule(delay, func, args=[], kwargs={}):
32 task = Task(delay, func, args, kwargs)
33 heapq.heappush(tasks, task)
34 return task
35
36 def loop(timeout=30.0, use_poll=False):
37 global running
38 running = True
39 oldhandler = signal.signal(signal.SIGTERM, exit)
40
41 if use_poll:
42 if hasattr(select, 'poll'):
43 poll_fun = asyncore.poll3
44 else:
45 poll_fun = asyncore.poll2
46 else:
47 poll_fun = asyncore.poll
48
49 while running:
50 now = time.time()
51 while tasks and tasks[0].time < now:
52 task = heapq.heappop(tasks)
53 task()
54
55 t = timeout
56 if tasks:
57 t = max(min(t, tasks[0].time - now), 0)
58
59 poll_fun(timeout=t)
60
61 signal.signal(signal.SIGTERM, oldhandler)
62
63 def exit(*args):
64 global running
65 running = False
66
67 __all__ = ("schedule", "loop", "exit")
68