Gentoo Archives: gentoo-commits

From: Zac Medico <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: pym/_emerge/
Date: Tue, 07 Feb 2012 23:04:38
Message-Id: fa983106fac83ca29f242cca37ce8ddf565f92d6.zmedico@gentoo
1 commit: fa983106fac83ca29f242cca37ce8ddf565f92d6
2 Author: Zac Medico <zmedico <AT> gentoo <DOT> org>
3 AuthorDate: Tue Feb 7 19:40:55 2012 +0000
4 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org>
5 CommitDate: Tue Feb 7 19:40:55 2012 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=fa983106
7
8 PollScheduler: timeouts regardless of IO events
9
10 Now PollScheduler will execute timeouts predictably, even when there
11 no IO events being generated. This allows the Scheduler's display
12 updates to be handled via timeout_add.
13
14 ---
15 pym/_emerge/JobStatusDisplay.py | 10 ++++--
16 pym/_emerge/PollScheduler.py | 59 +++++++++++++++++++++++++++++++++------
17 pym/_emerge/Scheduler.py | 46 ++----------------------------
18 3 files changed, 59 insertions(+), 56 deletions(-)
19
20 diff --git a/pym/_emerge/JobStatusDisplay.py b/pym/_emerge/JobStatusDisplay.py
21 index 877a0c9..d84d1b0 100644
22 --- a/pym/_emerge/JobStatusDisplay.py
23 +++ b/pym/_emerge/JobStatusDisplay.py
24 @@ -209,24 +209,26 @@ class JobStatusDisplay(object):
25 def display(self):
26 """
27 Display status on stdout, but only if something has
28 - changed since the last call.
29 + changed since the last call. This always returns True,
30 + for continuous scheduling via timeout_add.
31 """
32
33 if self.quiet:
34 - return
35 + return True
36
37 current_time = time.time()
38 time_delta = current_time - self._last_display_time
39 if self._displayed and \
40 not self._changed:
41 if not self._isatty:
42 - return
43 + return True
44 if time_delta < self._min_display_latency:
45 - return
46 + return True
47
48 self._last_display_time = current_time
49 self._changed = False
50 self._display_status()
51 + return True
52
53 def _display_status(self):
54 # Don't use len(self._completed_tasks) here since that also
55
56 diff --git a/pym/_emerge/PollScheduler.py b/pym/_emerge/PollScheduler.py
57 index fd57359..757d12e 100644
58 --- a/pym/_emerge/PollScheduler.py
59 +++ b/pym/_emerge/PollScheduler.py
60 @@ -43,6 +43,7 @@ class PollScheduler(object):
61 # Increment id for each new handler.
62 self._event_handler_id = 0
63 self._timeout_handlers = {}
64 + self._timeout_interval = None
65 self._poll_obj = create_poll_instance()
66 self._polling = False
67 self._scheduling = False
68 @@ -142,18 +143,51 @@ class PollScheduler(object):
69 return True
70
71 def _poll(self, timeout=None):
72 - """
73 - All poll() calls pass through here. The poll events
74 - are added directly to self._poll_event_queue.
75 - In order to avoid endless blocking, this raises
76 - StopIteration if timeout is None and there are
77 - no file descriptors to poll.
78 - """
79 if self._polling:
80 return
81 self._polling = True
82 try:
83 - self._do_poll(timeout=timeout)
84 + if self._timeout_interval is None:
85 + self._run_timeouts()
86 + self._do_poll(timeout=timeout)
87 +
88 + elif timeout is None:
89 + while True:
90 + self._run_timeouts()
91 + previous_count = len(self._poll_event_queue)
92 + self._do_poll(timeout=self._timeout_interval)
93 + if previous_count != len(self._poll_event_queue):
94 + break
95 +
96 + elif timeout <= self._timeout_interval:
97 + self._run_timeouts()
98 + self._do_poll(timeout=timeout)
99 +
100 + else:
101 + remaining_timeout = timeout
102 + start_time = time.time()
103 + while True:
104 + self._run_timeouts()
105 + # _timeout_interval can change each time
106 + # _run_timeouts is called
107 + min_timeout = remaining_timeout
108 + if self._timeout_interval is not None and \
109 + self._timeout_interval < min_timeout:
110 + min_timeout = self._timeout_interval
111 +
112 + previous_count = len(self._poll_event_queue)
113 + self._do_poll(timeout=min_timeout)
114 + if previous_count != len(self._poll_event_queue):
115 + break
116 + elapsed_time = time.time() - start_time
117 + if elapsed_time < 0:
118 + # The system clock has changed such that start_time
119 + # is now in the future, so just assume that the
120 + # timeout has already elapsed.
121 + break
122 + remaining_timeout = timeout - 1000 * elapsed_time
123 + if remaining_timeout <= 0:
124 + break
125 finally:
126 self._polling = False
127
128 @@ -165,7 +199,6 @@ class PollScheduler(object):
129 StopIteration if timeout is None and there are
130 no file descriptors to poll.
131 """
132 - self._run_timeouts()
133 if not self._poll_event_handlers:
134 self._schedule()
135 if timeout is None and \
136 @@ -273,6 +306,8 @@ class PollScheduler(object):
137 self._timeout_handler_class(
138 interval=interval, function=function, args=args,
139 source_id=source_id, timestamp=time.time())
140 + if self._timeout_interval is None or self._timeout_interval < interval:
141 + self._timeout_interval = interval
142 return source_id
143
144 def _run_timeouts(self):
145 @@ -320,6 +355,12 @@ class PollScheduler(object):
146 """
147 timeout_handler = self._timeout_handlers.pop(reg_id, None)
148 if timeout_handler is not None:
149 + if timeout_handler.interval >= self._timeout_interval:
150 + if self._timeout_handlers:
151 + self._timeout_interval = \
152 + min(x.interval for x in self._timeout_handlers.values())
153 + else:
154 + self._timeout_interval = None
155 return True
156 f = self._poll_event_handler_ids.pop(reg_id, None)
157 if f is None:
158
159 diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py
160 index 5b56650..e6f3e0e 100644
161 --- a/pym/_emerge/Scheduler.py
162 +++ b/pym/_emerge/Scheduler.py
163 @@ -196,6 +196,8 @@ class Scheduler(PollScheduler):
164
165 self._status_display = JobStatusDisplay(
166 xterm_titles=('notitles' not in settings.features))
167 + self._timeout_add(self._max_display_latency,
168 + self._status_display.display)
169 self._max_load = myopts.get("--load-average")
170 max_jobs = myopts.get("--jobs")
171 if max_jobs is None:
172 @@ -352,50 +354,8 @@ class Scheduler(PollScheduler):
173 gc.collect()
174
175 def _poll(self, timeout=None):
176 -
177 self._schedule()
178 -
179 - if timeout is None:
180 - while True:
181 - if not self._poll_event_handlers:
182 - self._schedule()
183 - if not self._poll_event_handlers:
184 - raise StopIteration(
185 - "timeout is None and there are no poll() event handlers")
186 - previous_count = len(self._poll_event_queue)
187 - PollScheduler._poll(self, timeout=self._max_display_latency)
188 - self._status_display.display()
189 - if previous_count != len(self._poll_event_queue):
190 - break
191 -
192 - elif timeout <= self._max_display_latency:
193 - PollScheduler._poll(self, timeout=timeout)
194 - if timeout == 0:
195 - # The display is updated by _schedule() above, so it would be
196 - # redundant to update it here when timeout is 0.
197 - pass
198 - else:
199 - self._status_display.display()
200 -
201 - else:
202 - remaining_timeout = timeout
203 - start_time = time.time()
204 - while True:
205 - previous_count = len(self._poll_event_queue)
206 - PollScheduler._poll(self,
207 - timeout=min(self._max_display_latency, remaining_timeout))
208 - self._status_display.display()
209 - if previous_count != len(self._poll_event_queue):
210 - break
211 - elapsed_time = time.time() - start_time
212 - if elapsed_time < 0:
213 - # The system clock has changed such that start_time
214 - # is now in the future, so just assume that the
215 - # timeout has already elapsed.
216 - break
217 - remaining_timeout = timeout - 1000 * elapsed_time
218 - if remaining_timeout <= 0:
219 - break
220 + PollScheduler._poll(self, timeout=timeout)
221
222 def _set_max_jobs(self, max_jobs):
223 self._max_jobs = max_jobs