summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/event.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/event.py')
-rw-r--r--bitbake/lib/bb/event.py179
1 files changed, 111 insertions, 68 deletions
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py
index 23e1f3187b..4761c86880 100644
--- a/bitbake/lib/bb/event.py
+++ b/bitbake/lib/bb/event.py
@@ -40,7 +40,7 @@ class HeartbeatEvent(Event):
40 """Triggered at regular time intervals of 10 seconds. Other events can fire much more often 40 """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 41 (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 42 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.""" 43 event is more suitable for doing some task-independent work occasionally."""
44 def __init__(self, time): 44 def __init__(self, time):
45 Event.__init__(self) 45 Event.__init__(self)
46 self.time = time 46 self.time = time
@@ -68,29 +68,39 @@ _catchall_handlers = {}
68_eventfilter = None 68_eventfilter = None
69_uiready = False 69_uiready = False
70_thread_lock = threading.Lock() 70_thread_lock = threading.Lock()
71_thread_lock_enabled = False 71_heartbeat_enabled = False
72 72_should_exit = threading.Event()
73if hasattr(__builtins__, '__setitem__'):
74 builtins = __builtins__
75else:
76 builtins = __builtins__.__dict__
77 73
78def enable_threadlock(): 74def enable_threadlock():
79 global _thread_lock_enabled 75 # Always needed now
80 _thread_lock_enabled = True 76 return
81 77
82def disable_threadlock(): 78def disable_threadlock():
83 global _thread_lock_enabled 79 # Always needed now
84 _thread_lock_enabled = False 80 return
81
82def enable_heartbeat():
83 global _heartbeat_enabled
84 _heartbeat_enabled = True
85
86def disable_heartbeat():
87 global _heartbeat_enabled
88 _heartbeat_enabled = False
89
90#
91# In long running code, this function should be called periodically
92# to check if we should exit due to an interuption (.e.g Ctrl+C from the UI)
93#
94def check_for_interrupts(d):
95 global _should_exit
96 if _should_exit.is_set():
97 bb.warn("Exiting due to interrupt.")
98 raise bb.BBHandledException()
85 99
86def execute_handler(name, handler, event, d): 100def execute_handler(name, handler, event, d):
87 event.data = d 101 event.data = d
88 addedd = False
89 if 'd' not in builtins:
90 builtins['d'] = d
91 addedd = True
92 try: 102 try:
93 ret = handler(event) 103 ret = handler(event, d)
94 except (bb.parse.SkipRecipe, bb.BBHandledException): 104 except (bb.parse.SkipRecipe, bb.BBHandledException):
95 raise 105 raise
96 except Exception: 106 except Exception:
@@ -104,8 +114,7 @@ def execute_handler(name, handler, event, d):
104 raise 114 raise
105 finally: 115 finally:
106 del event.data 116 del event.data
107 if addedd: 117
108 del builtins['d']
109 118
110def fire_class_handlers(event, d): 119def fire_class_handlers(event, d):
111 if isinstance(event, logging.LogRecord): 120 if isinstance(event, logging.LogRecord):
@@ -118,7 +127,7 @@ def fire_class_handlers(event, d):
118 if _eventfilter: 127 if _eventfilter:
119 if not _eventfilter(name, handler, event, d): 128 if not _eventfilter(name, handler, event, d):
120 continue 129 continue
121 if d and not name in (d.getVar("__BBHANDLERS_MC") or []): 130 if d is not None and not name in (d.getVar("__BBHANDLERS_MC") or set()):
122 continue 131 continue
123 execute_handler(name, handler, event, d) 132 execute_handler(name, handler, event, d)
124 133
@@ -132,8 +141,14 @@ def print_ui_queue():
132 if not _uiready: 141 if not _uiready:
133 from bb.msg import BBLogFormatter 142 from bb.msg import BBLogFormatter
134 # Flush any existing buffered content 143 # Flush any existing buffered content
135 sys.stdout.flush() 144 try:
136 sys.stderr.flush() 145 sys.stdout.flush()
146 except:
147 pass
148 try:
149 sys.stderr.flush()
150 except:
151 pass
137 stdout = logging.StreamHandler(sys.stdout) 152 stdout = logging.StreamHandler(sys.stdout)
138 stderr = logging.StreamHandler(sys.stderr) 153 stderr = logging.StreamHandler(sys.stderr)
139 formatter = BBLogFormatter("%(levelname)s: %(message)s") 154 formatter = BBLogFormatter("%(levelname)s: %(message)s")
@@ -174,36 +189,30 @@ def print_ui_queue():
174 189
175def fire_ui_handlers(event, d): 190def fire_ui_handlers(event, d):
176 global _thread_lock 191 global _thread_lock
177 global _thread_lock_enabled
178 192
179 if not _uiready: 193 if not _uiready:
180 # No UI handlers registered yet, queue up the messages 194 # No UI handlers registered yet, queue up the messages
181 ui_queue.append(event) 195 ui_queue.append(event)
182 return 196 return
183 197
184 if _thread_lock_enabled: 198 with bb.utils.lock_timeout(_thread_lock):
185 _thread_lock.acquire() 199 errors = []
186 200 for h in _ui_handlers:
187 errors = [] 201 #print "Sending event %s" % event
188 for h in _ui_handlers: 202 try:
189 #print "Sending event %s" % event 203 if not _ui_logfilters[h].filter(event):
190 try: 204 continue
191 if not _ui_logfilters[h].filter(event): 205 # We use pickle here since it better handles object instances
192 continue 206 # which xmlrpc's marshaller does not. Events *must* be serializable
193 # We use pickle here since it better handles object instances 207 # by pickle.
194 # which xmlrpc's marshaller does not. Events *must* be serializable 208 if hasattr(_ui_handlers[h].event, "sendpickle"):
195 # by pickle. 209 _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
196 if hasattr(_ui_handlers[h].event, "sendpickle"): 210 else:
197 _ui_handlers[h].event.sendpickle((pickle.dumps(event))) 211 _ui_handlers[h].event.send(event)
198 else: 212 except:
199 _ui_handlers[h].event.send(event) 213 errors.append(h)
200 except: 214 for h in errors:
201 errors.append(h) 215 del _ui_handlers[h]
202 for h in errors:
203 del _ui_handlers[h]
204
205 if _thread_lock_enabled:
206 _thread_lock.release()
207 216
208def fire(event, d): 217def fire(event, d):
209 """Fire off an Event""" 218 """Fire off an Event"""
@@ -232,26 +241,31 @@ noop = lambda _: None
232def register(name, handler, mask=None, filename=None, lineno=None, data=None): 241def register(name, handler, mask=None, filename=None, lineno=None, data=None):
233 """Register an Event handler""" 242 """Register an Event handler"""
234 243
235 if data and data.getVar("BB_CURRENT_MC"): 244 if data is not None and data.getVar("BB_CURRENT_MC"):
236 mc = data.getVar("BB_CURRENT_MC") 245 mc = data.getVar("BB_CURRENT_MC")
237 name = '%s%s' % (mc.replace('-', '_'), name) 246 name = '%s%s' % (mc.replace('-', '_'), name)
238 247
239 # already registered 248 # already registered
240 if name in _handlers: 249 if name in _handlers:
250 if data is not None:
251 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
252 bbhands_mc.add(name)
253 data.setVar("__BBHANDLERS_MC", bbhands_mc)
241 return AlreadyRegistered 254 return AlreadyRegistered
242 255
243 if handler is not None: 256 if handler is not None:
244 # handle string containing python code 257 # handle string containing python code
245 if isinstance(handler, str): 258 if isinstance(handler, str):
246 tmp = "def %s(e):\n%s" % (name, handler) 259 tmp = "def %s(e, d):\n%s" % (name, handler)
260 # Inject empty lines to make code match lineno in filename
261 if lineno is not None:
262 tmp = "\n" * (lineno-1) + tmp
247 try: 263 try:
248 code = bb.methodpool.compile_cache(tmp) 264 code = bb.methodpool.compile_cache(tmp)
249 if not code: 265 if not code:
250 if filename is None: 266 if filename is None:
251 filename = "%s(e)" % name 267 filename = "%s(e, d)" % name
252 code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST) 268 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") 269 code = compile(code, filename, "exec")
256 bb.methodpool.compile_cache_add(tmp, code) 270 bb.methodpool.compile_cache_add(tmp, code)
257 except SyntaxError: 271 except SyntaxError:
@@ -274,16 +288,16 @@ def register(name, handler, mask=None, filename=None, lineno=None, data=None):
274 _event_handler_map[m] = {} 288 _event_handler_map[m] = {}
275 _event_handler_map[m][name] = True 289 _event_handler_map[m][name] = True
276 290
277 if data: 291 if data is not None:
278 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or []) 292 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
279 bbhands_mc.append(name) 293 bbhands_mc.add(name)
280 data.setVar("__BBHANDLERS_MC", bbhands_mc) 294 data.setVar("__BBHANDLERS_MC", bbhands_mc)
281 295
282 return Registered 296 return Registered
283 297
284def remove(name, handler, data=None): 298def remove(name, handler, data=None):
285 """Remove an Event handler""" 299 """Remove an Event handler"""
286 if data: 300 if data is not None:
287 if data.getVar("BB_CURRENT_MC"): 301 if data.getVar("BB_CURRENT_MC"):
288 mc = data.getVar("BB_CURRENT_MC") 302 mc = data.getVar("BB_CURRENT_MC")
289 name = '%s%s' % (mc.replace('-', '_'), name) 303 name = '%s%s' % (mc.replace('-', '_'), name)
@@ -295,8 +309,8 @@ def remove(name, handler, data=None):
295 if name in _event_handler_map[event]: 309 if name in _event_handler_map[event]:
296 _event_handler_map[event].pop(name) 310 _event_handler_map[event].pop(name)
297 311
298 if data: 312 if data is not None:
299 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or []) 313 bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set())
300 if name in bbhands_mc: 314 if name in bbhands_mc:
301 bbhands_mc.remove(name) 315 bbhands_mc.remove(name)
302 data.setVar("__BBHANDLERS_MC", bbhands_mc) 316 data.setVar("__BBHANDLERS_MC", bbhands_mc)
@@ -313,21 +327,23 @@ def set_eventfilter(func):
313 _eventfilter = func 327 _eventfilter = func
314 328
315def register_UIHhandler(handler, mainui=False): 329def register_UIHhandler(handler, mainui=False):
316 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 330 with bb.utils.lock_timeout(_thread_lock):
317 _ui_handlers[_ui_handler_seq] = handler 331 bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
318 level, debug_domains = bb.msg.constructLogOptions() 332 _ui_handlers[_ui_handler_seq] = handler
319 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains) 333 level, debug_domains = bb.msg.constructLogOptions()
320 if mainui: 334 _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains)
321 global _uiready 335 if mainui:
322 _uiready = _ui_handler_seq 336 global _uiready
323 return _ui_handler_seq 337 _uiready = _ui_handler_seq
338 return _ui_handler_seq
324 339
325def unregister_UIHhandler(handlerNum, mainui=False): 340def unregister_UIHhandler(handlerNum, mainui=False):
326 if mainui: 341 if mainui:
327 global _uiready 342 global _uiready
328 _uiready = False 343 _uiready = False
329 if handlerNum in _ui_handlers: 344 with bb.utils.lock_timeout(_thread_lock):
330 del _ui_handlers[handlerNum] 345 if handlerNum in _ui_handlers:
346 del _ui_handlers[handlerNum]
331 return 347 return
332 348
333def get_uihandler(): 349def get_uihandler():
@@ -482,7 +498,7 @@ class BuildCompleted(BuildBase, OperationCompleted):
482 BuildBase.__init__(self, n, p, failures) 498 BuildBase.__init__(self, n, p, failures)
483 499
484class DiskFull(Event): 500class DiskFull(Event):
485 """Disk full case build aborted""" 501 """Disk full case build halted"""
486 def __init__(self, dev, type, freespace, mountpoint): 502 def __init__(self, dev, type, freespace, mountpoint):
487 Event.__init__(self) 503 Event.__init__(self)
488 self._dev = dev 504 self._dev = dev
@@ -666,6 +682,17 @@ class ReachableStamps(Event):
666 Event.__init__(self) 682 Event.__init__(self)
667 self.stamps = stamps 683 self.stamps = stamps
668 684
685class StaleSetSceneTasks(Event):
686 """
687 An event listing setscene tasks which are 'stale' and will
688 be rerun. The metadata may use to clean up stale data.
689 tasks is a mapping of tasks and matching stale stamps.
690 """
691
692 def __init__(self, tasks):
693 Event.__init__(self)
694 self.tasks = tasks
695
669class FilesMatchingFound(Event): 696class FilesMatchingFound(Event):
670 """ 697 """
671 Event when a list of files matching the supplied pattern has 698 Event when a list of files matching the supplied pattern has
@@ -749,7 +776,7 @@ class LogHandler(logging.Handler):
749class MetadataEvent(Event): 776class MetadataEvent(Event):
750 """ 777 """
751 Generic event that target for OE-Core classes 778 Generic event that target for OE-Core classes
752 to report information during asynchrous execution 779 to report information during asynchronous execution
753 """ 780 """
754 def __init__(self, eventtype, eventdata): 781 def __init__(self, eventtype, eventdata):
755 Event.__init__(self) 782 Event.__init__(self)
@@ -830,3 +857,19 @@ class FindSigInfoResult(Event):
830 def __init__(self, result): 857 def __init__(self, result):
831 Event.__init__(self) 858 Event.__init__(self)
832 self.result = result 859 self.result = result
860
861class GetTaskSignatureResult(Event):
862 """
863 Event to return results from GetTaskSignatures command
864 """
865 def __init__(self, sig):
866 Event.__init__(self)
867 self.sig = sig
868
869class ParseError(Event):
870 """
871 Event to indicate parse failed
872 """
873 def __init__(self, msg):
874 super().__init__()
875 self._msg = msg