diff options
Diffstat (limited to 'bitbake/lib/bb/event.py')
-rw-r--r-- | bitbake/lib/bb/event.py | 211 |
1 files changed, 134 insertions, 77 deletions
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py index 23e1f3187b..ddf1006c29 100644 --- a/bitbake/lib/bb/event.py +++ b/bitbake/lib/bb/event.py | |||
@@ -19,7 +19,6 @@ import sys | |||
19 | import threading | 19 | import threading |
20 | import traceback | 20 | import traceback |
21 | 21 | ||
22 | import bb.exceptions | ||
23 | import bb.utils | 22 | import bb.utils |
24 | 23 | ||
25 | # This is the pid for which we should generate the event. This is set when | 24 | # This is the pid for which we should generate the event. This is set when |
@@ -40,7 +39,7 @@ class HeartbeatEvent(Event): | |||
40 | """Triggered at regular time intervals of 10 seconds. Other events can fire much more often | 39 | """Triggered at regular time intervals of 10 seconds. Other events can fire much more often |
41 | (runQueueTaskStarted when there are many short tasks) or not at all for long periods | 40 | (runQueueTaskStarted when there are many short tasks) or not at all for long periods |
42 | of time (again runQueueTaskStarted, when there is just one long-running task), so this | 41 | of time (again runQueueTaskStarted, when there is just one long-running task), so this |
43 | event is more suitable for doing some task-independent work occassionally.""" | 42 | event is more suitable for doing some task-independent work occasionally.""" |
44 | def __init__(self, time): | 43 | def __init__(self, time): |
45 | Event.__init__(self) | 44 | Event.__init__(self) |
46 | self.time = time | 45 | self.time = time |
@@ -68,29 +67,39 @@ _catchall_handlers = {} | |||
68 | _eventfilter = None | 67 | _eventfilter = None |
69 | _uiready = False | 68 | _uiready = False |
70 | _thread_lock = threading.Lock() | 69 | _thread_lock = threading.Lock() |
71 | _thread_lock_enabled = False | 70 | _heartbeat_enabled = False |
72 | 71 | _should_exit = threading.Event() | |
73 | if hasattr(__builtins__, '__setitem__'): | ||
74 | builtins = __builtins__ | ||
75 | else: | ||
76 | builtins = __builtins__.__dict__ | ||
77 | 72 | ||
78 | def enable_threadlock(): | 73 | def enable_threadlock(): |
79 | global _thread_lock_enabled | 74 | # Always needed now |
80 | _thread_lock_enabled = True | 75 | return |
81 | 76 | ||
82 | def disable_threadlock(): | 77 | def disable_threadlock(): |
83 | global _thread_lock_enabled | 78 | # Always needed now |
84 | _thread_lock_enabled = False | 79 | return |
80 | |||
81 | def enable_heartbeat(): | ||
82 | global _heartbeat_enabled | ||
83 | _heartbeat_enabled = True | ||
84 | |||
85 | def disable_heartbeat(): | ||
86 | global _heartbeat_enabled | ||
87 | _heartbeat_enabled = False | ||
88 | |||
89 | # | ||
90 | # In long running code, this function should be called periodically | ||
91 | # to check if we should exit due to an interuption (.e.g Ctrl+C from the UI) | ||
92 | # | ||
93 | def check_for_interrupts(): | ||
94 | global _should_exit | ||
95 | if _should_exit.is_set(): | ||
96 | bb.warn("Exiting due to interrupt.") | ||
97 | raise bb.BBHandledException() | ||
85 | 98 | ||
86 | def execute_handler(name, handler, event, d): | 99 | def execute_handler(name, handler, event, d): |
87 | event.data = d | 100 | event.data = d |
88 | addedd = False | ||
89 | if 'd' not in builtins: | ||
90 | builtins['d'] = d | ||
91 | addedd = True | ||
92 | try: | 101 | try: |
93 | ret = handler(event) | 102 | ret = handler(event, d) |
94 | except (bb.parse.SkipRecipe, bb.BBHandledException): | 103 | except (bb.parse.SkipRecipe, bb.BBHandledException): |
95 | raise | 104 | raise |
96 | except Exception: | 105 | except Exception: |
@@ -104,8 +113,7 @@ def execute_handler(name, handler, event, d): | |||
104 | raise | 113 | raise |
105 | finally: | 114 | finally: |
106 | del event.data | 115 | del event.data |
107 | if addedd: | 116 | |
108 | del builtins['d'] | ||
109 | 117 | ||
110 | def fire_class_handlers(event, d): | 118 | def fire_class_handlers(event, d): |
111 | if isinstance(event, logging.LogRecord): | 119 | if isinstance(event, logging.LogRecord): |
@@ -118,7 +126,7 @@ def fire_class_handlers(event, d): | |||
118 | if _eventfilter: | 126 | if _eventfilter: |
119 | if not _eventfilter(name, handler, event, d): | 127 | if not _eventfilter(name, handler, event, d): |
120 | continue | 128 | continue |
121 | if d and not name in (d.getVar("__BBHANDLERS_MC") or []): | 129 | if d is not None and not name in (d.getVar("__BBHANDLERS_MC") or set()): |
122 | continue | 130 | continue |
123 | execute_handler(name, handler, event, d) | 131 | execute_handler(name, handler, event, d) |
124 | 132 | ||
@@ -132,8 +140,14 @@ def print_ui_queue(): | |||
132 | if not _uiready: | 140 | if not _uiready: |
133 | from bb.msg import BBLogFormatter | 141 | from bb.msg import BBLogFormatter |
134 | # Flush any existing buffered content | 142 | # Flush any existing buffered content |
135 | sys.stdout.flush() | 143 | try: |
136 | sys.stderr.flush() | 144 | sys.stdout.flush() |
145 | except: | ||
146 | pass | ||
147 | try: | ||
148 | sys.stderr.flush() | ||
149 | except: | ||
150 | pass | ||
137 | stdout = logging.StreamHandler(sys.stdout) | 151 | stdout = logging.StreamHandler(sys.stdout) |
138 | stderr = logging.StreamHandler(sys.stderr) | 152 | stderr = logging.StreamHandler(sys.stderr) |
139 | formatter = BBLogFormatter("%(levelname)s: %(message)s") | 153 | formatter = BBLogFormatter("%(levelname)s: %(message)s") |
@@ -174,36 +188,38 @@ def print_ui_queue(): | |||
174 | 188 | ||
175 | def fire_ui_handlers(event, d): | 189 | def fire_ui_handlers(event, d): |
176 | global _thread_lock | 190 | global _thread_lock |
177 | global _thread_lock_enabled | ||
178 | 191 | ||
179 | if not _uiready: | 192 | if not _uiready: |
180 | # No UI handlers registered yet, queue up the messages | 193 | # No UI handlers registered yet, queue up the messages |
181 | ui_queue.append(event) | 194 | ui_queue.append(event) |
182 | return | 195 | return |
183 | 196 | ||
184 | if _thread_lock_enabled: | 197 | with bb.utils.lock_timeout_nocheck(_thread_lock) as lock: |
185 | _thread_lock.acquire() | 198 | if not lock: |
186 | 199 | # If we can't get the lock, we may be recursively called, queue and return | |
187 | errors = [] | 200 | ui_queue.append(event) |
188 | for h in _ui_handlers: | 201 | return |
189 | #print "Sending event %s" % event | ||
190 | try: | ||
191 | if not _ui_logfilters[h].filter(event): | ||
192 | continue | ||
193 | # We use pickle here since it better handles object instances | ||
194 | # which xmlrpc's marshaller does not. Events *must* be serializable | ||
195 | # by pickle. | ||
196 | if hasattr(_ui_handlers[h].event, "sendpickle"): | ||
197 | _ui_handlers[h].event.sendpickle((pickle.dumps(event))) | ||
198 | else: | ||
199 | _ui_handlers[h].event.send(event) | ||
200 | except: | ||
201 | errors.append(h) | ||
202 | for h in errors: | ||
203 | del _ui_handlers[h] | ||
204 | 202 | ||
205 | if _thread_lock_enabled: | 203 | errors = [] |
206 | _thread_lock.release() | 204 | for h in _ui_handlers: |
205 | #print "Sending event %s" % event | ||
206 | try: | ||
207 | if not _ui_logfilters[h].filter(event): | ||
208 | continue | ||
209 | # We use pickle here since it better handles object instances | ||
210 | # which xmlrpc's marshaller does not. Events *must* be serializable | ||
211 | # by pickle. | ||
212 | if hasattr(_ui_handlers[h].event, "sendpickle"): | ||
213 | _ui_handlers[h].event.sendpickle((pickle.dumps(event))) | ||
214 | else: | ||
215 | _ui_handlers[h].event.send(event) | ||
216 | except: | ||
217 | errors.append(h) | ||
218 | for h in errors: | ||
219 | del _ui_handlers[h] | ||
220 | |||
221 | while ui_queue: | ||
222 | fire_ui_handlers(ui_queue.pop(), d) | ||
207 | 223 | ||
208 | def fire(event, d): | 224 | def fire(event, d): |
209 | """Fire off an Event""" | 225 | """Fire off an Event""" |
@@ -220,9 +236,12 @@ def fire(event, d): | |||
220 | # If messages have been queued up, clear the queue | 236 | # If messages have been queued up, clear the queue |
221 | global _uiready, ui_queue | 237 | global _uiready, ui_queue |
222 | if _uiready and ui_queue: | 238 | if _uiready and ui_queue: |
223 | for queue_event in ui_queue: | 239 | with bb.utils.lock_timeout_nocheck(_thread_lock): |
240 | queue = ui_queue | ||
241 | ui_queue = [] | ||
242 | for queue_event in queue: | ||
224 | fire_ui_handlers(queue_event, d) | 243 | fire_ui_handlers(queue_event, d) |
225 | ui_queue = [] | 244 | |
226 | fire_ui_handlers(event, d) | 245 | fire_ui_handlers(event, d) |
227 | 246 | ||
228 | def fire_from_worker(event, d): | 247 | def fire_from_worker(event, d): |
@@ -232,26 +251,31 @@ noop = lambda _: None | |||
232 | def register(name, handler, mask=None, filename=None, lineno=None, data=None): | 251 | def register(name, handler, mask=None, filename=None, lineno=None, data=None): |
233 | """Register an Event handler""" | 252 | """Register an Event handler""" |
234 | 253 | ||
235 | if data and data.getVar("BB_CURRENT_MC"): | 254 | if data is not None and data.getVar("BB_CURRENT_MC"): |
236 | mc = data.getVar("BB_CURRENT_MC") | 255 | mc = data.getVar("BB_CURRENT_MC") |
237 | name = '%s%s' % (mc.replace('-', '_'), name) | 256 | name = '%s%s' % (mc.replace('-', '_'), name) |
238 | 257 | ||
239 | # already registered | 258 | # already registered |
240 | if name in _handlers: | 259 | if name in _handlers: |
260 | if data is not None: | ||
261 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set()) | ||
262 | bbhands_mc.add(name) | ||
263 | data.setVar("__BBHANDLERS_MC", bbhands_mc) | ||
241 | return AlreadyRegistered | 264 | return AlreadyRegistered |
242 | 265 | ||
243 | if handler is not None: | 266 | if handler is not None: |
244 | # handle string containing python code | 267 | # handle string containing python code |
245 | if isinstance(handler, str): | 268 | if isinstance(handler, str): |
246 | tmp = "def %s(e):\n%s" % (name, handler) | 269 | tmp = "def %s(e, d):\n%s" % (name, handler) |
270 | # Inject empty lines to make code match lineno in filename | ||
271 | if lineno is not None: | ||
272 | tmp = "\n" * (lineno-1) + tmp | ||
247 | try: | 273 | try: |
248 | code = bb.methodpool.compile_cache(tmp) | 274 | code = bb.methodpool.compile_cache(tmp) |
249 | if not code: | 275 | if not code: |
250 | if filename is None: | 276 | if filename is None: |
251 | filename = "%s(e)" % name | 277 | filename = "%s(e, d)" % name |
252 | code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST) | 278 | code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST) |
253 | if lineno is not None: | ||
254 | ast.increment_lineno(code, lineno-1) | ||
255 | code = compile(code, filename, "exec") | 279 | code = compile(code, filename, "exec") |
256 | bb.methodpool.compile_cache_add(tmp, code) | 280 | bb.methodpool.compile_cache_add(tmp, code) |
257 | except SyntaxError: | 281 | except SyntaxError: |
@@ -274,16 +298,16 @@ def register(name, handler, mask=None, filename=None, lineno=None, data=None): | |||
274 | _event_handler_map[m] = {} | 298 | _event_handler_map[m] = {} |
275 | _event_handler_map[m][name] = True | 299 | _event_handler_map[m][name] = True |
276 | 300 | ||
277 | if data: | 301 | if data is not None: |
278 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or []) | 302 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set()) |
279 | bbhands_mc.append(name) | 303 | bbhands_mc.add(name) |
280 | data.setVar("__BBHANDLERS_MC", bbhands_mc) | 304 | data.setVar("__BBHANDLERS_MC", bbhands_mc) |
281 | 305 | ||
282 | return Registered | 306 | return Registered |
283 | 307 | ||
284 | def remove(name, handler, data=None): | 308 | def remove(name, handler, data=None): |
285 | """Remove an Event handler""" | 309 | """Remove an Event handler""" |
286 | if data: | 310 | if data is not None: |
287 | if data.getVar("BB_CURRENT_MC"): | 311 | if data.getVar("BB_CURRENT_MC"): |
288 | mc = data.getVar("BB_CURRENT_MC") | 312 | mc = data.getVar("BB_CURRENT_MC") |
289 | name = '%s%s' % (mc.replace('-', '_'), name) | 313 | name = '%s%s' % (mc.replace('-', '_'), name) |
@@ -295,8 +319,8 @@ def remove(name, handler, data=None): | |||
295 | if name in _event_handler_map[event]: | 319 | if name in _event_handler_map[event]: |
296 | _event_handler_map[event].pop(name) | 320 | _event_handler_map[event].pop(name) |
297 | 321 | ||
298 | if data: | 322 | if data is not None: |
299 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or []) | 323 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set()) |
300 | if name in bbhands_mc: | 324 | if name in bbhands_mc: |
301 | bbhands_mc.remove(name) | 325 | bbhands_mc.remove(name) |
302 | data.setVar("__BBHANDLERS_MC", bbhands_mc) | 326 | data.setVar("__BBHANDLERS_MC", bbhands_mc) |
@@ -313,21 +337,23 @@ def set_eventfilter(func): | |||
313 | _eventfilter = func | 337 | _eventfilter = func |
314 | 338 | ||
315 | def register_UIHhandler(handler, mainui=False): | 339 | def register_UIHhandler(handler, mainui=False): |
316 | bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 | 340 | with bb.utils.lock_timeout(_thread_lock): |
317 | _ui_handlers[_ui_handler_seq] = handler | 341 | bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 |
318 | level, debug_domains = bb.msg.constructLogOptions() | 342 | _ui_handlers[_ui_handler_seq] = handler |
319 | _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains) | 343 | level, debug_domains = bb.msg.constructLogOptions() |
320 | if mainui: | 344 | _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains) |
321 | global _uiready | 345 | if mainui: |
322 | _uiready = _ui_handler_seq | 346 | global _uiready |
323 | return _ui_handler_seq | 347 | _uiready = _ui_handler_seq |
348 | return _ui_handler_seq | ||
324 | 349 | ||
325 | def unregister_UIHhandler(handlerNum, mainui=False): | 350 | def unregister_UIHhandler(handlerNum, mainui=False): |
326 | if mainui: | 351 | if mainui: |
327 | global _uiready | 352 | global _uiready |
328 | _uiready = False | 353 | _uiready = False |
329 | if handlerNum in _ui_handlers: | 354 | with bb.utils.lock_timeout(_thread_lock): |
330 | del _ui_handlers[handlerNum] | 355 | if handlerNum in _ui_handlers: |
356 | del _ui_handlers[handlerNum] | ||
331 | return | 357 | return |
332 | 358 | ||
333 | def get_uihandler(): | 359 | def get_uihandler(): |
@@ -408,6 +434,16 @@ class RecipeEvent(Event): | |||
408 | self.fn = fn | 434 | self.fn = fn |
409 | Event.__init__(self) | 435 | Event.__init__(self) |
410 | 436 | ||
437 | class RecipePreDeferredInherits(RecipeEvent): | ||
438 | """ | ||
439 | Called before deferred inherits are processed so code can snoop on class extensions for example | ||
440 | Limitations: It won't see inherits of inherited classes and the data is unexpanded | ||
441 | """ | ||
442 | def __init__(self, fn, inherits): | ||
443 | self.fn = fn | ||
444 | self.inherits = inherits | ||
445 | Event.__init__(self) | ||
446 | |||
411 | class RecipePreFinalise(RecipeEvent): | 447 | class RecipePreFinalise(RecipeEvent): |
412 | """ Recipe Parsing Complete but not yet finalised""" | 448 | """ Recipe Parsing Complete but not yet finalised""" |
413 | 449 | ||
@@ -482,7 +518,7 @@ class BuildCompleted(BuildBase, OperationCompleted): | |||
482 | BuildBase.__init__(self, n, p, failures) | 518 | BuildBase.__init__(self, n, p, failures) |
483 | 519 | ||
484 | class DiskFull(Event): | 520 | class DiskFull(Event): |
485 | """Disk full case build aborted""" | 521 | """Disk full case build halted""" |
486 | def __init__(self, dev, type, freespace, mountpoint): | 522 | def __init__(self, dev, type, freespace, mountpoint): |
487 | Event.__init__(self) | 523 | Event.__init__(self) |
488 | self._dev = dev | 524 | self._dev = dev |
@@ -666,6 +702,17 @@ class ReachableStamps(Event): | |||
666 | Event.__init__(self) | 702 | Event.__init__(self) |
667 | self.stamps = stamps | 703 | self.stamps = stamps |
668 | 704 | ||
705 | class StaleSetSceneTasks(Event): | ||
706 | """ | ||
707 | An event listing setscene tasks which are 'stale' and will | ||
708 | be rerun. The metadata may use to clean up stale data. | ||
709 | tasks is a mapping of tasks and matching stale stamps. | ||
710 | """ | ||
711 | |||
712 | def __init__(self, tasks): | ||
713 | Event.__init__(self) | ||
714 | self.tasks = tasks | ||
715 | |||
669 | class FilesMatchingFound(Event): | 716 | class FilesMatchingFound(Event): |
670 | """ | 717 | """ |
671 | Event when a list of files matching the supplied pattern has | 718 | Event when a list of files matching the supplied pattern has |
@@ -732,13 +779,7 @@ class LogHandler(logging.Handler): | |||
732 | 779 | ||
733 | def emit(self, record): | 780 | def emit(self, record): |
734 | if record.exc_info: | 781 | if record.exc_info: |
735 | etype, value, tb = record.exc_info | 782 | record.bb_exc_formatted = traceback.format_exception(*record.exc_info) |
736 | if hasattr(tb, 'tb_next'): | ||
737 | tb = list(bb.exceptions.extract_traceback(tb, context=3)) | ||
738 | # Need to turn the value into something the logging system can pickle | ||
739 | record.bb_exc_info = (etype, value, tb) | ||
740 | record.bb_exc_formatted = bb.exceptions.format_exception(etype, value, tb, limit=5) | ||
741 | value = str(value) | ||
742 | record.exc_info = None | 783 | record.exc_info = None |
743 | fire(record, None) | 784 | fire(record, None) |
744 | 785 | ||
@@ -749,7 +790,7 @@ class LogHandler(logging.Handler): | |||
749 | class MetadataEvent(Event): | 790 | class MetadataEvent(Event): |
750 | """ | 791 | """ |
751 | Generic event that target for OE-Core classes | 792 | Generic event that target for OE-Core classes |
752 | to report information during asynchrous execution | 793 | to report information during asynchronous execution |
753 | """ | 794 | """ |
754 | def __init__(self, eventtype, eventdata): | 795 | def __init__(self, eventtype, eventdata): |
755 | Event.__init__(self) | 796 | Event.__init__(self) |
@@ -830,3 +871,19 @@ class FindSigInfoResult(Event): | |||
830 | def __init__(self, result): | 871 | def __init__(self, result): |
831 | Event.__init__(self) | 872 | Event.__init__(self) |
832 | self.result = result | 873 | self.result = result |
874 | |||
875 | class GetTaskSignatureResult(Event): | ||
876 | """ | ||
877 | Event to return results from GetTaskSignatures command | ||
878 | """ | ||
879 | def __init__(self, sig): | ||
880 | Event.__init__(self) | ||
881 | self.sig = sig | ||
882 | |||
883 | class ParseError(Event): | ||
884 | """ | ||
885 | Event to indicate parse failed | ||
886 | """ | ||
887 | def __init__(self, msg): | ||
888 | super().__init__() | ||
889 | self._msg = msg | ||