summaryrefslogtreecommitdiffstats
path: root/pym
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2012-02-07 11:40:55 -0800
committerZac Medico <zmedico@gentoo.org>2012-02-07 15:23:59 -0800
commita3162633773ce5efd3b1cc459df147c93877d953 (patch)
tree741c30f96144661757b2473b8bd1e336ebd97233 /pym
parent445a6ea22c132f4c06c2cc7c48ec6e7af7116962 (diff)
downloadportage-a3162633773ce5efd3b1cc459df147c93877d953.tar.gz
portage-a3162633773ce5efd3b1cc459df147c93877d953.tar.bz2
portage-a3162633773ce5efd3b1cc459df147c93877d953.zip
PollScheduler: timeouts regardless of IO events
Now PollScheduler will execute timeouts predictably, even when there no IO events being generated. This allows the Scheduler's display updates to be handled via timeout_add.
Diffstat (limited to 'pym')
-rw-r--r--pym/_emerge/JobStatusDisplay.py10
-rw-r--r--pym/_emerge/PollScheduler.py59
-rw-r--r--pym/_emerge/Scheduler.py46
3 files changed, 59 insertions, 56 deletions
diff --git a/pym/_emerge/JobStatusDisplay.py b/pym/_emerge/JobStatusDisplay.py
index 877a0c963..d84d1b060 100644
--- a/pym/_emerge/JobStatusDisplay.py
+++ b/pym/_emerge/JobStatusDisplay.py
@@ -209,24 +209,26 @@ class JobStatusDisplay(object):
def display(self):
"""
Display status on stdout, but only if something has
- changed since the last call.
+ changed since the last call. This always returns True,
+ for continuous scheduling via timeout_add.
"""
if self.quiet:
- return
+ return True
current_time = time.time()
time_delta = current_time - self._last_display_time
if self._displayed and \
not self._changed:
if not self._isatty:
- return
+ return True
if time_delta < self._min_display_latency:
- return
+ return True
self._last_display_time = current_time
self._changed = False
self._display_status()
+ return True
def _display_status(self):
# Don't use len(self._completed_tasks) here since that also
diff --git a/pym/_emerge/PollScheduler.py b/pym/_emerge/PollScheduler.py
index fd573592a..519a3700d 100644
--- a/pym/_emerge/PollScheduler.py
+++ b/pym/_emerge/PollScheduler.py
@@ -43,6 +43,7 @@ class PollScheduler(object):
# Increment id for each new handler.
self._event_handler_id = 0
self._timeout_handlers = {}
+ self._timeout_interval = None
self._poll_obj = create_poll_instance()
self._polling = False
self._scheduling = False
@@ -142,18 +143,51 @@ class PollScheduler(object):
return True
def _poll(self, timeout=None):
- """
- All poll() calls pass through here. The poll events
- are added directly to self._poll_event_queue.
- In order to avoid endless blocking, this raises
- StopIteration if timeout is None and there are
- no file descriptors to poll.
- """
if self._polling:
return
self._polling = True
try:
- self._do_poll(timeout=timeout)
+ if self._timeout_interval is None:
+ self._run_timeouts()
+ self._do_poll(timeout=timeout)
+
+ elif timeout is None:
+ while True:
+ self._run_timeouts()
+ previous_count = len(self._poll_event_queue)
+ self._do_poll(timeout=self._timeout_interval)
+ if previous_count != len(self._poll_event_queue):
+ break
+
+ elif timeout <= self._timeout_interval:
+ self._run_timeouts()
+ self._do_poll(timeout=timeout)
+
+ else:
+ remaining_timeout = timeout
+ start_time = time.time()
+ while True:
+ self._run_timeouts()
+ # _timeout_interval can change each time
+ # _run_timeouts is called
+ min_timeout = remaining_timeout
+ if self._timeout_interval is not None and \
+ self._timeout_interval < min_timeout:
+ min_timeout = self._timeout_interval
+
+ previous_count = len(self._poll_event_queue)
+ self._do_poll(timeout=min_timeout)
+ if previous_count != len(self._poll_event_queue):
+ break
+ elapsed_time = time.time() - start_time
+ if elapsed_time < 0:
+ # The system clock has changed such that start_time
+ # is now in the future, so just assume that the
+ # timeout has already elapsed.
+ break
+ remaining_timeout = timeout - 1000 * elapsed_time
+ if remaining_timeout <= 0:
+ break
finally:
self._polling = False
@@ -165,7 +199,6 @@ class PollScheduler(object):
StopIteration if timeout is None and there are
no file descriptors to poll.
"""
- self._run_timeouts()
if not self._poll_event_handlers:
self._schedule()
if timeout is None and \
@@ -273,6 +306,8 @@ class PollScheduler(object):
self._timeout_handler_class(
interval=interval, function=function, args=args,
source_id=source_id, timestamp=time.time())
+ if self._timeout_interval is None or self._timeout_interval < interval:
+ self._timeout_interval = interval
return source_id
def _run_timeouts(self):
@@ -320,6 +355,12 @@ class PollScheduler(object):
"""
timeout_handler = self._timeout_handlers.pop(reg_id, None)
if timeout_handler is not None:
+ if timeout_handler.interval == self._timeout_interval:
+ if self._timeout_handlers:
+ self._timeout_interval = \
+ min(x.interval for x in self._timeout_handlers.values())
+ else:
+ self._timeout_interval = None
return True
f = self._poll_event_handler_ids.pop(reg_id, None)
if f is None:
diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py
index 5b56650f3..e6f3e0e5c 100644
--- a/pym/_emerge/Scheduler.py
+++ b/pym/_emerge/Scheduler.py
@@ -196,6 +196,8 @@ class Scheduler(PollScheduler):
self._status_display = JobStatusDisplay(
xterm_titles=('notitles' not in settings.features))
+ self._timeout_add(self._max_display_latency,
+ self._status_display.display)
self._max_load = myopts.get("--load-average")
max_jobs = myopts.get("--jobs")
if max_jobs is None:
@@ -352,50 +354,8 @@ class Scheduler(PollScheduler):
gc.collect()
def _poll(self, timeout=None):
-
self._schedule()
-
- if timeout is None:
- while True:
- if not self._poll_event_handlers:
- self._schedule()
- if not self._poll_event_handlers:
- raise StopIteration(
- "timeout is None and there are no poll() event handlers")
- previous_count = len(self._poll_event_queue)
- PollScheduler._poll(self, timeout=self._max_display_latency)
- self._status_display.display()
- if previous_count != len(self._poll_event_queue):
- break
-
- elif timeout <= self._max_display_latency:
- PollScheduler._poll(self, timeout=timeout)
- if timeout == 0:
- # The display is updated by _schedule() above, so it would be
- # redundant to update it here when timeout is 0.
- pass
- else:
- self._status_display.display()
-
- else:
- remaining_timeout = timeout
- start_time = time.time()
- while True:
- previous_count = len(self._poll_event_queue)
- PollScheduler._poll(self,
- timeout=min(self._max_display_latency, remaining_timeout))
- self._status_display.display()
- if previous_count != len(self._poll_event_queue):
- break
- elapsed_time = time.time() - start_time
- if elapsed_time < 0:
- # The system clock has changed such that start_time
- # is now in the future, so just assume that the
- # timeout has already elapsed.
- break
- remaining_timeout = timeout - 1000 * elapsed_time
- if remaining_timeout <= 0:
- break
+ PollScheduler._poll(self, timeout=timeout)
def _set_max_jobs(self, max_jobs):
self._max_jobs = max_jobs