bitbake: event: Prevent bitbake from executing event handler for wrong multiconfig target

When multiconfig is used bitbake might try to run events that don't
exist for specific mc target. In cooker.py we pass
`self.databuilder.mcdata[mc]` data that contains names of events'
handlers per mc target, but fire_class_handlers uses global _handlers
variable that is created during parsing of all the targets.

This leads to a problem where bitbake runs event handler that don't
exist for a target or even overrides them - if multiple targets use
event handler with the same name but different code then only one
version will be executed for all targets.

See [YOCTO #13071] for detailed bug information.

Add mc target name as a prefix to event handler name so there won't be
two different handlers with the same name. Add internal __BBHANDLERS_MC
variable to have the handlers lists per machine.

(Bitbake rev: 5f7fdf7b2d8c59805c8ef4dae84f536baa5e172b)

Signed-off-by: Tomasz Dziendzielski <tomasz.dziendzielski@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Tomasz Dziendzielski 2021-02-10 12:15:15 +01:00 committed by Richard Purdie
parent f162c34fdb
commit 8b792d4f75
4 changed files with 28 additions and 6 deletions

View File

@ -429,7 +429,7 @@ class CookerDataBuilder(object):
parselog.critical("Undefined event handler function '%s'" % var)
raise bb.BBHandledException()
handlerln = int(data.getVarFlag(var, "lineno", False))
bb.event.register(var, data.getVar(var, False), (data.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln)
bb.event.register(var, data.getVar(var, False), (data.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln, data)
data.setVar('BBINCLUDED',bb.parse.get_file_depends(data))

View File

@ -118,6 +118,8 @@ def fire_class_handlers(event, d):
if _eventfilter:
if not _eventfilter(name, handler, event, d):
continue
if d and not name in (d.getVar("__BBHANDLERS_MC") or []):
continue
execute_handler(name, handler, event, d)
ui_queue = []
@ -227,9 +229,13 @@ def fire_from_worker(event, d):
fire_ui_handlers(event, d)
noop = lambda _: None
def register(name, handler, mask=None, filename=None, lineno=None):
def register(name, handler, mask=None, filename=None, lineno=None, data=None):
"""Register an Event handler"""
if data and data.getVar("BB_CURRENT_MC"):
mc = data.getVar("BB_CURRENT_MC")
name = '%s%s' % (mc, name)
# already registered
if name in _handlers:
return AlreadyRegistered
@ -268,10 +274,20 @@ def register(name, handler, mask=None, filename=None, lineno=None):
_event_handler_map[m] = {}
_event_handler_map[m][name] = True
if data:
bbhands_mc = (data.getVar("__BBHANDLERS_MC") or [])
bbhands_mc.append(name)
data.setVar("__BBHANDLERS_MC", bbhands_mc)
return Registered
def remove(name, handler):
def remove(name, handler, data=None):
"""Remove an Event handler"""
if data:
if data.getVar("BB_CURRENT_MC"):
mc = data.getVar("BB_CURRENT_MC")
name = '%s%s' % (mc, name)
_handlers.pop(name)
if name in _catchall_handlers:
_catchall_handlers.pop(name)
@ -279,6 +295,12 @@ def remove(name, handler):
if name in _event_handler_map[event]:
_event_handler_map[event].pop(name)
if data:
bbhands_mc = (data.getVar("__BBHANDLERS_MC") or [])
if name in bbhands_mc:
bbhands_mc.remove(name)
data.setVar("__BBHANDLERS_MC", bbhands_mc)
def get_handlers():
return _handlers

View File

@ -335,7 +335,7 @@ def finalize(fn, d, variant = None):
if not handlerfn:
bb.fatal("Undefined event handler function '%s'" % var)
handlerln = int(d.getVarFlag(var, "lineno", False))
bb.event.register(var, d.getVar(var, False), (d.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln)
bb.event.register(var, d.getVar(var, False), (d.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln, data=d)
bb.event.fire(bb.event.RecipePreFinalise(fn), d)

View File

@ -1466,7 +1466,7 @@ class RunQueue:
if not self.dm_event_handler_registered:
res = bb.event.register(self.dm_event_handler_name,
lambda x: self.dm.check(self) if self.state in [runQueueRunning, runQueueCleanUp] else False,
('bb.event.HeartbeatEvent',))
('bb.event.HeartbeatEvent',), data=self.cfgData)
self.dm_event_handler_registered = True
dump = self.cooker.configuration.dump_signatures
@ -1505,7 +1505,7 @@ class RunQueue:
build_done = self.state is runQueueComplete or self.state is runQueueFailed
if build_done and self.dm_event_handler_registered:
bb.event.remove(self.dm_event_handler_name, None)
bb.event.remove(self.dm_event_handler_name, None, data=self.cfgData)
self.dm_event_handler_registered = False
if build_done and self.rqexe: