149 |
149 |
150 def _scheduler_thread(self): |
150 def _scheduler_thread(self): |
151 logger.debug("Scheduler thread started") |
151 logger.debug("Scheduler thread started") |
152 with self._cond: |
152 with self._cond: |
153 while not self._terminate: |
153 while not self._terminate: |
154 snapshot = dreamtime.Snapshot() |
154 try: |
155 now = snapshot.monotonic() |
155 self.__schedule_one() |
156 if not self._list: |
156 except: |
157 timeout = None |
157 logger.exception("Bug in scheduler") |
158 else: |
158 |
159 delta = self._list.when.horizon(snapshot)-now |
159 def __schedule_one(self): |
160 if delta==math.inf: |
160 snapshot = dreamtime.Snapshot() |
161 timeout=None |
161 now = snapshot.monotonic() |
162 else: |
162 if not self._list: |
163 timeout = min(self.precision, delta) |
163 timeout = None |
164 |
164 delta = None |
165 if not timeout or timeout>0: |
165 nextname = None |
166 logger.debug("Scheduler waiting %s seconds" % str(timeout)) |
166 else: |
167 self._cond.wait(timeout) |
167 nextname=self._list.name |
168 snapshot = dreamtime.Snapshot() |
168 delta = self._list.when.horizon(snapshot)-now |
169 now = snapshot.monotonic() |
169 if delta==math.inf: |
170 |
170 timeout=None |
171 logger.debug("Scheduler timed out") |
171 else: |
172 |
172 timeout = min(self.precision, delta) |
173 while self._list and self._list.when.horizon(snapshot) <= now: |
173 |
174 ev=self._list |
174 if not timeout or timeout>0: |
175 logger.debug("Scheduler activating %s" % (ev.name or "(unknown)")) |
175 logger.debug("Scheduler waiting %s seconds [next event '%s' in %s seconds]" |
176 # We are only allowed to remove ev from list when ev.cond allows |
176 % (str(timeout), nextname, str(delta))) |
177 self._unlink(ev) |
177 self._cond.wait(timeout) |
178 # We need to release the lock on self._cond before acquire |
178 snapshot = dreamtime.Snapshot() |
179 # one ev.cond to avoid race conditions with self._wait |
179 now = snapshot.monotonic() |
180 self._cond.release() |
180 logger.debug("Scheduler timed out") |
181 with ev.cond: |
181 |
182 ev.cond.notify_all() |
182 while self._list and self._list.when.horizon(snapshot) <= now: |
183 self._cond.acquire() |
183 ev=self._list |
|
184 logger.debug("Scheduler activating %s" % (ev.name or "(unknown)")) |
|
185 # We are only allowed to remove ev from list when ev.cond allows |
|
186 self._unlink(ev) |
|
187 # We need to release the lock on self._cond before acquire |
|
188 # one ev.cond to avoid race conditions with self._wait |
|
189 self._cond.release() |
|
190 with ev.cond: |
|
191 ev.cond.notify_all() |
|
192 self._cond.acquire() |
184 |
193 |
185 |
194 |
186 def _sleepwake_callback(self, woke): |
195 def _sleepwake_callback(self, woke): |
187 logger.debug("Rescheduling events after sleep/wakeup") |
196 logger.debug("Rescheduling events after sleep/wakeup") |
188 with self._cond: |
197 with self._cond: |
209 self._unlink(ev) |
218 self._unlink(ev) |
210 #ev.cond.acquire() |
219 #ev.cond.acquire() |
211 |
220 |
212 # cond has to be acquired on entry! |
221 # cond has to be acquired on entry! |
213 def wait_until(self, when, cond, name=None): |
222 def wait_until(self, when, cond, name=None): |
214 logger.debug("Scheduling '%s' in %s seconds [%s]" % |
223 logger.info("Scheduling '%s' in %0.01f seconds / on %s [%s]" % |
215 (name, when.seconds_to(), when.__class__.__name__)) |
224 (name, when.seconds_to(), when.isoformat(), |
|
225 when.__class__.__name__)) |
216 self._wait(ScheduledEvent(when, cond, name)) |
226 self._wait(ScheduledEvent(when, cond, name)) |
217 |
227 |