blob: b70a998ab70e11cefe95b0c5fada3a5a96cfa1f8 [file] [log] [blame]
Guido van Rossum2d844d11991-04-07 13:41:50 +00001# Module sched -- a generally useful event scheduler class
2
3# Each instance of this class manages its own queue.
4# No multi-threading is implied; you are supposed to hack that
5# yourself, or use a single instance per application.
6#
7# Each instance is parametrized with two functions, one that is
8# supposed to return the current time, one that is supposed to
9# implement a delay. You can implement fine- or course-grained
10# real-time scheduling by substituting time and sleep or millitimer
11# and millisleep from the built-in module time, or you can implement
12# simulated time by writing your own functions. This can also be
13# used to integrate scheduling with STDWIN events; the delay function
14# is allowed to modify the queue. Time can be expressed
15# as integers or floating point numbers, as long as it is consistent.
16
17# Events are specified by tuples (time, priority, action, argument).
18# As in UNIX, lower priority numbers mean higher priority; in this
19# way the queue can be maintained fully sorted. Execution of the
20# event means calling the action function, passing it the argument.
21# Remember that in Python, multiple function arguments can be packed
22# in a tuple. The action function may be an instance method so it
23# has another way to reference private data (besides global variables).
24# Parameterless functions or methods cannot be used, however.
25
26class scheduler():
27 #
28 # Initialize a new instance, passing the time and delay functions
29 #
30 def init(self, (timefunc, delayfunc)):
31 self.queue = []
32 self.timefunc = timefunc
33 self.delayfunc = delayfunc
34 return self
35 #
36 # Enter a new event in the queue at an absolute time.
37 # Returns an ID for the event which can be used
38 # to remove it, if necessary.
39 #
40 def enterabs(self, event):
41 time, priority, action, argument = event
42 q = self.queue
43 # XXX Could use bisection or linear interpolation?
44 for i in range(len(q)):
45 qtime, qpri, qact, qarg = q[i]
46 if time < qtime: break
47 if time = qtime and priority < qpri: break
48 else:
49 i = len(q)
50 q.insert(i, event)
51 return event # The ID
52 #
53 # A variant that specifies the time as a relative time.
54 # This is actually the more commonly used interface.
55 #
56 def enter(self, (delay, priority, action, argument)):
57 time = self.timefunc() + delay
58 return self.enterabs(time, priority, action, argument)
59 #
60 # Remove an event from the queue.
61 # This must be presented the ID as returned by enter().
62 # If the event is not in the queue, this raises RuntimeError.
63 #
64 def cancel(self, event):
65 self.queue.remove(event)
66 #
67 # Check whether the queue is empty.
68 #
69 def empty(self):
70 return len(self.queue) = 0
71 #
72 # Run: execute events until the queue is empty.
73 #
74 # When there is a positive delay until the first event, the
75 # delay function is called and the event is left in the queue;
76 # otherwise, the event is removed from the queue and executed
77 # (its action function is called, passing it the argument).
78 # If the delay function returns prematurely, it is simply
79 # restarted.
80 #
81 # It is legal for both the delay function and the action
82 # function to to modify the queue or to raise an exception;
83 # exceptions are not caught but the scheduler's state
84 # remains well-defined so run() may be called again.
85 #
86 def run(self):
87 q = self.queue
88 while q:
89 time, priority, action, argument = q[0]
90 now = self.timefunc()
91 if now < time:
92 self.delayfunc(time - now)
93 else:
94 del q[0]
95 void = action(argument)
96 #