Mon, 22 Jan 2018 21:07:34 +0000
Generalisation of scheduler thread to general queue threads
49 | 1 | # |
2 | # Scheduler for Borgend | |
3 | # | |
4 | # This module simply provide a way for other threads to until a given time | |
5 | # | |
6 | ||
7 | import time | |
8 | import borgend | |
9 | from threading import Condition, Lock, Thread | |
10 | ||
11 | logger=borgend.logger.getChild(__name__) | |
12 | ||
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
13 | class QueuedEvent: |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
14 | def __init__(self, cond, name=None): |
49 | 15 | self.next=None |
16 | self.prev=None | |
17 | self.name=name | |
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
18 | self.cond=cond |
49 | 19 | |
20 | def __lt__(self, other): | |
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
21 | return False |
49 | 22 | |
23 | def __gt__(self, other): | |
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
24 | return True |
49 | 25 | |
26 | def insert_after(self, ev): | |
27 | if not self.next: | |
28 | ev.prev=self | |
29 | self.next=ev | |
30 | ev.next=None | |
31 | elif self.next>ev: | |
32 | self.insert_immediately_after(ev) | |
33 | else: | |
34 | self.next.insert_after(ev) | |
35 | ||
36 | def insert_immediately_after(self, ev): | |
37 | ev.prev=self | |
38 | ev.next=self.next | |
39 | if ev.next: | |
40 | ev.next.prev=ev | |
41 | self.next=ev | |
42 | ||
43 | def unlink(self): | |
44 | n=self.next | |
45 | p=self.prev | |
46 | if n: | |
47 | n.prev=p | |
48 | if p: | |
49 | p.next=n | |
50 | ||
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
51 | class ScheduledEvent(QueuedEvent): |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
52 | def __init__(self, when, cond, name=None): |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
53 | super().__init__(cond, name) |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
54 | self.when=when |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
55 | |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
56 | def __lt__(self, other): |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
57 | return self.when < other.when |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
58 | |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
59 | def __gt__(self, other): |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
60 | return self.when > other.when |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
61 | |
49 | 62 | class TerminableThread(Thread): |
63 | def __init__(self, *args, **kwargs): | |
64 | super().__init__(*args, **kwargs) | |
65 | self._terminate=False | |
66 | self._cond=Condition() | |
67 | ||
68 | def terminate(self): | |
69 | with self._cond: | |
70 | _terminate=True | |
71 | self._cond.notify() | |
72 | ||
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
73 | class QueueThread(TerminableThread): |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
74 | def __init__(self, *args, **kwargs): |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
75 | self._list = None |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
76 | super().__init__(*args, **kwargs) |
49 | 77 | |
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
78 | def _insert(self, ev): |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
79 | if not self._list: |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
80 | self._list=ev |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
81 | elif self._list > ev: |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
82 | ev.insert_immediately_after(self._list) |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
83 | self._list=ev |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
84 | else: |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
85 | self._list.insert_immediately_after(ev) |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
86 | |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
87 | self._cond.notify() |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
88 | |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
89 | def _wait(self, ev): |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
90 | with self._cond: |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
91 | self._insert(ev) |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
92 | # This will release the lock on cond, allowing queue manager (scheduler) |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
93 | # thread to notify us if we are already to be released |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
94 | ev.cond.wait() |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
95 | |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
96 | # If we were woken up by some other event, not the scheduler, |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
97 | # ensure the event is removed |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
98 | with self._cond: |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
99 | if ev==self._list: |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
100 | self._list=ev.next |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
101 | ev.unlink() |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
102 | |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
103 | def _pop(self): |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
104 | ev=self._list |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
105 | logger.info("%s: Found event %s" % self.name(), str(ev.name)) |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
106 | self._list=ev.next |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
107 | ev.unlink() |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
108 | ev.cond.acquire() |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
109 | ev.cond.notifyAll() |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
110 | ev.cond.release() |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
111 | |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
112 | |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
113 | class Scheduler(QueueThread): |
49 | 114 | # Default to precision of 60 seconds: the scheduler thread will never |
115 | # sleep longer than that, to get quickly back on track with the schedule | |
116 | # when the computer wakes up from sleep | |
117 | def __init__(self, precision=60): | |
118 | self.precision = precision | |
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
119 | self._next_event_time = None |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
120 | self._list = None |
49 | 121 | super().__init__(target = self.__scheduler_thread, name = 'Scheduler') |
122 | self.daemon=True | |
123 | ||
124 | def __scheduler_thread(self): | |
125 | with self._cond: | |
126 | while not self._terminate: | |
127 | now = time.monotonic() | |
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
128 | if not self._list: |
49 | 129 | timeout = None |
130 | else: | |
131 | # Wait at most precision seconds, or until next event if it | |
132 | # comes earlier | |
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
133 | timeout=min(self.precision, self._list.when-now) |
49 | 134 | |
135 | if not timeout or timeout>0: | |
136 | self._cond.wait(timeout) | |
137 | now = time.monotonic() | |
138 | ||
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
139 | while self._list and self._list.when <= now: |
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
140 | self._pop() |
49 | 141 | |
142 | # cond has to be acquired on entry! | |
143 | def wait_until(self, when, cond, name=None): | |
53
442c558bd632
Generalisation of scheduler thread to general queue threads
Tuomo Valkonen <tuomov@iki.fi>
parents:
49
diff
changeset
|
144 | self._wait(ScheduledEvent(when, cond, name)) |
49 | 145 |