blob: 359b5032976c3cd3332f1351bb984a9d7891c39f [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001"""
2BitBake 'RunQueue' implementation
3
4Handles preparation and execution of a queue of tasks
5"""
6
7# Copyright (C) 2006-2007 Richard Purdie
8#
Brad Bishopc342db32019-05-15 21:57:59 -04009# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050011
12import copy
13import os
14import sys
Patrick Williamsc124f4f2015-09-15 14:41:29 -050015import stat
Patrick Williamsc124f4f2015-09-15 14:41:29 -050016import errno
17import logging
18import re
19import bb
Andrew Geissler82c905d2020-04-13 13:39:40 -050020from bb import msg, event
Patrick Williamsc124f4f2015-09-15 14:41:29 -050021from bb import monitordisk
22import subprocess
Patrick Williamsc0f7c042017-02-23 20:41:17 -060023import pickle
Brad Bishop6e60e8b2018-02-01 10:27:11 -050024from multiprocessing import Process
Brad Bishop19323692019-04-05 15:28:33 -040025import shlex
Brad Bishop96ff1982019-08-19 13:50:42 -040026import pprint
Patrick Williamsdb4c27e2022-08-05 08:10:29 -050027import time
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028
29bblogger = logging.getLogger("BitBake")
30logger = logging.getLogger("BitBake.RunQueue")
Andrew Geissler82c905d2020-04-13 13:39:40 -050031hashequiv_logger = logging.getLogger("BitBake.RunQueue.HashEquiv")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050032
Brad Bishop19323692019-04-05 15:28:33 -040033__find_sha256__ = re.compile( r'(?i)(?<![a-z0-9])[a-f0-9]{64}(?![a-z0-9])' )
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034
Patrick Williamsc0f7c042017-02-23 20:41:17 -060035def fn_from_tid(tid):
36 return tid.rsplit(":", 1)[0]
37
38def taskname_from_tid(tid):
39 return tid.rsplit(":", 1)[1]
40
Andrew Geissler99467da2019-02-25 18:54:23 -060041def mc_from_tid(tid):
Andrew Geisslerd1e89492021-02-12 15:35:20 -060042 if tid.startswith('mc:') and tid.count(':') >= 2:
Andrew Geissler99467da2019-02-25 18:54:23 -060043 return tid.split(':')[1]
44 return ""
45
Patrick Williamsc0f7c042017-02-23 20:41:17 -060046def split_tid(tid):
47 (mc, fn, taskname, _) = split_tid_mcfn(tid)
48 return (mc, fn, taskname)
49
Andrew Geissler5a43b432020-06-13 10:46:56 -050050def split_mc(n):
Andrew Geisslerd1e89492021-02-12 15:35:20 -060051 if n.startswith("mc:") and n.count(':') >= 2:
Andrew Geissler5a43b432020-06-13 10:46:56 -050052 _, mc, n = n.split(":", 2)
53 return (mc, n)
54 return ('', n)
55
Patrick Williamsc0f7c042017-02-23 20:41:17 -060056def split_tid_mcfn(tid):
Andrew Geisslerd1e89492021-02-12 15:35:20 -060057 if tid.startswith('mc:') and tid.count(':') >= 2:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060058 elems = tid.split(':')
59 mc = elems[1]
60 fn = ":".join(elems[2:-1])
61 taskname = elems[-1]
Brad Bishop15ae2502019-06-18 21:44:24 -040062 mcfn = "mc:" + mc + ":" + fn
Patrick Williamsc0f7c042017-02-23 20:41:17 -060063 else:
64 tid = tid.rsplit(":", 1)
65 mc = ""
66 fn = tid[0]
67 taskname = tid[1]
68 mcfn = fn
69
70 return (mc, fn, taskname, mcfn)
71
72def build_tid(mc, fn, taskname):
73 if mc:
Brad Bishop15ae2502019-06-18 21:44:24 -040074 return "mc:" + mc + ":" + fn + ":" + taskname
Patrick Williamsc0f7c042017-02-23 20:41:17 -060075 return fn + ":" + taskname
76
Brad Bishop96ff1982019-08-19 13:50:42 -040077# Index used to pair up potentially matching multiconfig tasks
78# We match on PN, taskname and hash being equal
79def pending_hash_index(tid, rqdata):
80 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
81 pn = rqdata.dataCaches[mc].pkg_fn[taskfn]
Brad Bishop00e122a2019-10-05 11:10:57 -040082 h = rqdata.runtaskentries[tid].unihash
Brad Bishop96ff1982019-08-19 13:50:42 -040083 return pn + ":" + "taskname" + h
84
Patrick Williamsc124f4f2015-09-15 14:41:29 -050085class RunQueueStats:
86 """
87 Holds statistics on the tasks handled by the associated runQueue
88 """
Andrew Geissler5199d832021-09-24 16:47:35 -050089 def __init__(self, total, setscene_total):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090 self.completed = 0
91 self.skipped = 0
92 self.failed = 0
93 self.active = 0
Andrew Geissler5199d832021-09-24 16:47:35 -050094 self.setscene_active = 0
95 self.setscene_covered = 0
96 self.setscene_notcovered = 0
97 self.setscene_total = setscene_total
Patrick Williamsc124f4f2015-09-15 14:41:29 -050098 self.total = total
99
100 def copy(self):
Andrew Geissler5199d832021-09-24 16:47:35 -0500101 obj = self.__class__(self.total, self.setscene_total)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500102 obj.__dict__.update(self.__dict__)
103 return obj
104
105 def taskFailed(self):
106 self.active = self.active - 1
107 self.failed = self.failed + 1
108
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800109 def taskCompleted(self):
110 self.active = self.active - 1
111 self.completed = self.completed + 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500112
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800113 def taskSkipped(self):
114 self.active = self.active + 1
115 self.skipped = self.skipped + 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500116
117 def taskActive(self):
118 self.active = self.active + 1
119
Andrew Geissler5199d832021-09-24 16:47:35 -0500120 def updateCovered(self, covered, notcovered):
121 self.setscene_covered = covered
122 self.setscene_notcovered = notcovered
123
124 def updateActiveSetscene(self, active):
125 self.setscene_active = active
126
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500127# These values indicate the next step due to be run in the
128# runQueue state machine
129runQueuePrepare = 2
130runQueueSceneInit = 3
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500131runQueueRunning = 6
132runQueueFailed = 7
133runQueueCleanUp = 8
134runQueueComplete = 9
135
136class RunQueueScheduler(object):
137 """
138 Control the order tasks are scheduled in.
139 """
140 name = "basic"
141
142 def __init__(self, runqueue, rqdata):
143 """
144 The default scheduler just returns the first buildable task (the
145 priority map is sorted by task number)
146 """
147 self.rq = runqueue
148 self.rqdata = rqdata
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600149 self.numTasks = len(self.rqdata.runtaskentries)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600151 self.prio_map = [self.rqdata.runtaskentries.keys()]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500152
Brad Bishop08902b02019-08-20 09:16:51 -0400153 self.buildable = set()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800154 self.skip_maxthread = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500155 self.stamps = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600156 for tid in self.rqdata.runtaskentries:
157 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
158 self.stamps[tid] = bb.build.stampfile(taskname, self.rqdata.dataCaches[mc], taskfn, noextra=True)
159 if tid in self.rq.runq_buildable:
160 self.buildable.append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500161
162 self.rev_prio_map = None
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500163 self.is_pressure_usable()
164
165 def is_pressure_usable(self):
166 """
167 If monitoring pressure, return True if pressure files can be open and read. For example
168 openSUSE /proc/pressure/* files have readable file permissions but when read the error EOPNOTSUPP (Operation not supported)
169 is returned.
170 """
171 if self.rq.max_cpu_pressure or self.rq.max_io_pressure:
172 try:
173 with open("/proc/pressure/cpu") as cpu_pressure_fds, open("/proc/pressure/io") as io_pressure_fds:
174 self.prev_cpu_pressure = cpu_pressure_fds.readline().split()[4].split("=")[1]
175 self.prev_io_pressure = io_pressure_fds.readline().split()[4].split("=")[1]
176 self.prev_pressure_time = time.time()
177 self.check_pressure = True
178 except:
179 bb.warn("The /proc/pressure files can't be read. Continuing build without monitoring pressure")
180 self.check_pressure = False
181 else:
182 self.check_pressure = False
183
184 def exceeds_max_pressure(self):
185 """
186 Monitor the difference in total pressure at least once per second, if
187 BB_PRESSURE_MAX_{CPU|IO} are set, return True if above threshold.
188 """
189 if self.check_pressure:
190 with open("/proc/pressure/cpu") as cpu_pressure_fds, open("/proc/pressure/io") as io_pressure_fds:
191 # extract "total" from /proc/pressure/{cpu|io}
192 curr_cpu_pressure = cpu_pressure_fds.readline().split()[4].split("=")[1]
193 curr_io_pressure = io_pressure_fds.readline().split()[4].split("=")[1]
194 exceeds_cpu_pressure = self.rq.max_cpu_pressure and (float(curr_cpu_pressure) - float(self.prev_cpu_pressure)) > self.rq.max_cpu_pressure
195 exceeds_io_pressure = self.rq.max_io_pressure and (float(curr_io_pressure) - float(self.prev_io_pressure)) > self.rq.max_io_pressure
196 now = time.time()
197 if now - self.prev_pressure_time > 1.0:
198 self.prev_cpu_pressure = curr_cpu_pressure
199 self.prev_io_pressure = curr_io_pressure
200 self.prev_pressure_time = now
201 return (exceeds_cpu_pressure or exceeds_io_pressure)
202 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500203
204 def next_buildable_task(self):
205 """
206 Return the id of the first task we find that is buildable
207 """
Andrew Geissler82c905d2020-04-13 13:39:40 -0500208 # Once tasks are running we don't need to worry about them again
209 self.buildable.difference_update(self.rq.runq_running)
Brad Bishop08902b02019-08-20 09:16:51 -0400210 buildable = set(self.buildable)
Brad Bishop08902b02019-08-20 09:16:51 -0400211 buildable.difference_update(self.rq.holdoff_tasks)
212 buildable.intersection_update(self.rq.tasks_covered | self.rq.tasks_notcovered)
Brad Bishop96ff1982019-08-19 13:50:42 -0400213 if not buildable:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500214 return None
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800215
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500216 # Bitbake requires that at least one task be active. Only check for pressure if
217 # this is the case, otherwise the pressure limitation could result in no tasks
218 # being active and no new tasks started thereby, at times, breaking the scheduler.
219 if self.rq.stats.active and self.exceeds_max_pressure():
220 return None
221
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800222 # Filter out tasks that have a max number of threads that have been exceeded
223 skip_buildable = {}
224 for running in self.rq.runq_running.difference(self.rq.runq_complete):
225 rtaskname = taskname_from_tid(running)
226 if rtaskname not in self.skip_maxthread:
227 self.skip_maxthread[rtaskname] = self.rq.cfgData.getVarFlag(rtaskname, "number_threads")
228 if not self.skip_maxthread[rtaskname]:
229 continue
230 if rtaskname in skip_buildable:
231 skip_buildable[rtaskname] += 1
232 else:
233 skip_buildable[rtaskname] = 1
234
Brad Bishop96ff1982019-08-19 13:50:42 -0400235 if len(buildable) == 1:
Brad Bishop08902b02019-08-20 09:16:51 -0400236 tid = buildable.pop()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800237 taskname = taskname_from_tid(tid)
238 if taskname in skip_buildable and skip_buildable[taskname] >= int(self.skip_maxthread[taskname]):
239 return None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600240 stamp = self.stamps[tid]
241 if stamp not in self.rq.build_stamps.values():
242 return tid
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500243
244 if not self.rev_prio_map:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600245 self.rev_prio_map = {}
246 for tid in self.rqdata.runtaskentries:
247 self.rev_prio_map[tid] = self.prio_map.index(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500248
249 best = None
250 bestprio = None
Brad Bishop96ff1982019-08-19 13:50:42 -0400251 for tid in buildable:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800252 taskname = taskname_from_tid(tid)
253 if taskname in skip_buildable and skip_buildable[taskname] >= int(self.skip_maxthread[taskname]):
254 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600255 prio = self.rev_prio_map[tid]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500256 if bestprio is None or bestprio > prio:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600257 stamp = self.stamps[tid]
258 if stamp in self.rq.build_stamps.values():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500259 continue
260 bestprio = prio
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600261 best = tid
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500262
263 return best
264
265 def next(self):
266 """
267 Return the id of the task we should build next
268 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800269 if self.rq.can_start_task():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500270 return self.next_buildable_task()
271
Brad Bishop316dfdd2018-06-25 12:45:53 -0400272 def newbuildable(self, task):
Brad Bishop08902b02019-08-20 09:16:51 -0400273 self.buildable.add(task)
274
275 def removebuildable(self, task):
276 self.buildable.remove(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500277
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500278 def describe_task(self, taskid):
279 result = 'ID %s' % taskid
280 if self.rev_prio_map:
281 result = result + (' pri %d' % self.rev_prio_map[taskid])
282 return result
283
284 def dump_prio(self, comment):
285 bb.debug(3, '%s (most important first):\n%s' %
286 (comment,
287 '\n'.join(['%d. %s' % (index + 1, self.describe_task(taskid)) for
288 index, taskid in enumerate(self.prio_map)])))
289
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500290class RunQueueSchedulerSpeed(RunQueueScheduler):
291 """
292 A scheduler optimised for speed. The priority map is sorted by task weight,
293 heavier weighted tasks (tasks needed by the most other tasks) are run first.
294 """
295 name = "speed"
296
297 def __init__(self, runqueue, rqdata):
298 """
299 The priority map is sorted by task weight.
300 """
301 RunQueueScheduler.__init__(self, runqueue, rqdata)
302
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600303 weights = {}
304 for tid in self.rqdata.runtaskentries:
305 weight = self.rqdata.runtaskentries[tid].weight
306 if not weight in weights:
307 weights[weight] = []
308 weights[weight].append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500309
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600310 self.prio_map = []
311 for weight in sorted(weights):
312 for w in weights[weight]:
313 self.prio_map.append(w)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500314
315 self.prio_map.reverse()
316
317class RunQueueSchedulerCompletion(RunQueueSchedulerSpeed):
318 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500319 A scheduler optimised to complete .bb files as quickly as possible. The
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500320 priority map is sorted by task weight, but then reordered so once a given
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500321 .bb file starts to build, it's completed as quickly as possible by
322 running all tasks related to the same .bb file one after the after.
323 This works well where disk space is at a premium and classes like OE's
324 rm_work are in force.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500325 """
326 name = "completion"
327
328 def __init__(self, runqueue, rqdata):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500329 super(RunQueueSchedulerCompletion, self).__init__(runqueue, rqdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500330
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500331 # Extract list of tasks for each recipe, with tasks sorted
332 # ascending from "must run first" (typically do_fetch) to
333 # "runs last" (do_build). The speed scheduler prioritizes
334 # tasks that must run first before the ones that run later;
335 # this is what we depend on here.
336 task_lists = {}
337 for taskid in self.prio_map:
338 fn, taskname = taskid.rsplit(':', 1)
339 task_lists.setdefault(fn, []).append(taskname)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500340
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500341 # Now unify the different task lists. The strategy is that
342 # common tasks get skipped and new ones get inserted after the
343 # preceeding common one(s) as they are found. Because task
344 # lists should differ only by their number of tasks, but not
345 # the ordering of the common tasks, this should result in a
346 # deterministic result that is a superset of the individual
347 # task ordering.
348 all_tasks = []
349 for recipe, new_tasks in task_lists.items():
350 index = 0
351 old_task = all_tasks[index] if index < len(all_tasks) else None
352 for new_task in new_tasks:
353 if old_task == new_task:
354 # Common task, skip it. This is the fast-path which
355 # avoids a full search.
356 index += 1
357 old_task = all_tasks[index] if index < len(all_tasks) else None
358 else:
359 try:
360 index = all_tasks.index(new_task)
361 # Already present, just not at the current
362 # place. We re-synchronized by changing the
363 # index so that it matches again. Now
364 # move on to the next existing task.
365 index += 1
366 old_task = all_tasks[index] if index < len(all_tasks) else None
367 except ValueError:
368 # Not present. Insert before old_task, which
369 # remains the same (but gets shifted back).
370 all_tasks.insert(index, new_task)
371 index += 1
372 bb.debug(3, 'merged task list: %s' % all_tasks)
373
374 # Now reverse the order so that tasks that finish the work on one
375 # recipe are considered more imporant (= come first). The ordering
376 # is now so that do_build is most important.
377 all_tasks.reverse()
378
379 # Group tasks of the same kind before tasks of less important
380 # kinds at the head of the queue (because earlier = lower
381 # priority number = runs earlier), while preserving the
382 # ordering by recipe. If recipe foo is more important than
383 # bar, then the goal is to work on foo's do_populate_sysroot
384 # before bar's do_populate_sysroot and on the more important
385 # tasks of foo before any of the less important tasks in any
386 # other recipe (if those other recipes are more important than
387 # foo).
388 #
389 # All of this only applies when tasks are runable. Explicit
390 # dependencies still override this ordering by priority.
391 #
392 # Here's an example why this priority re-ordering helps with
393 # minimizing disk usage. Consider a recipe foo with a higher
394 # priority than bar where foo DEPENDS on bar. Then the
395 # implicit rule (from base.bbclass) is that foo's do_configure
396 # depends on bar's do_populate_sysroot. This ensures that
397 # bar's do_populate_sysroot gets done first. Normally the
398 # tasks from foo would continue to run once that is done, and
399 # bar only gets completed and cleaned up later. By ordering
400 # bar's task that depend on bar's do_populate_sysroot before foo's
401 # do_configure, that problem gets avoided.
402 task_index = 0
403 self.dump_prio('original priorities')
404 for task in all_tasks:
405 for index in range(task_index, self.numTasks):
406 taskid = self.prio_map[index]
407 taskname = taskid.rsplit(':', 1)[1]
408 if taskname == task:
409 del self.prio_map[index]
410 self.prio_map.insert(task_index, taskid)
411 task_index += 1
412 self.dump_prio('completion priorities')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500413
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600414class RunTaskEntry(object):
415 def __init__(self):
416 self.depends = set()
417 self.revdeps = set()
418 self.hash = None
Brad Bishop19323692019-04-05 15:28:33 -0400419 self.unihash = None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600420 self.task = None
421 self.weight = 1
422
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500423class RunQueueData:
424 """
425 BitBake Run Queue implementation
426 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600427 def __init__(self, rq, cooker, cfgData, dataCaches, taskData, targets):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500428 self.cooker = cooker
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600429 self.dataCaches = dataCaches
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500430 self.taskData = taskData
431 self.targets = targets
432 self.rq = rq
433 self.warn_multi_bb = False
434
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000435 self.multi_provider_allowed = (cfgData.getVar("BB_MULTI_PROVIDER_ALLOWED") or "").split()
436 self.setscene_ignore_tasks = get_setscene_enforce_ignore_tasks(cfgData, targets)
437 self.setscene_ignore_tasks_checked = False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500438 self.setscene_enforce = (cfgData.getVar('BB_SETSCENE_ENFORCE') == "1")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600439 self.init_progress_reporter = bb.progress.DummyMultiStageProcessProgressReporter()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500440
441 self.reset()
442
443 def reset(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600444 self.runtaskentries = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500445
446 def runq_depends_names(self, ids):
447 import re
448 ret = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600449 for id in ids:
450 nam = os.path.basename(id)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500451 nam = re.sub("_[^,]*,", ",", nam)
452 ret.extend([nam])
453 return ret
454
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600455 def get_task_hash(self, tid):
456 return self.runtaskentries[tid].hash
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500457
Brad Bishop19323692019-04-05 15:28:33 -0400458 def get_task_unihash(self, tid):
459 return self.runtaskentries[tid].unihash
460
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600461 def get_user_idstring(self, tid, task_name_suffix = ""):
462 return tid + task_name_suffix
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500463
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500464 def get_short_user_idstring(self, task, task_name_suffix = ""):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500465 (mc, fn, taskname, taskfn) = split_tid_mcfn(task)
466 pn = self.dataCaches[mc].pkg_fn[taskfn]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600467 taskname = taskname_from_tid(task) + task_name_suffix
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500468 return "%s:%s" % (pn, taskname)
469
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500470 def circular_depchains_handler(self, tasks):
471 """
472 Some tasks aren't buildable, likely due to circular dependency issues.
473 Identify the circular dependencies and print them in a user readable format.
474 """
475 from copy import deepcopy
476
477 valid_chains = []
478 explored_deps = {}
479 msgs = []
480
Andrew Geissler99467da2019-02-25 18:54:23 -0600481 class TooManyLoops(Exception):
482 pass
483
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500484 def chain_reorder(chain):
485 """
486 Reorder a dependency chain so the lowest task id is first
487 """
488 lowest = 0
489 new_chain = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600490 for entry in range(len(chain)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500491 if chain[entry] < chain[lowest]:
492 lowest = entry
493 new_chain.extend(chain[lowest:])
494 new_chain.extend(chain[:lowest])
495 return new_chain
496
497 def chain_compare_equal(chain1, chain2):
498 """
499 Compare two dependency chains and see if they're the same
500 """
501 if len(chain1) != len(chain2):
502 return False
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600503 for index in range(len(chain1)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500504 if chain1[index] != chain2[index]:
505 return False
506 return True
507
508 def chain_array_contains(chain, chain_array):
509 """
510 Return True if chain_array contains chain
511 """
512 for ch in chain_array:
513 if chain_compare_equal(ch, chain):
514 return True
515 return False
516
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600517 def find_chains(tid, prev_chain):
518 prev_chain.append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500519 total_deps = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600520 total_deps.extend(self.runtaskentries[tid].revdeps)
521 for revdep in self.runtaskentries[tid].revdeps:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500522 if revdep in prev_chain:
523 idx = prev_chain.index(revdep)
524 # To prevent duplicates, reorder the chain to start with the lowest taskid
525 # and search through an array of those we've already printed
526 chain = prev_chain[idx:]
527 new_chain = chain_reorder(chain)
528 if not chain_array_contains(new_chain, valid_chains):
529 valid_chains.append(new_chain)
530 msgs.append("Dependency loop #%d found:\n" % len(valid_chains))
531 for dep in new_chain:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600532 msgs.append(" Task %s (dependent Tasks %s)\n" % (dep, self.runq_depends_names(self.runtaskentries[dep].depends)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500533 msgs.append("\n")
534 if len(valid_chains) > 10:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000535 msgs.append("Halted dependency loops search after 10 matches.\n")
Andrew Geissler99467da2019-02-25 18:54:23 -0600536 raise TooManyLoops
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500537 continue
538 scan = False
539 if revdep not in explored_deps:
540 scan = True
541 elif revdep in explored_deps[revdep]:
542 scan = True
543 else:
544 for dep in prev_chain:
545 if dep in explored_deps[revdep]:
546 scan = True
547 if scan:
548 find_chains(revdep, copy.deepcopy(prev_chain))
549 for dep in explored_deps[revdep]:
550 if dep not in total_deps:
551 total_deps.append(dep)
552
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600553 explored_deps[tid] = total_deps
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500554
Andrew Geissler99467da2019-02-25 18:54:23 -0600555 try:
556 for task in tasks:
557 find_chains(task, [])
558 except TooManyLoops:
559 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500560
561 return msgs
562
563 def calculate_task_weights(self, endpoints):
564 """
565 Calculate a number representing the "weight" of each task. Heavier weighted tasks
566 have more dependencies and hence should be executed sooner for maximum speed.
567
568 This function also sanity checks the task list finding tasks that are not
569 possible to execute due to circular dependencies.
570 """
571
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600572 numTasks = len(self.runtaskentries)
573 weight = {}
574 deps_left = {}
575 task_done = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500576
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600577 for tid in self.runtaskentries:
578 task_done[tid] = False
579 weight[tid] = 1
580 deps_left[tid] = len(self.runtaskentries[tid].revdeps)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500581
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600582 for tid in endpoints:
583 weight[tid] = 10
584 task_done[tid] = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500585
586 while True:
587 next_points = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600588 for tid in endpoints:
589 for revdep in self.runtaskentries[tid].depends:
590 weight[revdep] = weight[revdep] + weight[tid]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500591 deps_left[revdep] = deps_left[revdep] - 1
592 if deps_left[revdep] == 0:
593 next_points.append(revdep)
594 task_done[revdep] = True
595 endpoints = next_points
Andrew Geissler595f6302022-01-24 19:11:47 +0000596 if not next_points:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500597 break
598
599 # Circular dependency sanity check
600 problem_tasks = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600601 for tid in self.runtaskentries:
602 if task_done[tid] is False or deps_left[tid] != 0:
603 problem_tasks.append(tid)
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600604 logger.debug2("Task %s is not buildable", tid)
605 logger.debug2("(Complete marker was %s and the remaining dependency count was %s)\n", task_done[tid], deps_left[tid])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600606 self.runtaskentries[tid].weight = weight[tid]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500607
608 if problem_tasks:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600609 message = "%s unbuildable tasks were found.\n" % len(problem_tasks)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500610 message = message + "These are usually caused by circular dependencies and any circular dependency chains found will be printed below. Increase the debug level to see a list of unbuildable tasks.\n\n"
611 message = message + "Identifying dependency loops (this may take a short while)...\n"
612 logger.error(message)
613
614 msgs = self.circular_depchains_handler(problem_tasks)
615
616 message = "\n"
617 for msg in msgs:
618 message = message + msg
619 bb.msg.fatal("RunQueue", message)
620
621 return weight
622
623 def prepare(self):
624 """
625 Turn a set of taskData into a RunQueue and compute data needed
626 to optimise the execution order.
627 """
628
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600629 runq_build = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500630 recursivetasks = {}
631 recursiveitasks = {}
632 recursivetasksselfref = set()
633
634 taskData = self.taskData
635
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600636 found = False
637 for mc in self.taskData:
Andrew Geissler595f6302022-01-24 19:11:47 +0000638 if taskData[mc].taskentries:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600639 found = True
640 break
641 if not found:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500642 # Nothing to do
643 return 0
644
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600645 self.init_progress_reporter.start()
646 self.init_progress_reporter.next_stage()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500647
648 # Step A - Work out a list of tasks to run
649 #
650 # Taskdata gives us a list of possible providers for every build and run
651 # target ordered by priority. It also gives information on each of those
652 # providers.
653 #
654 # To create the actual list of tasks to execute we fix the list of
655 # providers and then resolve the dependencies into task IDs. This
656 # process is repeated for each type of dependency (tdepends, deptask,
657 # rdeptast, recrdeptask, idepends).
658
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600659 def add_build_dependencies(depids, tasknames, depends, mc):
660 for depname in depids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500661 # Won't be in build_targets if ASSUME_PROVIDED
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600662 if depname not in taskData[mc].build_targets or not taskData[mc].build_targets[depname]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500663 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600664 depdata = taskData[mc].build_targets[depname][0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500665 if depdata is None:
666 continue
667 for taskname in tasknames:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600668 t = depdata + ":" + taskname
669 if t in taskData[mc].taskentries:
670 depends.add(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500671
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600672 def add_runtime_dependencies(depids, tasknames, depends, mc):
673 for depname in depids:
674 if depname not in taskData[mc].run_targets or not taskData[mc].run_targets[depname]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500675 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600676 depdata = taskData[mc].run_targets[depname][0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500677 if depdata is None:
678 continue
679 for taskname in tasknames:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600680 t = depdata + ":" + taskname
681 if t in taskData[mc].taskentries:
682 depends.add(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500683
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800684 def add_mc_dependencies(mc, tid):
685 mcdeps = taskData[mc].get_mcdepends()
686 for dep in mcdeps:
687 mcdependency = dep.split(':')
688 pn = mcdependency[3]
689 frommc = mcdependency[1]
690 mcdep = mcdependency[2]
691 deptask = mcdependency[4]
692 if mc == frommc:
693 fn = taskData[mcdep].build_targets[pn][0]
694 newdep = '%s:%s' % (fn,deptask)
695 taskData[mc].taskentries[tid].tdepends.append(newdep)
696
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600697 for mc in taskData:
698 for tid in taskData[mc].taskentries:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500699
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600700 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
701 #runtid = build_tid(mc, fn, taskname)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500702
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600703 #logger.debug2("Processing %s,%s:%s", mc, fn, taskname)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600704
705 depends = set()
706 task_deps = self.dataCaches[mc].task_deps[taskfn]
707
708 self.runtaskentries[tid] = RunTaskEntry()
709
710 if fn in taskData[mc].failed_fns:
711 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500712
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800713 # We add multiconfig dependencies before processing internal task deps (tdepends)
714 if 'mcdepends' in task_deps and taskname in task_deps['mcdepends']:
715 add_mc_dependencies(mc, tid)
716
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500717 # Resolve task internal dependencies
718 #
719 # e.g. addtask before X after Y
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600720 for t in taskData[mc].taskentries[tid].tdepends:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800721 (depmc, depfn, deptaskname, _) = split_tid_mcfn(t)
722 depends.add(build_tid(depmc, depfn, deptaskname))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500723
724 # Resolve 'deptask' dependencies
725 #
726 # e.g. do_sometask[deptask] = "do_someothertask"
727 # (makes sure sometask runs after someothertask of all DEPENDS)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600728 if 'deptask' in task_deps and taskname in task_deps['deptask']:
729 tasknames = task_deps['deptask'][taskname].split()
730 add_build_dependencies(taskData[mc].depids[taskfn], tasknames, depends, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500731
732 # Resolve 'rdeptask' dependencies
733 #
734 # e.g. do_sometask[rdeptask] = "do_someothertask"
735 # (makes sure sometask runs after someothertask of all RDEPENDS)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600736 if 'rdeptask' in task_deps and taskname in task_deps['rdeptask']:
737 tasknames = task_deps['rdeptask'][taskname].split()
738 add_runtime_dependencies(taskData[mc].rdepids[taskfn], tasknames, depends, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500739
740 # Resolve inter-task dependencies
741 #
742 # e.g. do_sometask[depends] = "targetname:do_someothertask"
743 # (makes sure sometask runs after targetname's someothertask)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600744 idepends = taskData[mc].taskentries[tid].idepends
745 for (depname, idependtask) in idepends:
746 if depname in taskData[mc].build_targets and taskData[mc].build_targets[depname] and not depname in taskData[mc].failed_deps:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500747 # Won't be in build_targets if ASSUME_PROVIDED
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600748 depdata = taskData[mc].build_targets[depname][0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500749 if depdata is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600750 t = depdata + ":" + idependtask
751 depends.add(t)
752 if t not in taskData[mc].taskentries:
753 bb.msg.fatal("RunQueue", "Task %s in %s depends upon non-existent task %s in %s" % (taskname, fn, idependtask, depdata))
754 irdepends = taskData[mc].taskentries[tid].irdepends
755 for (depname, idependtask) in irdepends:
756 if depname in taskData[mc].run_targets:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500757 # Won't be in run_targets if ASSUME_PROVIDED
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500758 if not taskData[mc].run_targets[depname]:
759 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600760 depdata = taskData[mc].run_targets[depname][0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500761 if depdata is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600762 t = depdata + ":" + idependtask
763 depends.add(t)
764 if t not in taskData[mc].taskentries:
765 bb.msg.fatal("RunQueue", "Task %s in %s rdepends upon non-existent task %s in %s" % (taskname, fn, idependtask, depdata))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500766
767 # Resolve recursive 'recrdeptask' dependencies (Part A)
768 #
769 # e.g. do_sometask[recrdeptask] = "do_someothertask"
770 # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively)
771 # We cover the recursive part of the dependencies below
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600772 if 'recrdeptask' in task_deps and taskname in task_deps['recrdeptask']:
773 tasknames = task_deps['recrdeptask'][taskname].split()
774 recursivetasks[tid] = tasknames
775 add_build_dependencies(taskData[mc].depids[taskfn], tasknames, depends, mc)
776 add_runtime_dependencies(taskData[mc].rdepids[taskfn], tasknames, depends, mc)
777 if taskname in tasknames:
778 recursivetasksselfref.add(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500779
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600780 if 'recideptask' in task_deps and taskname in task_deps['recideptask']:
781 recursiveitasks[tid] = []
782 for t in task_deps['recideptask'][taskname].split():
783 newdep = build_tid(mc, fn, t)
784 recursiveitasks[tid].append(newdep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500785
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600786 self.runtaskentries[tid].depends = depends
Brad Bishop316dfdd2018-06-25 12:45:53 -0400787 # Remove all self references
788 self.runtaskentries[tid].depends.discard(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500789
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600790 #self.dump_data()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500791
Brad Bishop316dfdd2018-06-25 12:45:53 -0400792 self.init_progress_reporter.next_stage()
793
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500794 # Resolve recursive 'recrdeptask' dependencies (Part B)
795 #
796 # e.g. do_sometask[recrdeptask] = "do_someothertask"
797 # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600798 # We need to do this separately since we need all of runtaskentries[*].depends to be complete before this is processed
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600799
Brad Bishop316dfdd2018-06-25 12:45:53 -0400800 # Generating/interating recursive lists of dependencies is painful and potentially slow
801 # Precompute recursive task dependencies here by:
802 # a) create a temp list of reverse dependencies (revdeps)
803 # b) walk up the ends of the chains (when a given task no longer has dependencies i.e. len(deps) == 0)
804 # c) combine the total list of dependencies in cumulativedeps
805 # d) optimise by pre-truncating 'task' off the items in cumulativedeps (keeps items in sets lower)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500806
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500807
Brad Bishop316dfdd2018-06-25 12:45:53 -0400808 revdeps = {}
809 deps = {}
810 cumulativedeps = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600811 for tid in self.runtaskentries:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400812 deps[tid] = set(self.runtaskentries[tid].depends)
813 revdeps[tid] = set()
814 cumulativedeps[tid] = set()
815 # Generate a temp list of reverse dependencies
816 for tid in self.runtaskentries:
817 for dep in self.runtaskentries[tid].depends:
818 revdeps[dep].add(tid)
819 # Find the dependency chain endpoints
820 endpoints = set()
821 for tid in self.runtaskentries:
Andrew Geissler595f6302022-01-24 19:11:47 +0000822 if not deps[tid]:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400823 endpoints.add(tid)
824 # Iterate the chains collating dependencies
825 while endpoints:
826 next = set()
827 for tid in endpoints:
828 for dep in revdeps[tid]:
829 cumulativedeps[dep].add(fn_from_tid(tid))
830 cumulativedeps[dep].update(cumulativedeps[tid])
831 if tid in deps[dep]:
832 deps[dep].remove(tid)
Andrew Geissler595f6302022-01-24 19:11:47 +0000833 if not deps[dep]:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400834 next.add(dep)
835 endpoints = next
836 #for tid in deps:
Andrew Geissler595f6302022-01-24 19:11:47 +0000837 # if deps[tid]:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400838 # bb.warn("Sanity test failure, dependencies left for %s (%s)" % (tid, deps[tid]))
839
840 # Loop here since recrdeptasks can depend upon other recrdeptasks and we have to
841 # resolve these recursively until we aren't adding any further extra dependencies
842 extradeps = True
843 while extradeps:
844 extradeps = 0
845 for tid in recursivetasks:
846 tasknames = recursivetasks[tid]
847
848 totaldeps = set(self.runtaskentries[tid].depends)
849 if tid in recursiveitasks:
850 totaldeps.update(recursiveitasks[tid])
851 for dep in recursiveitasks[tid]:
852 if dep not in self.runtaskentries:
853 continue
854 totaldeps.update(self.runtaskentries[dep].depends)
855
856 deps = set()
857 for dep in totaldeps:
858 if dep in cumulativedeps:
859 deps.update(cumulativedeps[dep])
860
861 for t in deps:
862 for taskname in tasknames:
863 newtid = t + ":" + taskname
864 if newtid == tid:
865 continue
866 if newtid in self.runtaskentries and newtid not in self.runtaskentries[tid].depends:
867 extradeps += 1
868 self.runtaskentries[tid].depends.add(newtid)
869
870 # Handle recursive tasks which depend upon other recursive tasks
871 deps = set()
872 for dep in self.runtaskentries[tid].depends.intersection(recursivetasks):
873 deps.update(self.runtaskentries[dep].depends.difference(self.runtaskentries[tid].depends))
874 for newtid in deps:
875 for taskname in tasknames:
876 if not newtid.endswith(":" + taskname):
877 continue
878 if newtid in self.runtaskentries:
879 extradeps += 1
880 self.runtaskentries[tid].depends.add(newtid)
881
882 bb.debug(1, "Added %s recursive dependencies in this loop" % extradeps)
883
884 # Remove recrdeptask circular references so that do_a[recrdeptask] = "do_a do_b" can work
885 for tid in recursivetasksselfref:
886 self.runtaskentries[tid].depends.difference_update(recursivetasksselfref)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600887
888 self.init_progress_reporter.next_stage()
889
890 #self.dump_data()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500891
892 # Step B - Mark all active tasks
893 #
894 # Start with the tasks we were asked to run and mark all dependencies
895 # as active too. If the task is to be 'forced', clear its stamp. Once
896 # all active tasks are marked, prune the ones we don't need.
897
898 logger.verbose("Marking Active Tasks")
899
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600900 def mark_active(tid, depth):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500901 """
902 Mark an item as active along with its depends
903 (calls itself recursively)
904 """
905
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600906 if tid in runq_build:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500907 return
908
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600909 runq_build[tid] = 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500910
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600911 depends = self.runtaskentries[tid].depends
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500912 for depend in depends:
913 mark_active(depend, depth+1)
914
Brad Bishop79641f22019-09-10 07:20:22 -0400915 def invalidate_task(tid, error_nostamp):
916 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
917 taskdep = self.dataCaches[mc].task_deps[taskfn]
918 if fn + ":" + taskname not in taskData[mc].taskentries:
919 logger.warning("Task %s does not exist, invalidating this task will have no effect" % taskname)
920 if 'nostamp' in taskdep and taskname in taskdep['nostamp']:
921 if error_nostamp:
922 bb.fatal("Task %s is marked nostamp, cannot invalidate this task" % taskname)
923 else:
924 bb.debug(1, "Task %s is marked nostamp, cannot invalidate this task" % taskname)
925 else:
926 logger.verbose("Invalidate task %s, %s", taskname, fn)
927 bb.parse.siggen.invalidate_task(taskname, self.dataCaches[mc], taskfn)
928
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600929 self.target_tids = []
930 for (mc, target, task, fn) in self.targets:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500931
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600932 if target not in taskData[mc].build_targets or not taskData[mc].build_targets[target]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500933 continue
934
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600935 if target in taskData[mc].failed_deps:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500936 continue
937
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500938 parents = False
939 if task.endswith('-'):
940 parents = True
941 task = task[:-1]
942
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600943 if fn in taskData[mc].failed_fns:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500944 continue
945
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600946 # fn already has mc prefix
947 tid = fn + ":" + task
948 self.target_tids.append(tid)
949 if tid not in taskData[mc].taskentries:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500950 import difflib
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600951 tasks = []
952 for x in taskData[mc].taskentries:
953 if x.startswith(fn + ":"):
954 tasks.append(taskname_from_tid(x))
955 close_matches = difflib.get_close_matches(task, tasks, cutoff=0.7)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500956 if close_matches:
957 extra = ". Close matches:\n %s" % "\n ".join(close_matches)
958 else:
959 extra = ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600960 bb.msg.fatal("RunQueue", "Task %s does not exist for target %s (%s)%s" % (task, target, tid, extra))
961
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500962 # For tasks called "XXXX-", ony run their dependencies
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500963 if parents:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600964 for i in self.runtaskentries[tid].depends:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500965 mark_active(i, 1)
966 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600967 mark_active(tid, 1)
968
969 self.init_progress_reporter.next_stage()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500970
971 # Step C - Prune all inactive tasks
972 #
973 # Once all active tasks are marked, prune the ones we don't need.
974
Brad Bishop316dfdd2018-06-25 12:45:53 -0400975 # Handle --runall
976 if self.cooker.configuration.runall:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500977 # re-run the mark_active and then drop unused tasks from new list
Andrew Geissler595f6302022-01-24 19:11:47 +0000978 reduced_tasklist = set(self.runtaskentries.keys())
979 for tid in list(self.runtaskentries.keys()):
980 if tid not in runq_build:
981 reduced_tasklist.remove(tid)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500982 runq_build = {}
Brad Bishop316dfdd2018-06-25 12:45:53 -0400983
984 for task in self.cooker.configuration.runall:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500985 if not task.startswith("do_"):
986 task = "do_{0}".format(task)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400987 runall_tids = set()
Andrew Geissler595f6302022-01-24 19:11:47 +0000988 for tid in reduced_tasklist:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500989 wanttid = "{0}:{1}".format(fn_from_tid(tid), task)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400990 if wanttid in self.runtaskentries:
991 runall_tids.add(wanttid)
992
993 for tid in list(runall_tids):
Andrew Geissler595f6302022-01-24 19:11:47 +0000994 mark_active(tid, 1)
Brad Bishop79641f22019-09-10 07:20:22 -0400995 if self.cooker.configuration.force:
996 invalidate_task(tid, False)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500997
Andrew Geissler595f6302022-01-24 19:11:47 +0000998 delcount = set()
999 for tid in list(self.runtaskentries.keys()):
1000 if tid not in runq_build:
1001 delcount.add(tid)
1002 del self.runtaskentries[tid]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001003
Andrew Geissler595f6302022-01-24 19:11:47 +00001004 if self.cooker.configuration.runall:
1005 if not self.runtaskentries:
Brad Bishop316dfdd2018-06-25 12:45:53 -04001006 bb.msg.fatal("RunQueue", "Could not find any tasks with the tasknames %s to run within the recipes of the taskgraphs of the targets %s" % (str(self.cooker.configuration.runall), str(self.targets)))
1007
1008 self.init_progress_reporter.next_stage()
1009
1010 # Handle runonly
1011 if self.cooker.configuration.runonly:
1012 # re-run the mark_active and then drop unused tasks from new list
1013 runq_build = {}
1014
1015 for task in self.cooker.configuration.runonly:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001016 if not task.startswith("do_"):
1017 task = "do_{0}".format(task)
Andrew Geissler595f6302022-01-24 19:11:47 +00001018 runonly_tids = [k for k in self.runtaskentries.keys() if taskname_from_tid(k) == task]
Brad Bishop316dfdd2018-06-25 12:45:53 -04001019
Andrew Geissler595f6302022-01-24 19:11:47 +00001020 for tid in runonly_tids:
1021 mark_active(tid, 1)
Brad Bishop79641f22019-09-10 07:20:22 -04001022 if self.cooker.configuration.force:
1023 invalidate_task(tid, False)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001024
1025 for tid in list(self.runtaskentries.keys()):
1026 if tid not in runq_build:
Andrew Geissler595f6302022-01-24 19:11:47 +00001027 delcount.add(tid)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001028 del self.runtaskentries[tid]
1029
Andrew Geissler595f6302022-01-24 19:11:47 +00001030 if not self.runtaskentries:
Brad Bishop316dfdd2018-06-25 12:45:53 -04001031 bb.msg.fatal("RunQueue", "Could not find any tasks with the tasknames %s to run within the taskgraphs of the targets %s" % (str(self.cooker.configuration.runonly), str(self.targets)))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001032
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001033 #
1034 # Step D - Sanity checks and computation
1035 #
1036
1037 # Check to make sure we still have tasks to run
Andrew Geissler595f6302022-01-24 19:11:47 +00001038 if not self.runtaskentries:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001039 if not taskData[''].halt:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001040 bb.msg.fatal("RunQueue", "All buildable tasks have been run but the build is incomplete (--continue mode). Errors for the tasks that failed will have been printed above.")
1041 else:
1042 bb.msg.fatal("RunQueue", "No active tasks and not in --continue mode?! Please report this bug.")
1043
Brad Bishop316dfdd2018-06-25 12:45:53 -04001044 logger.verbose("Pruned %s inactive tasks, %s left", len(delcount), len(self.runtaskentries))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001045
1046 logger.verbose("Assign Weightings")
1047
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001048 self.init_progress_reporter.next_stage()
1049
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001050 # Generate a list of reverse dependencies to ease future calculations
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001051 for tid in self.runtaskentries:
1052 for dep in self.runtaskentries[tid].depends:
1053 self.runtaskentries[dep].revdeps.add(tid)
1054
1055 self.init_progress_reporter.next_stage()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001056
1057 # Identify tasks at the end of dependency chains
1058 # Error on circular dependency loops (length two)
1059 endpoints = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001060 for tid in self.runtaskentries:
1061 revdeps = self.runtaskentries[tid].revdeps
Andrew Geissler595f6302022-01-24 19:11:47 +00001062 if not revdeps:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001063 endpoints.append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001064 for dep in revdeps:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001065 if dep in self.runtaskentries[tid].depends:
1066 bb.msg.fatal("RunQueue", "Task %s has circular dependency on %s" % (tid, dep))
1067
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001068
1069 logger.verbose("Compute totals (have %s endpoint(s))", len(endpoints))
1070
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001071 self.init_progress_reporter.next_stage()
1072
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001073 # Calculate task weights
1074 # Check of higher length circular dependencies
1075 self.runq_weight = self.calculate_task_weights(endpoints)
1076
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001077 self.init_progress_reporter.next_stage()
1078
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001079 # Sanity Check - Check for multiple tasks building the same provider
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001080 for mc in self.dataCaches:
1081 prov_list = {}
1082 seen_fn = []
1083 for tid in self.runtaskentries:
1084 (tidmc, fn, taskname, taskfn) = split_tid_mcfn(tid)
1085 if taskfn in seen_fn:
1086 continue
1087 if mc != tidmc:
1088 continue
1089 seen_fn.append(taskfn)
1090 for prov in self.dataCaches[mc].fn_provides[taskfn]:
1091 if prov not in prov_list:
1092 prov_list[prov] = [taskfn]
1093 elif taskfn not in prov_list[prov]:
1094 prov_list[prov].append(taskfn)
1095 for prov in prov_list:
1096 if len(prov_list[prov]) < 2:
1097 continue
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001098 if prov in self.multi_provider_allowed:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001099 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001100 seen_pn = []
1101 # If two versions of the same PN are being built its fatal, we don't support it.
1102 for fn in prov_list[prov]:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001103 pn = self.dataCaches[mc].pkg_fn[fn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001104 if pn not in seen_pn:
1105 seen_pn.append(pn)
1106 else:
1107 bb.fatal("Multiple versions of %s are due to be built (%s). Only one version of a given PN should be built in any given build. You likely need to set PREFERRED_VERSION_%s to select the correct version or don't depend on multiple versions." % (pn, " ".join(prov_list[prov]), pn))
Andrew Geissler595f6302022-01-24 19:11:47 +00001108 msgs = ["Multiple .bb files are due to be built which each provide %s:\n %s" % (prov, "\n ".join(prov_list[prov]))]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001109 #
1110 # Construct a list of things which uniquely depend on each provider
1111 # since this may help the user figure out which dependency is triggering this warning
1112 #
Andrew Geissler595f6302022-01-24 19:11:47 +00001113 msgs.append("\nA list of tasks depending on these providers is shown and may help explain where the dependency comes from.")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001114 deplist = {}
1115 commondeps = None
1116 for provfn in prov_list[prov]:
1117 deps = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001118 for tid in self.runtaskentries:
1119 fn = fn_from_tid(tid)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001120 if fn != provfn:
1121 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001122 for dep in self.runtaskentries[tid].revdeps:
1123 fn = fn_from_tid(dep)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001124 if fn == provfn:
1125 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001126 deps.add(dep)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001127 if not commondeps:
1128 commondeps = set(deps)
1129 else:
1130 commondeps &= deps
1131 deplist[provfn] = deps
1132 for provfn in deplist:
Andrew Geissler595f6302022-01-24 19:11:47 +00001133 msgs.append("\n%s has unique dependees:\n %s" % (provfn, "\n ".join(deplist[provfn] - commondeps)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001134 #
1135 # Construct a list of provides and runtime providers for each recipe
1136 # (rprovides has to cover RPROVIDES, PACKAGES, PACKAGES_DYNAMIC)
1137 #
Andrew Geissler595f6302022-01-24 19:11:47 +00001138 msgs.append("\nIt could be that one recipe provides something the other doesn't and should. The following provider and runtime provider differences may be helpful.")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001139 provide_results = {}
1140 rprovide_results = {}
1141 commonprovs = None
1142 commonrprovs = None
1143 for provfn in prov_list[prov]:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001144 provides = set(self.dataCaches[mc].fn_provides[provfn])
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001145 rprovides = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001146 for rprovide in self.dataCaches[mc].rproviders:
1147 if provfn in self.dataCaches[mc].rproviders[rprovide]:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001148 rprovides.add(rprovide)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001149 for package in self.dataCaches[mc].packages:
1150 if provfn in self.dataCaches[mc].packages[package]:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001151 rprovides.add(package)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001152 for package in self.dataCaches[mc].packages_dynamic:
1153 if provfn in self.dataCaches[mc].packages_dynamic[package]:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001154 rprovides.add(package)
1155 if not commonprovs:
1156 commonprovs = set(provides)
1157 else:
1158 commonprovs &= provides
1159 provide_results[provfn] = provides
1160 if not commonrprovs:
1161 commonrprovs = set(rprovides)
1162 else:
1163 commonrprovs &= rprovides
1164 rprovide_results[provfn] = rprovides
Andrew Geissler595f6302022-01-24 19:11:47 +00001165 #msgs.append("\nCommon provides:\n %s" % ("\n ".join(commonprovs)))
1166 #msgs.append("\nCommon rprovides:\n %s" % ("\n ".join(commonrprovs)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001167 for provfn in prov_list[prov]:
Andrew Geissler595f6302022-01-24 19:11:47 +00001168 msgs.append("\n%s has unique provides:\n %s" % (provfn, "\n ".join(provide_results[provfn] - commonprovs)))
1169 msgs.append("\n%s has unique rprovides:\n %s" % (provfn, "\n ".join(rprovide_results[provfn] - commonrprovs)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001170
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001171 if self.warn_multi_bb:
Andrew Geissler595f6302022-01-24 19:11:47 +00001172 logger.verbnote("".join(msgs))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001173 else:
Andrew Geissler595f6302022-01-24 19:11:47 +00001174 logger.error("".join(msgs))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001175
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001176 self.init_progress_reporter.next_stage()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001177 self.init_progress_reporter.next_stage()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001178
1179 # Iterate over the task list looking for tasks with a 'setscene' function
Andrew Geissler82c905d2020-04-13 13:39:40 -05001180 self.runq_setscene_tids = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001181 if not self.cooker.configuration.nosetscene:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001182 for tid in self.runtaskentries:
1183 (mc, fn, taskname, _) = split_tid_mcfn(tid)
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001184 setscenetid = tid + "_setscene"
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001185 if setscenetid not in taskData[mc].taskentries:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001186 continue
Andrew Geissler82c905d2020-04-13 13:39:40 -05001187 self.runq_setscene_tids.add(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001188
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001189 self.init_progress_reporter.next_stage()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001190
1191 # Invalidate task if force mode active
1192 if self.cooker.configuration.force:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001193 for tid in self.target_tids:
1194 invalidate_task(tid, False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001195
1196 # Invalidate task if invalidate mode active
1197 if self.cooker.configuration.invalidate_stamp:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001198 for tid in self.target_tids:
1199 fn = fn_from_tid(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001200 for st in self.cooker.configuration.invalidate_stamp.split(','):
1201 if not st.startswith("do_"):
1202 st = "do_%s" % st
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001203 invalidate_task(fn + ":" + st, True)
1204
1205 self.init_progress_reporter.next_stage()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001206
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001207 # Create and print to the logs a virtual/xxxx -> PN (fn) table
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001208 for mc in taskData:
1209 virtmap = taskData[mc].get_providermap(prefix="virtual/")
1210 virtpnmap = {}
1211 for v in virtmap:
1212 virtpnmap[v] = self.dataCaches[mc].pkg_fn[virtmap[v]]
1213 bb.debug(2, "%s resolved to: %s (%s)" % (v, virtpnmap[v], virtmap[v]))
1214 if hasattr(bb.parse.siggen, "tasks_resolved"):
1215 bb.parse.siggen.tasks_resolved(virtmap, virtpnmap, self.dataCaches[mc])
1216
1217 self.init_progress_reporter.next_stage()
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001218
Brad Bishop00e122a2019-10-05 11:10:57 -04001219 bb.parse.siggen.set_setscene_tasks(self.runq_setscene_tids)
1220
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001221 # Iterate over the task list and call into the siggen code
1222 dealtwith = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001223 todeal = set(self.runtaskentries)
Andrew Geissler595f6302022-01-24 19:11:47 +00001224 while todeal:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001225 for tid in todeal.copy():
Andrew Geissler595f6302022-01-24 19:11:47 +00001226 if not (self.runtaskentries[tid].depends - dealtwith):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001227 dealtwith.add(tid)
1228 todeal.remove(tid)
Brad Bishop19323692019-04-05 15:28:33 -04001229 self.prepare_task_hash(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001230
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001231 bb.parse.siggen.writeout_file_checksum_cache()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001232
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001233 #self.dump_data()
1234 return len(self.runtaskentries)
1235
Brad Bishop19323692019-04-05 15:28:33 -04001236 def prepare_task_hash(self, tid):
Andrew Geissler5a43b432020-06-13 10:46:56 -05001237 dc = bb.parse.siggen.get_data_caches(self.dataCaches, mc_from_tid(tid))
1238 bb.parse.siggen.prep_taskhash(tid, self.runtaskentries[tid].depends, dc)
1239 self.runtaskentries[tid].hash = bb.parse.siggen.get_taskhash(tid, self.runtaskentries[tid].depends, dc)
Brad Bishop08902b02019-08-20 09:16:51 -04001240 self.runtaskentries[tid].unihash = bb.parse.siggen.get_unihash(tid)
Brad Bishop19323692019-04-05 15:28:33 -04001241
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001242 def dump_data(self):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001243 """
1244 Dump some debug information on the internal data structures
1245 """
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001246 logger.debug3("run_tasks:")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001247 for tid in self.runtaskentries:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001248 logger.debug3(" %s: %s Deps %s RevDeps %s", tid,
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001249 self.runtaskentries[tid].weight,
1250 self.runtaskentries[tid].depends,
1251 self.runtaskentries[tid].revdeps)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001252
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001253class RunQueueWorker():
1254 def __init__(self, process, pipe):
1255 self.process = process
1256 self.pipe = pipe
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001257
1258class RunQueue:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001259 def __init__(self, cooker, cfgData, dataCaches, taskData, targets):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001260
1261 self.cooker = cooker
1262 self.cfgData = cfgData
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001263 self.rqdata = RunQueueData(self, cooker, cfgData, dataCaches, taskData, targets)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001264
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001265 self.hashvalidate = cfgData.getVar("BB_HASHCHECK_FUNCTION") or None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001266 self.depvalidate = cfgData.getVar("BB_SETSCENE_DEPVALID") or None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001267
1268 self.state = runQueuePrepare
1269
1270 # For disk space monitor
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001271 # Invoked at regular time intervals via the bitbake heartbeat event
1272 # while the build is running. We generate a unique name for the handler
1273 # here, just in case that there ever is more than one RunQueue instance,
Brad Bishop96ff1982019-08-19 13:50:42 -04001274 # start the handler when reaching runQueueSceneInit, and stop it when
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001275 # done with the build.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001276 self.dm = monitordisk.diskMonitor(cfgData)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001277 self.dm_event_handler_name = '_bb_diskmonitor_' + str(id(self))
1278 self.dm_event_handler_registered = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001279 self.rqexe = None
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001280 self.worker = {}
1281 self.fakeworker = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001282
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001283 def _start_worker(self, mc, fakeroot = False, rqexec = None):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001284 logger.debug("Starting bitbake-worker")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001285 magic = "decafbad"
1286 if self.cooker.configuration.profile:
1287 magic = "decafbadbad"
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001288 fakerootlogs = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001289 if fakeroot:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001290 magic = magic + "beef"
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001291 mcdata = self.cooker.databuilder.mcdata[mc]
Brad Bishop19323692019-04-05 15:28:33 -04001292 fakerootcmd = shlex.split(mcdata.getVar("FAKEROOTCMD"))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001293 fakerootenv = (mcdata.getVar("FAKEROOTBASEENV") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001294 env = os.environ.copy()
1295 for key, value in (var.split('=') for var in fakerootenv):
1296 env[key] = value
Brad Bishop19323692019-04-05 15:28:33 -04001297 worker = subprocess.Popen(fakerootcmd + ["bitbake-worker", magic], stdout=subprocess.PIPE, stdin=subprocess.PIPE, env=env)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001298 fakerootlogs = self.rqdata.dataCaches[mc].fakerootlogs
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001299 else:
1300 worker = subprocess.Popen(["bitbake-worker", magic], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
1301 bb.utils.nonblockingfd(worker.stdout)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001302 workerpipe = runQueuePipe(worker.stdout, None, self.cfgData, self, rqexec, fakerootlogs=fakerootlogs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001303
1304 workerdata = {
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001305 "taskdeps" : self.rqdata.dataCaches[mc].task_deps,
1306 "fakerootenv" : self.rqdata.dataCaches[mc].fakerootenv,
1307 "fakerootdirs" : self.rqdata.dataCaches[mc].fakerootdirs,
1308 "fakerootnoenv" : self.rqdata.dataCaches[mc].fakerootnoenv,
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001309 "sigdata" : bb.parse.siggen.get_taskdata(),
Andrew Geissler82c905d2020-04-13 13:39:40 -05001310 "logdefaultlevel" : bb.msg.loggerDefaultLogLevel,
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001311 "build_verbose_shell" : self.cooker.configuration.build_verbose_shell,
1312 "build_verbose_stdout" : self.cooker.configuration.build_verbose_stdout,
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001313 "logdefaultdomain" : bb.msg.loggerDefaultDomains,
1314 "prhost" : self.cooker.prhost,
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001315 "buildname" : self.cfgData.getVar("BUILDNAME"),
1316 "date" : self.cfgData.getVar("DATE"),
1317 "time" : self.cfgData.getVar("TIME"),
Brad Bishopa34c0302019-09-23 22:34:48 -04001318 "hashservaddr" : self.cooker.hashservaddr,
Andrew Geissler9b4d8b02021-02-19 12:26:16 -06001319 "umask" : self.cfgData.getVar("BB_DEFAULT_UMASK"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001320 }
1321
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001322 worker.stdin.write(b"<cookerconfig>" + pickle.dumps(self.cooker.configuration) + b"</cookerconfig>")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001323 worker.stdin.write(b"<extraconfigdata>" + pickle.dumps(self.cooker.extraconfigdata) + b"</extraconfigdata>")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001324 worker.stdin.write(b"<workerdata>" + pickle.dumps(workerdata) + b"</workerdata>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001325 worker.stdin.flush()
1326
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001327 return RunQueueWorker(worker, workerpipe)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001328
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001329 def _teardown_worker(self, worker):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001330 if not worker:
1331 return
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001332 logger.debug("Teardown for bitbake-worker")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001333 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001334 worker.process.stdin.write(b"<quit></quit>")
1335 worker.process.stdin.flush()
1336 worker.process.stdin.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001337 except IOError:
1338 pass
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001339 while worker.process.returncode is None:
1340 worker.pipe.read()
1341 worker.process.poll()
1342 while worker.pipe.read():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001343 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001344 worker.pipe.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001345
1346 def start_worker(self):
1347 if self.worker:
1348 self.teardown_workers()
1349 self.teardown = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001350 for mc in self.rqdata.dataCaches:
1351 self.worker[mc] = self._start_worker(mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001352
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001353 def start_fakeworker(self, rqexec, mc):
1354 if not mc in self.fakeworker:
1355 self.fakeworker[mc] = self._start_worker(mc, True, rqexec)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001356
1357 def teardown_workers(self):
1358 self.teardown = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001359 for mc in self.worker:
1360 self._teardown_worker(self.worker[mc])
1361 self.worker = {}
1362 for mc in self.fakeworker:
1363 self._teardown_worker(self.fakeworker[mc])
1364 self.fakeworker = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001365
1366 def read_workers(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001367 for mc in self.worker:
1368 self.worker[mc].pipe.read()
1369 for mc in self.fakeworker:
1370 self.fakeworker[mc].pipe.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001371
1372 def active_fds(self):
1373 fds = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001374 for mc in self.worker:
1375 fds.append(self.worker[mc].pipe.input)
1376 for mc in self.fakeworker:
1377 fds.append(self.fakeworker[mc].pipe.input)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001378 return fds
1379
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001380 def check_stamp_task(self, tid, taskname = None, recurse = False, cache = None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001381 def get_timestamp(f):
1382 try:
1383 if not os.access(f, os.F_OK):
1384 return None
1385 return os.stat(f)[stat.ST_MTIME]
1386 except:
1387 return None
1388
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001389 (mc, fn, tn, taskfn) = split_tid_mcfn(tid)
1390 if taskname is None:
1391 taskname = tn
1392
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001393 stampfile = bb.build.stampfile(taskname, self.rqdata.dataCaches[mc], taskfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001394
1395 # If the stamp is missing, it's not current
1396 if not os.access(stampfile, os.F_OK):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001397 logger.debug2("Stampfile %s not available", stampfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001398 return False
1399 # If it's a 'nostamp' task, it's not current
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001400 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001401 if 'nostamp' in taskdep and taskname in taskdep['nostamp']:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001402 logger.debug2("%s.%s is nostamp\n", fn, taskname)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001403 return False
1404
1405 if taskname != "do_setscene" and taskname.endswith("_setscene"):
1406 return True
1407
1408 if cache is None:
1409 cache = {}
1410
1411 iscurrent = True
1412 t1 = get_timestamp(stampfile)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001413 for dep in self.rqdata.runtaskentries[tid].depends:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001414 if iscurrent:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001415 (mc2, fn2, taskname2, taskfn2) = split_tid_mcfn(dep)
1416 stampfile2 = bb.build.stampfile(taskname2, self.rqdata.dataCaches[mc2], taskfn2)
1417 stampfile3 = bb.build.stampfile(taskname2 + "_setscene", self.rqdata.dataCaches[mc2], taskfn2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001418 t2 = get_timestamp(stampfile2)
1419 t3 = get_timestamp(stampfile3)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001420 if t3 and not t2:
1421 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001422 if t3 and t3 > t2:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001423 continue
Andrew Geissler595f6302022-01-24 19:11:47 +00001424 if fn == fn2:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001425 if not t2:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001426 logger.debug2('Stampfile %s does not exist', stampfile2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001427 iscurrent = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001428 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001429 if t1 < t2:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001430 logger.debug2('Stampfile %s < %s', stampfile, stampfile2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001431 iscurrent = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001432 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001433 if recurse and iscurrent:
1434 if dep in cache:
1435 iscurrent = cache[dep]
1436 if not iscurrent:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001437 logger.debug2('Stampfile for dependency %s:%s invalid (cached)' % (fn2, taskname2))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001438 else:
1439 iscurrent = self.check_stamp_task(dep, recurse=True, cache=cache)
1440 cache[dep] = iscurrent
1441 if recurse:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001442 cache[tid] = iscurrent
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001443 return iscurrent
1444
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001445 def validate_hashes(self, tocheck, data, currentcount=0, siginfo=False, summary=True):
Brad Bishop96ff1982019-08-19 13:50:42 -04001446 valid = set()
1447 if self.hashvalidate:
Brad Bishop08902b02019-08-20 09:16:51 -04001448 sq_data = {}
1449 sq_data['hash'] = {}
1450 sq_data['hashfn'] = {}
1451 sq_data['unihash'] = {}
Brad Bishop96ff1982019-08-19 13:50:42 -04001452 for tid in tocheck:
1453 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
Brad Bishop08902b02019-08-20 09:16:51 -04001454 sq_data['hash'][tid] = self.rqdata.runtaskentries[tid].hash
1455 sq_data['hashfn'][tid] = self.rqdata.dataCaches[mc].hashfn[taskfn]
1456 sq_data['unihash'][tid] = self.rqdata.runtaskentries[tid].unihash
Brad Bishop96ff1982019-08-19 13:50:42 -04001457
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001458 valid = self.validate_hash(sq_data, data, siginfo, currentcount, summary)
Brad Bishop96ff1982019-08-19 13:50:42 -04001459
1460 return valid
1461
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001462 def validate_hash(self, sq_data, d, siginfo, currentcount, summary):
1463 locs = {"sq_data" : sq_data, "d" : d, "siginfo" : siginfo, "currentcount" : currentcount, "summary" : summary}
Brad Bishop19323692019-04-05 15:28:33 -04001464
Brad Bishop08902b02019-08-20 09:16:51 -04001465 # Metadata has **kwargs so args can be added, sq_data can also gain new fields
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001466 call = self.hashvalidate + "(sq_data, d, siginfo=siginfo, currentcount=currentcount, summary=summary)"
Brad Bishop19323692019-04-05 15:28:33 -04001467
Brad Bishop19323692019-04-05 15:28:33 -04001468 return bb.utils.better_eval(call, locs)
1469
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001470 def _execute_runqueue(self):
1471 """
1472 Run the tasks in a queue prepared by rqdata.prepare()
1473 Upon failure, optionally try to recover the build using any alternate providers
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001474 (if the halt on failure configuration option isn't set)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001475 """
1476
1477 retval = True
1478
1479 if self.state is runQueuePrepare:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001480 # NOTE: if you add, remove or significantly refactor the stages of this
1481 # process then you should recalculate the weightings here. This is quite
1482 # easy to do - just change the next line temporarily to pass debug=True as
1483 # the last parameter and you'll get a printout of the weightings as well
1484 # as a map to the lines where next_stage() was called. Of course this isn't
1485 # critical, but it helps to keep the progress reporting accurate.
1486 self.rqdata.init_progress_reporter = bb.progress.MultiStageProcessProgressReporter(self.cooker.data,
1487 "Initialising tasks",
1488 [43, 967, 4, 3, 1, 5, 3, 7, 13, 1, 2, 1, 1, 246, 35, 1, 38, 1, 35, 2, 338, 204, 142, 3, 3, 37, 244])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001489 if self.rqdata.prepare() == 0:
1490 self.state = runQueueComplete
1491 else:
1492 self.state = runQueueSceneInit
Brad Bishop00e122a2019-10-05 11:10:57 -04001493 bb.parse.siggen.save_unitaskhashes()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001494
1495 if self.state is runQueueSceneInit:
Brad Bishop96ff1982019-08-19 13:50:42 -04001496 self.rqdata.init_progress_reporter.next_stage()
1497
1498 # we are ready to run, emit dependency info to any UI or class which
1499 # needs it
1500 depgraph = self.cooker.buildDependTree(self, self.rqdata.taskData)
1501 self.rqdata.init_progress_reporter.next_stage()
1502 bb.event.fire(bb.event.DepTreeGenerated(depgraph), self.cooker.data)
1503
Brad Bishope2d5b612018-11-23 10:55:50 +13001504 if not self.dm_event_handler_registered:
1505 res = bb.event.register(self.dm_event_handler_name,
Brad Bishop96ff1982019-08-19 13:50:42 -04001506 lambda x: self.dm.check(self) if self.state in [runQueueRunning, runQueueCleanUp] else False,
Andrew Geissler9b4d8b02021-02-19 12:26:16 -06001507 ('bb.event.HeartbeatEvent',), data=self.cfgData)
Brad Bishope2d5b612018-11-23 10:55:50 +13001508 self.dm_event_handler_registered = True
1509
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001510 dump = self.cooker.configuration.dump_signatures
1511 if dump:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001512 self.rqdata.init_progress_reporter.finish()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001513 if 'printdiff' in dump:
1514 invalidtasks = self.print_diffscenetasks()
1515 self.dump_signatures(dump)
1516 if 'printdiff' in dump:
1517 self.write_diffscenetasks(invalidtasks)
1518 self.state = runQueueComplete
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001519
Brad Bishop96ff1982019-08-19 13:50:42 -04001520 if self.state is runQueueSceneInit:
1521 self.rqdata.init_progress_reporter.next_stage()
1522 self.start_worker()
1523 self.rqdata.init_progress_reporter.next_stage()
1524 self.rqexe = RunQueueExecute(self)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001525
Brad Bishop96ff1982019-08-19 13:50:42 -04001526 # If we don't have any setscene functions, skip execution
Andrew Geissler595f6302022-01-24 19:11:47 +00001527 if not self.rqdata.runq_setscene_tids:
Brad Bishop96ff1982019-08-19 13:50:42 -04001528 logger.info('No setscene tasks')
1529 for tid in self.rqdata.runtaskentries:
Andrew Geissler595f6302022-01-24 19:11:47 +00001530 if not self.rqdata.runtaskentries[tid].depends:
Brad Bishop96ff1982019-08-19 13:50:42 -04001531 self.rqexe.setbuildable(tid)
1532 self.rqexe.tasks_notcovered.add(tid)
1533 self.rqexe.sqdone = True
1534 logger.info('Executing Tasks')
1535 self.state = runQueueRunning
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001536
1537 if self.state is runQueueRunning:
1538 retval = self.rqexe.execute()
1539
1540 if self.state is runQueueCleanUp:
1541 retval = self.rqexe.finish()
1542
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001543 build_done = self.state is runQueueComplete or self.state is runQueueFailed
1544
1545 if build_done and self.dm_event_handler_registered:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -06001546 bb.event.remove(self.dm_event_handler_name, None, data=self.cfgData)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001547 self.dm_event_handler_registered = False
1548
1549 if build_done and self.rqexe:
Brad Bishop08902b02019-08-20 09:16:51 -04001550 bb.parse.siggen.save_unitaskhashes()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001551 self.teardown_workers()
Brad Bishop96ff1982019-08-19 13:50:42 -04001552 if self.rqexe:
1553 if self.rqexe.stats.failed:
1554 logger.info("Tasks Summary: Attempted %d tasks of which %d didn't need to be rerun and %d failed.", self.rqexe.stats.completed + self.rqexe.stats.failed, self.rqexe.stats.skipped, self.rqexe.stats.failed)
1555 else:
1556 # Let's avoid the word "failed" if nothing actually did
1557 logger.info("Tasks Summary: Attempted %d tasks of which %d didn't need to be rerun and all succeeded.", self.rqexe.stats.completed, self.rqexe.stats.skipped)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001558
1559 if self.state is runQueueFailed:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001560 raise bb.runqueue.TaskFailure(self.rqexe.failed_tids)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001561
1562 if self.state is runQueueComplete:
1563 # All done
1564 return False
1565
1566 # Loop
1567 return retval
1568
1569 def execute_runqueue(self):
1570 # Catch unexpected exceptions and ensure we exit when an error occurs, not loop.
1571 try:
1572 return self._execute_runqueue()
1573 except bb.runqueue.TaskFailure:
1574 raise
1575 except SystemExit:
1576 raise
1577 except bb.BBHandledException:
1578 try:
1579 self.teardown_workers()
1580 except:
1581 pass
1582 self.state = runQueueComplete
1583 raise
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001584 except Exception as err:
1585 logger.exception("An uncaught exception occurred in runqueue")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001586 try:
1587 self.teardown_workers()
1588 except:
1589 pass
1590 self.state = runQueueComplete
1591 raise
1592
1593 def finish_runqueue(self, now = False):
1594 if not self.rqexe:
1595 self.state = runQueueComplete
1596 return
1597
1598 if now:
1599 self.rqexe.finish_now()
1600 else:
1601 self.rqexe.finish()
1602
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001603 def rq_dump_sigfn(self, fn, options):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001604 bb_cache = bb.cache.NoCache(self.cooker.databuilder)
Andrew Geissler5a43b432020-06-13 10:46:56 -05001605 mc = bb.runqueue.mc_from_tid(fn)
1606 the_data = bb_cache.loadDataFull(fn, self.cooker.collections[mc].get_file_appends(fn))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001607 siggen = bb.parse.siggen
1608 dataCaches = self.rqdata.dataCaches
1609 siggen.dump_sigfn(fn, dataCaches, options)
1610
1611 def dump_signatures(self, options):
1612 fns = set()
1613 bb.note("Reparsing files to collect dependency data")
1614
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001615 for tid in self.rqdata.runtaskentries:
1616 fn = fn_from_tid(tid)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001617 fns.add(fn)
1618
1619 max_process = int(self.cfgData.getVar("BB_NUMBER_PARSE_THREADS") or os.cpu_count() or 1)
1620 # We cannot use the real multiprocessing.Pool easily due to some local data
1621 # that can't be pickled. This is a cheap multi-process solution.
1622 launched = []
1623 while fns:
1624 if len(launched) < max_process:
1625 p = Process(target=self.rq_dump_sigfn, args=(fns.pop(), options))
1626 p.start()
1627 launched.append(p)
1628 for q in launched:
1629 # The finished processes are joined when calling is_alive()
1630 if not q.is_alive():
1631 launched.remove(q)
1632 for p in launched:
1633 p.join()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001634
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001635 bb.parse.siggen.dump_sigs(self.rqdata.dataCaches, options)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001636
1637 return
1638
1639 def print_diffscenetasks(self):
1640
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001641 noexec = []
Brad Bishop96ff1982019-08-19 13:50:42 -04001642 tocheck = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001643
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001644 for tid in self.rqdata.runtaskentries:
1645 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
1646 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001647
1648 if 'noexec' in taskdep and taskname in taskdep['noexec']:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001649 noexec.append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001650 continue
1651
Brad Bishop96ff1982019-08-19 13:50:42 -04001652 tocheck.add(tid)
Brad Bishop19323692019-04-05 15:28:33 -04001653
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001654 valid_new = self.validate_hashes(tocheck, self.cooker.data, 0, True, summary=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001655
1656 # Tasks which are both setscene and noexec never care about dependencies
1657 # We therefore find tasks which are setscene and noexec and mark their
1658 # unique dependencies as valid.
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001659 for tid in noexec:
1660 if tid not in self.rqdata.runq_setscene_tids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001661 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001662 for dep in self.rqdata.runtaskentries[tid].depends:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001663 hasnoexecparents = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001664 for dep2 in self.rqdata.runtaskentries[dep].revdeps:
1665 if dep2 in self.rqdata.runq_setscene_tids and dep2 in noexec:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001666 continue
1667 hasnoexecparents = False
1668 break
1669 if hasnoexecparents:
1670 valid_new.add(dep)
1671
1672 invalidtasks = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001673 for tid in self.rqdata.runtaskentries:
1674 if tid not in valid_new and tid not in noexec:
1675 invalidtasks.add(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001676
1677 found = set()
1678 processed = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001679 for tid in invalidtasks:
1680 toprocess = set([tid])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001681 while toprocess:
1682 next = set()
1683 for t in toprocess:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001684 for dep in self.rqdata.runtaskentries[t].depends:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001685 if dep in invalidtasks:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001686 found.add(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001687 if dep not in processed:
1688 processed.add(dep)
1689 next.add(dep)
1690 toprocess = next
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001691 if tid in found:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001692 toprocess = set()
1693
1694 tasklist = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001695 for tid in invalidtasks.difference(found):
1696 tasklist.append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001697
1698 if tasklist:
1699 bb.plain("The differences between the current build and any cached tasks start at the following tasks:\n" + "\n".join(tasklist))
1700
1701 return invalidtasks.difference(found)
1702
1703 def write_diffscenetasks(self, invalidtasks):
1704
1705 # Define recursion callback
1706 def recursecb(key, hash1, hash2):
1707 hashes = [hash1, hash2]
1708 hashfiles = bb.siggen.find_siginfo(key, None, hashes, self.cfgData)
1709
1710 recout = []
1711 if len(hashfiles) == 2:
1712 out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb)
Brad Bishopc342db32019-05-15 21:57:59 -04001713 recout.extend(list(' ' + l for l in out2))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001714 else:
1715 recout.append("Unable to find matching sigdata for %s with hashes %s or %s" % (key, hash1, hash2))
1716
1717 return recout
1718
1719
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001720 for tid in invalidtasks:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001721 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
1722 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001723 h = self.rqdata.runtaskentries[tid].hash
Patrick Williams03907ee2022-05-01 06:28:52 -05001724 matches = bb.siggen.find_siginfo(pn, taskname, [], self.cooker.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001725 match = None
1726 for m in matches:
1727 if h in m:
1728 match = m
1729 if match is None:
1730 bb.fatal("Can't find a task we're supposed to have written out? (hash: %s)?" % h)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001731 matches = {k : v for k, v in iter(matches.items()) if h not in k}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001732 if matches:
1733 latestmatch = sorted(matches.keys(), key=lambda f: matches[f])[-1]
Brad Bishop19323692019-04-05 15:28:33 -04001734 prevh = __find_sha256__.search(latestmatch).group(0)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001735 output = bb.siggen.compare_sigfiles(latestmatch, match, recursecb)
1736 bb.plain("\nTask %s:%s couldn't be used from the cache because:\n We need hash %s, closest matching task was %s\n " % (pn, taskname, h, prevh) + '\n '.join(output))
1737
Brad Bishop96ff1982019-08-19 13:50:42 -04001738
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001739class RunQueueExecute:
1740
1741 def __init__(self, rq):
1742 self.rq = rq
1743 self.cooker = rq.cooker
1744 self.cfgData = rq.cfgData
1745 self.rqdata = rq.rqdata
1746
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001747 self.number_tasks = int(self.cfgData.getVar("BB_NUMBER_THREADS") or 1)
1748 self.scheduler = self.cfgData.getVar("BB_SCHEDULER") or "speed"
Patrick Williamsdb4c27e2022-08-05 08:10:29 -05001749 self.max_cpu_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_CPU")
1750 self.max_io_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_IO")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001751
Brad Bishop96ff1982019-08-19 13:50:42 -04001752 self.sq_buildable = set()
1753 self.sq_running = set()
1754 self.sq_live = set()
1755
Brad Bishop08902b02019-08-20 09:16:51 -04001756 self.updated_taskhash_queue = []
1757 self.pending_migrations = set()
1758
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001759 self.runq_buildable = set()
1760 self.runq_running = set()
1761 self.runq_complete = set()
Andrew Geissler82c905d2020-04-13 13:39:40 -05001762 self.runq_tasksrun = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001763
1764 self.build_stamps = {}
1765 self.build_stamps2 = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001766 self.failed_tids = []
Brad Bishop96ff1982019-08-19 13:50:42 -04001767 self.sq_deferred = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001768
1769 self.stampcache = {}
1770
Brad Bishop08902b02019-08-20 09:16:51 -04001771 self.holdoff_tasks = set()
Brad Bishopc68388fc2019-08-26 01:33:31 -04001772 self.holdoff_need_update = True
Brad Bishop96ff1982019-08-19 13:50:42 -04001773 self.sqdone = False
1774
Andrew Geissler5199d832021-09-24 16:47:35 -05001775 self.stats = RunQueueStats(len(self.rqdata.runtaskentries), len(self.rqdata.runq_setscene_tids))
Brad Bishop96ff1982019-08-19 13:50:42 -04001776
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001777 for mc in rq.worker:
1778 rq.worker[mc].pipe.setrunqueueexec(self)
1779 for mc in rq.fakeworker:
1780 rq.fakeworker[mc].pipe.setrunqueueexec(self)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001781
1782 if self.number_tasks <= 0:
1783 bb.fatal("Invalid BB_NUMBER_THREADS %s" % self.number_tasks)
1784
Patrick Williamsdb4c27e2022-08-05 08:10:29 -05001785 lower_limit = 1.0
1786 upper_limit = 1000000.0
1787 if self.max_cpu_pressure:
1788 self.max_cpu_pressure = float(self.max_cpu_pressure)
1789 if self.max_cpu_pressure < lower_limit:
1790 bb.fatal("Invalid BB_PRESSURE_MAX_CPU %s, minimum value is %s." % (self.max_cpu_pressure, lower_limit))
1791 if self.max_cpu_pressure > upper_limit:
1792 bb.warn("Your build will be largely unregulated since BB_PRESSURE_MAX_CPU is set to %s. It is very unlikely that such high pressure will be experienced." % (self.max_cpu_pressure))
1793
1794 if self.max_io_pressure:
1795 self.max_io_pressure = float(self.max_io_pressure)
1796 if self.max_io_pressure < lower_limit:
1797 bb.fatal("Invalid BB_PRESSURE_MAX_IO %s, minimum value is %s." % (self.max_io_pressure, lower_limit))
1798 if self.max_io_pressure > upper_limit:
1799 bb.warn("Your build will be largely unregulated since BB_PRESSURE_MAX_IO is set to %s. It is very unlikely that such high pressure will be experienced." % (self.max_io_pressure))
1800
Brad Bishop96ff1982019-08-19 13:50:42 -04001801 # List of setscene tasks which we've covered
1802 self.scenequeue_covered = set()
1803 # List of tasks which are covered (including setscene ones)
1804 self.tasks_covered = set()
1805 self.tasks_scenequeue_done = set()
1806 self.scenequeue_notcovered = set()
1807 self.tasks_notcovered = set()
1808 self.scenequeue_notneeded = set()
1809
Brad Bishop08902b02019-08-20 09:16:51 -04001810 # We can't skip specified target tasks which aren't setscene tasks
1811 self.cantskip = set(self.rqdata.target_tids)
1812 self.cantskip.difference_update(self.rqdata.runq_setscene_tids)
1813 self.cantskip.intersection_update(self.rqdata.runtaskentries)
Brad Bishop96ff1982019-08-19 13:50:42 -04001814
1815 schedulers = self.get_schedulers()
1816 for scheduler in schedulers:
1817 if self.scheduler == scheduler.name:
1818 self.sched = scheduler(self, self.rqdata)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001819 logger.debug("Using runqueue scheduler '%s'", scheduler.name)
Brad Bishop96ff1982019-08-19 13:50:42 -04001820 break
1821 else:
1822 bb.fatal("Invalid scheduler '%s'. Available schedulers: %s" %
1823 (self.scheduler, ", ".join(obj.name for obj in schedulers)))
1824
Andrew Geissler595f6302022-01-24 19:11:47 +00001825 #if self.rqdata.runq_setscene_tids:
Brad Bishop08902b02019-08-20 09:16:51 -04001826 self.sqdata = SQData()
1827 build_scenequeue_data(self.sqdata, self.rqdata, self.rq, self.cooker, self.stampcache, self)
Brad Bishop96ff1982019-08-19 13:50:42 -04001828
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001829 def runqueue_process_waitpid(self, task, status, fakerootlog=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001830
1831 # self.build_stamps[pid] may not exist when use shared work directory.
1832 if task in self.build_stamps:
1833 self.build_stamps2.remove(self.build_stamps[task])
1834 del self.build_stamps[task]
1835
Brad Bishop96ff1982019-08-19 13:50:42 -04001836 if task in self.sq_live:
1837 if status != 0:
1838 self.sq_task_fail(task, status)
1839 else:
1840 self.sq_task_complete(task)
1841 self.sq_live.remove(task)
Andrew Geissler5199d832021-09-24 16:47:35 -05001842 self.stats.updateActiveSetscene(len(self.sq_live))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001843 else:
Brad Bishop96ff1982019-08-19 13:50:42 -04001844 if status != 0:
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001845 self.task_fail(task, status, fakerootlog=fakerootlog)
Brad Bishop96ff1982019-08-19 13:50:42 -04001846 else:
1847 self.task_complete(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001848 return True
1849
1850 def finish_now(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001851 for mc in self.rq.worker:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001852 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001853 self.rq.worker[mc].process.stdin.write(b"<finishnow></finishnow>")
1854 self.rq.worker[mc].process.stdin.flush()
1855 except IOError:
1856 # worker must have died?
1857 pass
1858 for mc in self.rq.fakeworker:
1859 try:
1860 self.rq.fakeworker[mc].process.stdin.write(b"<finishnow></finishnow>")
1861 self.rq.fakeworker[mc].process.stdin.flush()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001862 except IOError:
1863 # worker must have died?
1864 pass
1865
Andrew Geissler595f6302022-01-24 19:11:47 +00001866 if self.failed_tids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001867 self.rq.state = runQueueFailed
1868 return
1869
1870 self.rq.state = runQueueComplete
1871 return
1872
1873 def finish(self):
1874 self.rq.state = runQueueCleanUp
1875
Andrew Geissler5199d832021-09-24 16:47:35 -05001876 active = self.stats.active + len(self.sq_live)
Brad Bishop96ff1982019-08-19 13:50:42 -04001877 if active > 0:
1878 bb.event.fire(runQueueExitWait(active), self.cfgData)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001879 self.rq.read_workers()
1880 return self.rq.active_fds()
1881
Andrew Geissler595f6302022-01-24 19:11:47 +00001882 if self.failed_tids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001883 self.rq.state = runQueueFailed
1884 return True
1885
1886 self.rq.state = runQueueComplete
1887 return True
1888
Brad Bishop96ff1982019-08-19 13:50:42 -04001889 # Used by setscene only
1890 def check_dependencies(self, task, taskdeps):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001891 if not self.rq.depvalidate:
1892 return False
1893
Brad Bishop08902b02019-08-20 09:16:51 -04001894 # Must not edit parent data
1895 taskdeps = set(taskdeps)
1896
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001897 taskdata = {}
1898 taskdeps.add(task)
1899 for dep in taskdeps:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001900 (mc, fn, taskname, taskfn) = split_tid_mcfn(dep)
1901 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001902 taskdata[dep] = [pn, taskname, fn]
1903 call = self.rq.depvalidate + "(task, taskdata, notneeded, d)"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001904 locs = { "task" : task, "taskdata" : taskdata, "notneeded" : self.scenequeue_notneeded, "d" : self.cooker.data }
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001905 valid = bb.utils.better_eval(call, locs)
1906 return valid
1907
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001908 def can_start_task(self):
Andrew Geissler5199d832021-09-24 16:47:35 -05001909 active = self.stats.active + len(self.sq_live)
Brad Bishop96ff1982019-08-19 13:50:42 -04001910 can_start = active < self.number_tasks
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001911 return can_start
1912
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001913 def get_schedulers(self):
1914 schedulers = set(obj for obj in globals().values()
1915 if type(obj) is type and
1916 issubclass(obj, RunQueueScheduler))
1917
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001918 user_schedulers = self.cfgData.getVar("BB_SCHEDULERS")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001919 if user_schedulers:
1920 for sched in user_schedulers.split():
1921 if not "." in sched:
1922 bb.note("Ignoring scheduler '%s' from BB_SCHEDULERS: not an import" % sched)
1923 continue
1924
1925 modname, name = sched.rsplit(".", 1)
1926 try:
1927 module = __import__(modname, fromlist=(name,))
1928 except ImportError as exc:
1929 logger.critical("Unable to import scheduler '%s' from '%s': %s" % (name, modname, exc))
1930 raise SystemExit(1)
1931 else:
1932 schedulers.add(getattr(module, name))
1933 return schedulers
1934
1935 def setbuildable(self, task):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001936 self.runq_buildable.add(task)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001937 self.sched.newbuildable(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001938
1939 def task_completeoutright(self, task):
1940 """
1941 Mark a task as completed
1942 Look at the reverse dependencies and mark any task with
1943 completed dependencies as buildable
1944 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001945 self.runq_complete.add(task)
1946 for revdep in self.rqdata.runtaskentries[task].revdeps:
1947 if revdep in self.runq_running:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001948 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001949 if revdep in self.runq_buildable:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001950 continue
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001951 alldeps = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001952 for dep in self.rqdata.runtaskentries[revdep].depends:
1953 if dep not in self.runq_complete:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001954 alldeps = False
1955 break
1956 if alldeps:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001957 self.setbuildable(revdep)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001958 logger.debug("Marking task %s as buildable", revdep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001959
Andrew Geissler5199d832021-09-24 16:47:35 -05001960 for t in self.sq_deferred.copy():
1961 if self.sq_deferred[t] == task:
1962 logger.debug2("Deferred task %s now buildable" % t)
1963 del self.sq_deferred[t]
1964 update_scenequeue_data([t], self.sqdata, self.rqdata, self.rq, self.cooker, self.stampcache, self, summary=False)
1965
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001966 def task_complete(self, task):
1967 self.stats.taskCompleted()
1968 bb.event.fire(runQueueTaskCompleted(task, self.stats, self.rq), self.cfgData)
1969 self.task_completeoutright(task)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001970 self.runq_tasksrun.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001971
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001972 def task_fail(self, task, exitcode, fakerootlog=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001973 """
1974 Called when a task has failed
1975 Updates the state engine with the failure
1976 """
1977 self.stats.taskFailed()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001978 self.failed_tids.append(task)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001979
Andrew Geissler595f6302022-01-24 19:11:47 +00001980 fakeroot_log = []
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001981 if fakerootlog and os.path.exists(fakerootlog):
1982 with open(fakerootlog) as fakeroot_log_file:
1983 fakeroot_failed = False
1984 for line in reversed(fakeroot_log_file.readlines()):
1985 for fakeroot_error in ['mismatch', 'error', 'fatal']:
1986 if fakeroot_error in line.lower():
1987 fakeroot_failed = True
1988 if 'doing new pid setup and server start' in line:
1989 break
Andrew Geissler595f6302022-01-24 19:11:47 +00001990 fakeroot_log.append(line)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001991
1992 if not fakeroot_failed:
Andrew Geissler595f6302022-01-24 19:11:47 +00001993 fakeroot_log = []
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001994
Andrew Geissler595f6302022-01-24 19:11:47 +00001995 bb.event.fire(runQueueTaskFailed(task, self.stats, exitcode, self.rq, fakeroot_log=("".join(fakeroot_log) or None)), self.cfgData)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001996
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001997 if self.rqdata.taskData[''].halt:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001998 self.rq.state = runQueueCleanUp
1999
2000 def task_skip(self, task, reason):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002001 self.runq_running.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002002 self.setbuildable(task)
2003 bb.event.fire(runQueueTaskSkipped(task, self.stats, self.rq, reason), self.cfgData)
2004 self.task_completeoutright(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002005 self.stats.taskSkipped()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08002006 self.stats.taskCompleted()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002007
Brad Bishop08902b02019-08-20 09:16:51 -04002008 def summarise_scenequeue_errors(self):
2009 err = False
2010 if not self.sqdone:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002011 logger.debug('We could skip tasks %s', "\n".join(sorted(self.scenequeue_covered)))
Andrew Geissler5199d832021-09-24 16:47:35 -05002012 completeevent = sceneQueueComplete(self.stats, self.rq)
Brad Bishop08902b02019-08-20 09:16:51 -04002013 bb.event.fire(completeevent, self.cfgData)
2014 if self.sq_deferred:
2015 logger.error("Scenequeue had deferred entries: %s" % pprint.pformat(self.sq_deferred))
2016 err = True
2017 if self.updated_taskhash_queue:
2018 logger.error("Scenequeue had unprocessed changed taskhash entries: %s" % pprint.pformat(self.updated_taskhash_queue))
2019 err = True
2020 if self.holdoff_tasks:
2021 logger.error("Scenequeue had holdoff tasks: %s" % pprint.pformat(self.holdoff_tasks))
2022 err = True
2023
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002024 for tid in self.scenequeue_covered.intersection(self.scenequeue_notcovered):
2025 # No task should end up in both covered and uncovered, that is a bug.
2026 logger.error("Setscene task %s in both covered and notcovered." % tid)
2027
Brad Bishop08902b02019-08-20 09:16:51 -04002028 for tid in self.rqdata.runq_setscene_tids:
2029 if tid not in self.scenequeue_covered and tid not in self.scenequeue_notcovered:
2030 err = True
2031 logger.error("Setscene Task %s was never marked as covered or not covered" % tid)
2032 if tid not in self.sq_buildable:
2033 err = True
2034 logger.error("Setscene Task %s was never marked as buildable" % tid)
2035 if tid not in self.sq_running:
2036 err = True
2037 logger.error("Setscene Task %s was never marked as running" % tid)
2038
2039 for x in self.rqdata.runtaskentries:
2040 if x not in self.tasks_covered and x not in self.tasks_notcovered:
2041 logger.error("Task %s was never moved from the setscene queue" % x)
2042 err = True
2043 if x not in self.tasks_scenequeue_done:
2044 logger.error("Task %s was never processed by the setscene code" % x)
2045 err = True
Andrew Geissler595f6302022-01-24 19:11:47 +00002046 if not self.rqdata.runtaskentries[x].depends and x not in self.runq_buildable:
Brad Bishop08902b02019-08-20 09:16:51 -04002047 logger.error("Task %s was never marked as buildable by the setscene code" % x)
2048 err = True
2049 return err
2050
2051
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002052 def execute(self):
2053 """
Brad Bishop96ff1982019-08-19 13:50:42 -04002054 Run the tasks in a queue prepared by prepare_runqueue
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002055 """
2056
2057 self.rq.read_workers()
Andrew Geissler82c905d2020-04-13 13:39:40 -05002058 if self.updated_taskhash_queue or self.pending_migrations:
2059 self.process_possible_migrations()
2060
2061 if not hasattr(self, "sorted_setscene_tids"):
2062 # Don't want to sort this set every execution
2063 self.sorted_setscene_tids = sorted(self.rqdata.runq_setscene_tids)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002064
Brad Bishop96ff1982019-08-19 13:50:42 -04002065 task = None
2066 if not self.sqdone and self.can_start_task():
2067 # Find the next setscene to run
Andrew Geissler82c905d2020-04-13 13:39:40 -05002068 for nexttask in self.sorted_setscene_tids:
Brad Bishop96ff1982019-08-19 13:50:42 -04002069 if nexttask in self.sq_buildable and nexttask not in self.sq_running and self.sqdata.stamps[nexttask] not in self.build_stamps.values():
Andrew Geissler595f6302022-01-24 19:11:47 +00002070 if nexttask not in self.sqdata.unskippable and self.sqdata.sq_revdeps[nexttask] and self.sqdata.sq_revdeps[nexttask].issubset(self.scenequeue_covered) and self.check_dependencies(nexttask, self.sqdata.sq_revdeps[nexttask]):
Brad Bishop96ff1982019-08-19 13:50:42 -04002071 if nexttask not in self.rqdata.target_tids:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002072 logger.debug2("Skipping setscene for task %s" % nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002073 self.sq_task_skip(nexttask)
2074 self.scenequeue_notneeded.add(nexttask)
2075 if nexttask in self.sq_deferred:
2076 del self.sq_deferred[nexttask]
2077 return True
Brad Bishop08902b02019-08-20 09:16:51 -04002078 # If covered tasks are running, need to wait for them to complete
2079 for t in self.sqdata.sq_covered_tasks[nexttask]:
2080 if t in self.runq_running and t not in self.runq_complete:
2081 continue
Brad Bishop96ff1982019-08-19 13:50:42 -04002082 if nexttask in self.sq_deferred:
2083 if self.sq_deferred[nexttask] not in self.runq_complete:
2084 continue
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002085 logger.debug("Task %s no longer deferred" % nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002086 del self.sq_deferred[nexttask]
Brad Bishop1d80a2e2019-11-15 16:35:03 -05002087 valid = self.rq.validate_hashes(set([nexttask]), self.cooker.data, 0, False, summary=False)
Brad Bishop96ff1982019-08-19 13:50:42 -04002088 if not valid:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002089 logger.debug("%s didn't become valid, skipping setscene" % nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002090 self.sq_task_failoutright(nexttask)
2091 return True
Brad Bishop96ff1982019-08-19 13:50:42 -04002092 if nexttask in self.sqdata.outrightfail:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002093 logger.debug2('No package found, so skipping setscene task %s', nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002094 self.sq_task_failoutright(nexttask)
2095 return True
2096 if nexttask in self.sqdata.unskippable:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002097 logger.debug2("Setscene task %s is unskippable" % nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002098 task = nexttask
2099 break
2100 if task is not None:
2101 (mc, fn, taskname, taskfn) = split_tid_mcfn(task)
2102 taskname = taskname + "_setscene"
2103 if self.rq.check_stamp_task(task, taskname_from_tid(task), recurse = True, cache=self.stampcache):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002104 logger.debug2('Stamp for underlying task %s is current, so skipping setscene variant', task)
Brad Bishop96ff1982019-08-19 13:50:42 -04002105 self.sq_task_failoutright(task)
2106 return True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002107
Brad Bishop96ff1982019-08-19 13:50:42 -04002108 if self.cooker.configuration.force:
2109 if task in self.rqdata.target_tids:
2110 self.sq_task_failoutright(task)
2111 return True
2112
2113 if self.rq.check_stamp_task(task, taskname, cache=self.stampcache):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002114 logger.debug2('Setscene stamp current task %s, so skip it and its dependencies', task)
Brad Bishop96ff1982019-08-19 13:50:42 -04002115 self.sq_task_skip(task)
2116 return True
2117
2118 if self.cooker.configuration.skipsetscene:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002119 logger.debug2('No setscene tasks should be executed. Skipping %s', task)
Brad Bishop96ff1982019-08-19 13:50:42 -04002120 self.sq_task_failoutright(task)
2121 return True
2122
Andrew Geissler5199d832021-09-24 16:47:35 -05002123 startevent = sceneQueueTaskStarted(task, self.stats, self.rq)
Brad Bishop96ff1982019-08-19 13:50:42 -04002124 bb.event.fire(startevent, self.cfgData)
2125
2126 taskdepdata = self.sq_build_taskdepdata(task)
2127
2128 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
2129 taskhash = self.rqdata.get_task_hash(task)
2130 unihash = self.rqdata.get_task_unihash(task)
2131 if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not self.cooker.configuration.dry_run:
2132 if not mc in self.rq.fakeworker:
2133 self.rq.start_fakeworker(self, mc)
Andrew Geissler5a43b432020-06-13 10:46:56 -05002134 self.rq.fakeworker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, taskhash, unihash, True, self.cooker.collections[mc].get_file_appends(taskfn), taskdepdata, False)) + b"</runtask>")
Brad Bishop96ff1982019-08-19 13:50:42 -04002135 self.rq.fakeworker[mc].process.stdin.flush()
2136 else:
Andrew Geissler5a43b432020-06-13 10:46:56 -05002137 self.rq.worker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, taskhash, unihash, True, self.cooker.collections[mc].get_file_appends(taskfn), taskdepdata, False)) + b"</runtask>")
Brad Bishop96ff1982019-08-19 13:50:42 -04002138 self.rq.worker[mc].process.stdin.flush()
2139
2140 self.build_stamps[task] = bb.build.stampfile(taskname, self.rqdata.dataCaches[mc], taskfn, noextra=True)
2141 self.build_stamps2.append(self.build_stamps[task])
2142 self.sq_running.add(task)
2143 self.sq_live.add(task)
Andrew Geissler5199d832021-09-24 16:47:35 -05002144 self.stats.updateActiveSetscene(len(self.sq_live))
Brad Bishop96ff1982019-08-19 13:50:42 -04002145 if self.can_start_task():
2146 return True
2147
Brad Bishopc68388fc2019-08-26 01:33:31 -04002148 self.update_holdofftasks()
2149
Brad Bishop08902b02019-08-20 09:16:51 -04002150 if not self.sq_live and not self.sqdone and not self.sq_deferred and not self.updated_taskhash_queue and not self.holdoff_tasks:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002151 hashequiv_logger.verbose("Setscene tasks completed")
Brad Bishop96ff1982019-08-19 13:50:42 -04002152
Brad Bishop08902b02019-08-20 09:16:51 -04002153 err = self.summarise_scenequeue_errors()
Brad Bishop96ff1982019-08-19 13:50:42 -04002154 if err:
2155 self.rq.state = runQueueFailed
2156 return True
2157
2158 if self.cooker.configuration.setsceneonly:
2159 self.rq.state = runQueueComplete
2160 return True
2161 self.sqdone = True
2162
2163 if self.stats.total == 0:
2164 # nothing to do
2165 self.rq.state = runQueueComplete
2166 return True
2167
2168 if self.cooker.configuration.setsceneonly:
2169 task = None
2170 else:
2171 task = self.sched.next()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002172 if task is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002173 (mc, fn, taskname, taskfn) = split_tid_mcfn(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002174
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002175 if self.rqdata.setscene_ignore_tasks is not None:
2176 if self.check_setscene_ignore_tasks(task):
2177 self.task_fail(task, "setscene ignore_tasks")
Brad Bishop96ff1982019-08-19 13:50:42 -04002178 return True
2179
2180 if task in self.tasks_covered:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002181 logger.debug2("Setscene covered task %s", task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002182 self.task_skip(task, "covered")
2183 return True
2184
2185 if self.rq.check_stamp_task(task, taskname, cache=self.stampcache):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002186 logger.debug2("Stamp current task %s", task)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002187
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002188 self.task_skip(task, "existing")
Andrew Geissler82c905d2020-04-13 13:39:40 -05002189 self.runq_tasksrun.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002190 return True
2191
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002192 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002193 if 'noexec' in taskdep and taskname in taskdep['noexec']:
2194 startevent = runQueueTaskStarted(task, self.stats, self.rq,
2195 noexec=True)
2196 bb.event.fire(startevent, self.cfgData)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002197 self.runq_running.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002198 self.stats.taskActive()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002199 if not (self.cooker.configuration.dry_run or self.rqdata.setscene_enforce):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002200 bb.build.make_stamp(taskname, self.rqdata.dataCaches[mc], taskfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002201 self.task_complete(task)
2202 return True
2203 else:
2204 startevent = runQueueTaskStarted(task, self.stats, self.rq)
2205 bb.event.fire(startevent, self.cfgData)
2206
2207 taskdepdata = self.build_taskdepdata(task)
2208
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002209 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
Brad Bishop19323692019-04-05 15:28:33 -04002210 taskhash = self.rqdata.get_task_hash(task)
2211 unihash = self.rqdata.get_task_unihash(task)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002212 if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not (self.cooker.configuration.dry_run or self.rqdata.setscene_enforce):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05002213 if not mc in self.rq.fakeworker:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002214 try:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05002215 self.rq.start_fakeworker(self, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002216 except OSError as exc:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002217 logger.critical("Failed to spawn fakeroot worker to run %s: %s" % (task, str(exc)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002218 self.rq.state = runQueueFailed
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002219 self.stats.taskFailed()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002220 return True
Andrew Geissler5a43b432020-06-13 10:46:56 -05002221 self.rq.fakeworker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, taskhash, unihash, False, self.cooker.collections[mc].get_file_appends(taskfn), taskdepdata, self.rqdata.setscene_enforce)) + b"</runtask>")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002222 self.rq.fakeworker[mc].process.stdin.flush()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002223 else:
Andrew Geissler5a43b432020-06-13 10:46:56 -05002224 self.rq.worker[mc].process.stdin.write(b"<runtask>" + pickle.dumps((taskfn, task, taskname, taskhash, unihash, False, self.cooker.collections[mc].get_file_appends(taskfn), taskdepdata, self.rqdata.setscene_enforce)) + b"</runtask>")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002225 self.rq.worker[mc].process.stdin.flush()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002226
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002227 self.build_stamps[task] = bb.build.stampfile(taskname, self.rqdata.dataCaches[mc], taskfn, noextra=True)
2228 self.build_stamps2.append(self.build_stamps[task])
2229 self.runq_running.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002230 self.stats.taskActive()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08002231 if self.can_start_task():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002232 return True
2233
Andrew Geissler595f6302022-01-24 19:11:47 +00002234 if self.stats.active > 0 or self.sq_live:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002235 self.rq.read_workers()
2236 return self.rq.active_fds()
2237
Brad Bishop96ff1982019-08-19 13:50:42 -04002238 # No more tasks can be run. If we have deferred setscene tasks we should run them.
2239 if self.sq_deferred:
2240 tid = self.sq_deferred.pop(list(self.sq_deferred.keys())[0])
2241 logger.warning("Runqeueue deadlocked on deferred tasks, forcing task %s" % tid)
Andrew Geissler5199d832021-09-24 16:47:35 -05002242 if tid not in self.runq_complete:
2243 self.sq_task_failoutright(tid)
Brad Bishop96ff1982019-08-19 13:50:42 -04002244 return True
2245
Andrew Geissler595f6302022-01-24 19:11:47 +00002246 if self.failed_tids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002247 self.rq.state = runQueueFailed
2248 return True
2249
2250 # Sanity Checks
Brad Bishop08902b02019-08-20 09:16:51 -04002251 err = self.summarise_scenequeue_errors()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002252 for task in self.rqdata.runtaskentries:
2253 if task not in self.runq_buildable:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002254 logger.error("Task %s never buildable!", task)
Brad Bishop08902b02019-08-20 09:16:51 -04002255 err = True
Brad Bishop96ff1982019-08-19 13:50:42 -04002256 elif task not in self.runq_running:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002257 logger.error("Task %s never ran!", task)
Brad Bishop08902b02019-08-20 09:16:51 -04002258 err = True
Brad Bishop96ff1982019-08-19 13:50:42 -04002259 elif task not in self.runq_complete:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002260 logger.error("Task %s never completed!", task)
Brad Bishop08902b02019-08-20 09:16:51 -04002261 err = True
2262
2263 if err:
2264 self.rq.state = runQueueFailed
2265 else:
2266 self.rq.state = runQueueComplete
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002267
2268 return True
2269
Brad Bishopc68388fc2019-08-26 01:33:31 -04002270 def filtermcdeps(self, task, mc, deps):
Andrew Geissler99467da2019-02-25 18:54:23 -06002271 ret = set()
Andrew Geissler99467da2019-02-25 18:54:23 -06002272 for dep in deps:
Brad Bishopc68388fc2019-08-26 01:33:31 -04002273 thismc = mc_from_tid(dep)
2274 if thismc != mc:
Andrew Geissler99467da2019-02-25 18:54:23 -06002275 continue
2276 ret.add(dep)
2277 return ret
2278
Brad Bishopa34c0302019-09-23 22:34:48 -04002279 # We filter out multiconfig dependencies from taskdepdata we pass to the tasks
Andrew Geissler99467da2019-02-25 18:54:23 -06002280 # as most code can't handle them
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002281 def build_taskdepdata(self, task):
2282 taskdepdata = {}
Brad Bishopc68388fc2019-08-26 01:33:31 -04002283 mc = mc_from_tid(task)
Brad Bishop08902b02019-08-20 09:16:51 -04002284 next = self.rqdata.runtaskentries[task].depends.copy()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002285 next.add(task)
Brad Bishopc68388fc2019-08-26 01:33:31 -04002286 next = self.filtermcdeps(task, mc, next)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002287 while next:
2288 additional = []
2289 for revdep in next:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002290 (mc, fn, taskname, taskfn) = split_tid_mcfn(revdep)
2291 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
2292 deps = self.rqdata.runtaskentries[revdep].depends
2293 provides = self.rqdata.dataCaches[mc].fn_provides[taskfn]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002294 taskhash = self.rqdata.runtaskentries[revdep].hash
Brad Bishop19323692019-04-05 15:28:33 -04002295 unihash = self.rqdata.runtaskentries[revdep].unihash
Brad Bishopc68388fc2019-08-26 01:33:31 -04002296 deps = self.filtermcdeps(task, mc, deps)
Brad Bishop19323692019-04-05 15:28:33 -04002297 taskdepdata[revdep] = [pn, taskname, fn, deps, provides, taskhash, unihash]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002298 for revdep2 in deps:
2299 if revdep2 not in taskdepdata:
2300 additional.append(revdep2)
2301 next = additional
2302
2303 #bb.note("Task %s: " % task + str(taskdepdata).replace("], ", "],\n"))
2304 return taskdepdata
2305
Brad Bishop08902b02019-08-20 09:16:51 -04002306 def update_holdofftasks(self):
Brad Bishopc68388fc2019-08-26 01:33:31 -04002307
2308 if not self.holdoff_need_update:
2309 return
2310
2311 notcovered = set(self.scenequeue_notcovered)
2312 notcovered |= self.cantskip
2313 for tid in self.scenequeue_notcovered:
2314 notcovered |= self.sqdata.sq_covered_tasks[tid]
2315 notcovered |= self.sqdata.unskippable.difference(self.rqdata.runq_setscene_tids)
2316 notcovered.intersection_update(self.tasks_scenequeue_done)
2317
2318 covered = set(self.scenequeue_covered)
2319 for tid in self.scenequeue_covered:
2320 covered |= self.sqdata.sq_covered_tasks[tid]
2321 covered.difference_update(notcovered)
2322 covered.intersection_update(self.tasks_scenequeue_done)
2323
2324 for tid in notcovered | covered:
Andrew Geissler595f6302022-01-24 19:11:47 +00002325 if not self.rqdata.runtaskentries[tid].depends:
Brad Bishopc68388fc2019-08-26 01:33:31 -04002326 self.setbuildable(tid)
2327 elif self.rqdata.runtaskentries[tid].depends.issubset(self.runq_complete):
2328 self.setbuildable(tid)
2329
2330 self.tasks_covered = covered
2331 self.tasks_notcovered = notcovered
2332
Brad Bishop08902b02019-08-20 09:16:51 -04002333 self.holdoff_tasks = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002334
Brad Bishop08902b02019-08-20 09:16:51 -04002335 for tid in self.rqdata.runq_setscene_tids:
2336 if tid not in self.scenequeue_covered and tid not in self.scenequeue_notcovered:
2337 self.holdoff_tasks.add(tid)
2338
2339 for tid in self.holdoff_tasks.copy():
2340 for dep in self.sqdata.sq_covered_tasks[tid]:
2341 if dep not in self.runq_complete:
2342 self.holdoff_tasks.add(dep)
2343
Brad Bishopc68388fc2019-08-26 01:33:31 -04002344 self.holdoff_need_update = False
2345
Brad Bishop08902b02019-08-20 09:16:51 -04002346 def process_possible_migrations(self):
2347
2348 changed = set()
Andrew Geissler82c905d2020-04-13 13:39:40 -05002349 toprocess = set()
Brad Bishop08902b02019-08-20 09:16:51 -04002350 for tid, unihash in self.updated_taskhash_queue.copy():
2351 if tid in self.runq_running and tid not in self.runq_complete:
2352 continue
2353
2354 self.updated_taskhash_queue.remove((tid, unihash))
2355
2356 if unihash != self.rqdata.runtaskentries[tid].unihash:
Andrew Geisslerc926e172021-05-07 16:11:35 -05002357 # Make sure we rehash any other tasks with the same task hash that we're deferred against.
2358 torehash = [tid]
2359 for deftid in self.sq_deferred:
2360 if self.sq_deferred[deftid] == tid:
2361 torehash.append(deftid)
2362 for hashtid in torehash:
2363 hashequiv_logger.verbose("Task %s unihash changed to %s" % (hashtid, unihash))
2364 self.rqdata.runtaskentries[hashtid].unihash = unihash
2365 bb.parse.siggen.set_unihash(hashtid, unihash)
2366 toprocess.add(hashtid)
Andrew Geissler78b72792022-06-14 06:47:25 -05002367 if torehash:
2368 # Need to save after set_unihash above
2369 bb.parse.siggen.save_unitaskhashes()
Brad Bishop08902b02019-08-20 09:16:51 -04002370
Andrew Geissler82c905d2020-04-13 13:39:40 -05002371 # Work out all tasks which depend upon these
2372 total = set()
2373 next = set()
2374 for p in toprocess:
2375 next |= self.rqdata.runtaskentries[p].revdeps
2376 while next:
2377 current = next.copy()
2378 total = total | next
2379 next = set()
2380 for ntid in current:
2381 next |= self.rqdata.runtaskentries[ntid].revdeps
2382 next.difference_update(total)
Brad Bishop08902b02019-08-20 09:16:51 -04002383
Andrew Geissler82c905d2020-04-13 13:39:40 -05002384 # Now iterate those tasks in dependency order to regenerate their taskhash/unihash
2385 next = set()
2386 for p in total:
Andrew Geissler595f6302022-01-24 19:11:47 +00002387 if not self.rqdata.runtaskentries[p].depends:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002388 next.add(p)
2389 elif self.rqdata.runtaskentries[p].depends.isdisjoint(total):
2390 next.add(p)
2391
2392 # When an item doesn't have dependencies in total, we can process it. Drop items from total when handled
2393 while next:
2394 current = next.copy()
2395 next = set()
2396 for tid in current:
Andrew Geissler595f6302022-01-24 19:11:47 +00002397 if self.rqdata.runtaskentries[p].depends and not self.rqdata.runtaskentries[tid].depends.isdisjoint(total):
Andrew Geissler82c905d2020-04-13 13:39:40 -05002398 continue
2399 orighash = self.rqdata.runtaskentries[tid].hash
Andrew Geissler5a43b432020-06-13 10:46:56 -05002400 dc = bb.parse.siggen.get_data_caches(self.rqdata.dataCaches, mc_from_tid(tid))
2401 newhash = bb.parse.siggen.get_taskhash(tid, self.rqdata.runtaskentries[tid].depends, dc)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002402 origuni = self.rqdata.runtaskentries[tid].unihash
2403 newuni = bb.parse.siggen.get_unihash(tid)
2404 # FIXME, need to check it can come from sstate at all for determinism?
2405 remapped = False
2406 if newuni == origuni:
2407 # Nothing to do, we match, skip code below
2408 remapped = True
2409 elif tid in self.scenequeue_covered or tid in self.sq_live:
2410 # Already ran this setscene task or it running. Report the new taskhash
2411 bb.parse.siggen.report_unihash_equiv(tid, newhash, origuni, newuni, self.rqdata.dataCaches)
2412 hashequiv_logger.verbose("Already covered setscene for %s so ignoring rehash (remap)" % (tid))
2413 remapped = True
2414
2415 if not remapped:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002416 #logger.debug("Task %s hash changes: %s->%s %s->%s" % (tid, orighash, newhash, origuni, newuni))
Andrew Geissler82c905d2020-04-13 13:39:40 -05002417 self.rqdata.runtaskentries[tid].hash = newhash
2418 self.rqdata.runtaskentries[tid].unihash = newuni
2419 changed.add(tid)
2420
2421 next |= self.rqdata.runtaskentries[tid].revdeps
2422 total.remove(tid)
2423 next.intersection_update(total)
Brad Bishop08902b02019-08-20 09:16:51 -04002424
2425 if changed:
2426 for mc in self.rq.worker:
2427 self.rq.worker[mc].process.stdin.write(b"<newtaskhashes>" + pickle.dumps(bb.parse.siggen.get_taskhashes()) + b"</newtaskhashes>")
2428 for mc in self.rq.fakeworker:
2429 self.rq.fakeworker[mc].process.stdin.write(b"<newtaskhashes>" + pickle.dumps(bb.parse.siggen.get_taskhashes()) + b"</newtaskhashes>")
2430
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002431 hashequiv_logger.debug(pprint.pformat("Tasks changed:\n%s" % (changed)))
Brad Bishop08902b02019-08-20 09:16:51 -04002432
2433 for tid in changed:
2434 if tid not in self.rqdata.runq_setscene_tids:
2435 continue
Brad Bishop08902b02019-08-20 09:16:51 -04002436 if tid not in self.pending_migrations:
2437 self.pending_migrations.add(tid)
2438
Andrew Geissler82c905d2020-04-13 13:39:40 -05002439 update_tasks = []
Brad Bishop08902b02019-08-20 09:16:51 -04002440 for tid in self.pending_migrations.copy():
Andrew Geissler82c905d2020-04-13 13:39:40 -05002441 if tid in self.runq_running or tid in self.sq_live:
Brad Bishop6dbb3162019-11-25 09:41:34 -05002442 # Too late, task already running, not much we can do now
2443 self.pending_migrations.remove(tid)
2444 continue
2445
Brad Bishop08902b02019-08-20 09:16:51 -04002446 valid = True
2447 # Check no tasks this covers are running
2448 for dep in self.sqdata.sq_covered_tasks[tid]:
2449 if dep in self.runq_running and dep not in self.runq_complete:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002450 hashequiv_logger.debug2("Task %s is running which blocks setscene for %s from running" % (dep, tid))
Brad Bishop08902b02019-08-20 09:16:51 -04002451 valid = False
2452 break
2453 if not valid:
2454 continue
2455
2456 self.pending_migrations.remove(tid)
Brad Bishopc68388fc2019-08-26 01:33:31 -04002457 changed = True
Brad Bishop08902b02019-08-20 09:16:51 -04002458
2459 if tid in self.tasks_scenequeue_done:
2460 self.tasks_scenequeue_done.remove(tid)
2461 for dep in self.sqdata.sq_covered_tasks[tid]:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002462 if dep in self.runq_complete and dep not in self.runq_tasksrun:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002463 bb.error("Task %s marked as completed but now needing to rerun? Halting build." % dep)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002464 self.failed_tids.append(tid)
2465 self.rq.state = runQueueCleanUp
2466 return
2467
Brad Bishop08902b02019-08-20 09:16:51 -04002468 if dep not in self.runq_complete:
2469 if dep in self.tasks_scenequeue_done and dep not in self.sqdata.unskippable:
2470 self.tasks_scenequeue_done.remove(dep)
2471
2472 if tid in self.sq_buildable:
2473 self.sq_buildable.remove(tid)
2474 if tid in self.sq_running:
2475 self.sq_running.remove(tid)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002476 harddepfail = False
2477 for t in self.sqdata.sq_harddeps:
2478 if tid in self.sqdata.sq_harddeps[t] and t in self.scenequeue_notcovered:
2479 harddepfail = True
2480 break
2481 if not harddepfail and self.sqdata.sq_revdeps[tid].issubset(self.scenequeue_covered | self.scenequeue_notcovered):
Brad Bishop08902b02019-08-20 09:16:51 -04002482 if tid not in self.sq_buildable:
2483 self.sq_buildable.add(tid)
Andrew Geissler595f6302022-01-24 19:11:47 +00002484 if not self.sqdata.sq_revdeps[tid]:
Brad Bishop08902b02019-08-20 09:16:51 -04002485 self.sq_buildable.add(tid)
2486
2487 if tid in self.sqdata.outrightfail:
2488 self.sqdata.outrightfail.remove(tid)
2489 if tid in self.scenequeue_notcovered:
2490 self.scenequeue_notcovered.remove(tid)
2491 if tid in self.scenequeue_covered:
2492 self.scenequeue_covered.remove(tid)
2493 if tid in self.scenequeue_notneeded:
2494 self.scenequeue_notneeded.remove(tid)
2495
2496 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
2497 self.sqdata.stamps[tid] = bb.build.stampfile(taskname + "_setscene", self.rqdata.dataCaches[mc], taskfn, noextra=True)
2498
2499 if tid in self.stampcache:
2500 del self.stampcache[tid]
2501
2502 if tid in self.build_stamps:
2503 del self.build_stamps[tid]
2504
Andrew Geissler82c905d2020-04-13 13:39:40 -05002505 update_tasks.append((tid, harddepfail, tid in self.sqdata.valid))
2506
2507 if update_tasks:
Brad Bishop08902b02019-08-20 09:16:51 -04002508 self.sqdone = False
Patrick Williams213cb262021-08-07 19:21:33 -05002509 for tid in [t[0] for t in update_tasks]:
2510 h = pending_hash_index(tid, self.rqdata)
2511 if h in self.sqdata.hashes and tid != self.sqdata.hashes[h]:
2512 self.sq_deferred[tid] = self.sqdata.hashes[h]
2513 bb.note("Deferring %s after %s" % (tid, self.sqdata.hashes[h]))
Andrew Geissler82c905d2020-04-13 13:39:40 -05002514 update_scenequeue_data([t[0] for t in update_tasks], self.sqdata, self.rqdata, self.rq, self.cooker, self.stampcache, self, summary=False)
2515
2516 for (tid, harddepfail, origvalid) in update_tasks:
Brad Bishop1d80a2e2019-11-15 16:35:03 -05002517 if tid in self.sqdata.valid and not origvalid:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002518 hashequiv_logger.verbose("Setscene task %s became valid" % tid)
2519 if harddepfail:
2520 self.sq_task_failoutright(tid)
Brad Bishop08902b02019-08-20 09:16:51 -04002521
2522 if changed:
Andrew Geissler5199d832021-09-24 16:47:35 -05002523 self.stats.updateCovered(len(self.scenequeue_covered), len(self.scenequeue_notcovered))
Brad Bishopc68388fc2019-08-26 01:33:31 -04002524 self.holdoff_need_update = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002525
Brad Bishop96ff1982019-08-19 13:50:42 -04002526 def scenequeue_updatecounters(self, task, fail=False):
Brad Bishop08902b02019-08-20 09:16:51 -04002527
2528 for dep in sorted(self.sqdata.sq_deps[task]):
Brad Bishop96ff1982019-08-19 13:50:42 -04002529 if fail and task in self.sqdata.sq_harddeps and dep in self.sqdata.sq_harddeps[task]:
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002530 if dep in self.scenequeue_covered or dep in self.scenequeue_notcovered:
2531 # dependency could be already processed, e.g. noexec setscene task
2532 continue
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05002533 noexec, stamppresent = check_setscene_stamps(dep, self.rqdata, self.rq, self.stampcache)
2534 if noexec or stamppresent:
2535 continue
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002536 logger.debug2("%s was unavailable and is a hard dependency of %s so skipping" % (task, dep))
Brad Bishop96ff1982019-08-19 13:50:42 -04002537 self.sq_task_failoutright(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002538 continue
Brad Bishop08902b02019-08-20 09:16:51 -04002539 if self.sqdata.sq_revdeps[dep].issubset(self.scenequeue_covered | self.scenequeue_notcovered):
2540 if dep not in self.sq_buildable:
2541 self.sq_buildable.add(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002542
Brad Bishop96ff1982019-08-19 13:50:42 -04002543 next = set([task])
2544 while next:
2545 new = set()
Brad Bishop08902b02019-08-20 09:16:51 -04002546 for t in sorted(next):
Brad Bishop96ff1982019-08-19 13:50:42 -04002547 self.tasks_scenequeue_done.add(t)
2548 # Look down the dependency chain for non-setscene things which this task depends on
2549 # and mark as 'done'
2550 for dep in self.rqdata.runtaskentries[t].depends:
2551 if dep in self.rqdata.runq_setscene_tids or dep in self.tasks_scenequeue_done:
2552 continue
2553 if self.rqdata.runtaskentries[dep].revdeps.issubset(self.tasks_scenequeue_done):
2554 new.add(dep)
Brad Bishop96ff1982019-08-19 13:50:42 -04002555 next = new
2556
Andrew Geissler5199d832021-09-24 16:47:35 -05002557 self.stats.updateCovered(len(self.scenequeue_covered), len(self.scenequeue_notcovered))
Brad Bishopc68388fc2019-08-26 01:33:31 -04002558 self.holdoff_need_update = True
Brad Bishop96ff1982019-08-19 13:50:42 -04002559
2560 def sq_task_completeoutright(self, task):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002561 """
2562 Mark a task as completed
2563 Look at the reverse dependencies and mark any task with
2564 completed dependencies as buildable
2565 """
2566
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002567 logger.debug('Found task %s which could be accelerated', task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002568 self.scenequeue_covered.add(task)
2569 self.scenequeue_updatecounters(task)
2570
Brad Bishop96ff1982019-08-19 13:50:42 -04002571 def sq_check_taskfail(self, task):
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002572 if self.rqdata.setscene_ignore_tasks is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002573 realtask = task.split('_setscene')[0]
Brad Bishop37a0e4d2017-12-04 01:01:44 -05002574 (mc, fn, taskname, taskfn) = split_tid_mcfn(realtask)
2575 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002576 if not check_setscene_enforce_ignore_tasks(pn, taskname, self.rqdata.setscene_ignore_tasks):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002577 logger.error('Task %s.%s failed' % (pn, taskname + "_setscene"))
2578 self.rq.state = runQueueCleanUp
2579
Brad Bishop96ff1982019-08-19 13:50:42 -04002580 def sq_task_complete(self, task):
Andrew Geissler5199d832021-09-24 16:47:35 -05002581 bb.event.fire(sceneQueueTaskCompleted(task, self.stats, self.rq), self.cfgData)
Brad Bishop96ff1982019-08-19 13:50:42 -04002582 self.sq_task_completeoutright(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002583
Brad Bishop96ff1982019-08-19 13:50:42 -04002584 def sq_task_fail(self, task, result):
Andrew Geissler5199d832021-09-24 16:47:35 -05002585 bb.event.fire(sceneQueueTaskFailed(task, self.stats, result, self), self.cfgData)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002586 self.scenequeue_notcovered.add(task)
2587 self.scenequeue_updatecounters(task, True)
Brad Bishop96ff1982019-08-19 13:50:42 -04002588 self.sq_check_taskfail(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002589
Brad Bishop96ff1982019-08-19 13:50:42 -04002590 def sq_task_failoutright(self, task):
2591 self.sq_running.add(task)
2592 self.sq_buildable.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002593 self.scenequeue_notcovered.add(task)
2594 self.scenequeue_updatecounters(task, True)
2595
Brad Bishop96ff1982019-08-19 13:50:42 -04002596 def sq_task_skip(self, task):
2597 self.sq_running.add(task)
2598 self.sq_buildable.add(task)
2599 self.sq_task_completeoutright(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002600
Brad Bishop96ff1982019-08-19 13:50:42 -04002601 def sq_build_taskdepdata(self, task):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002602 def getsetscenedeps(tid):
2603 deps = set()
2604 (mc, fn, taskname, _) = split_tid_mcfn(tid)
2605 realtid = tid + "_setscene"
2606 idepends = self.rqdata.taskData[mc].taskentries[realtid].idepends
2607 for (depname, idependtask) in idepends:
2608 if depname not in self.rqdata.taskData[mc].build_targets:
2609 continue
2610
2611 depfn = self.rqdata.taskData[mc].build_targets[depname][0]
2612 if depfn is None:
2613 continue
2614 deptid = depfn + ":" + idependtask.replace("_setscene", "")
2615 deps.add(deptid)
2616 return deps
2617
2618 taskdepdata = {}
2619 next = getsetscenedeps(task)
2620 next.add(task)
2621 while next:
2622 additional = []
2623 for revdep in next:
2624 (mc, fn, taskname, taskfn) = split_tid_mcfn(revdep)
2625 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
2626 deps = getsetscenedeps(revdep)
2627 provides = self.rqdata.dataCaches[mc].fn_provides[taskfn]
2628 taskhash = self.rqdata.runtaskentries[revdep].hash
Brad Bishop19323692019-04-05 15:28:33 -04002629 unihash = self.rqdata.runtaskentries[revdep].unihash
2630 taskdepdata[revdep] = [pn, taskname, fn, deps, provides, taskhash, unihash]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002631 for revdep2 in deps:
2632 if revdep2 not in taskdepdata:
2633 additional.append(revdep2)
2634 next = additional
2635
2636 #bb.note("Task %s: " % task + str(taskdepdata).replace("], ", "],\n"))
2637 return taskdepdata
2638
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002639 def check_setscene_ignore_tasks(self, tid):
2640 # Check task that is going to run against the ignore tasks list
Brad Bishop96ff1982019-08-19 13:50:42 -04002641 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
2642 # Ignore covered tasks
2643 if tid in self.tasks_covered:
2644 return False
2645 # Ignore stamped tasks
2646 if self.rq.check_stamp_task(tid, taskname, cache=self.stampcache):
2647 return False
2648 # Ignore noexec tasks
2649 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
2650 if 'noexec' in taskdep and taskname in taskdep['noexec']:
2651 return False
2652
2653 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002654 if not check_setscene_enforce_ignore_tasks(pn, taskname, self.rqdata.setscene_ignore_tasks):
Brad Bishop96ff1982019-08-19 13:50:42 -04002655 if tid in self.rqdata.runq_setscene_tids:
Andrew Geissler595f6302022-01-24 19:11:47 +00002656 msg = ['Task %s.%s attempted to execute unexpectedly and should have been setscened' % (pn, taskname)]
Brad Bishop96ff1982019-08-19 13:50:42 -04002657 else:
Andrew Geissler595f6302022-01-24 19:11:47 +00002658 msg = ['Task %s.%s attempted to execute unexpectedly' % (pn, taskname)]
Andrew Geissler82c905d2020-04-13 13:39:40 -05002659 for t in self.scenequeue_notcovered:
Andrew Geissler595f6302022-01-24 19:11:47 +00002660 msg.append("\nTask %s, unihash %s, taskhash %s" % (t, self.rqdata.runtaskentries[t].unihash, self.rqdata.runtaskentries[t].hash))
2661 msg.append('\nThis is usually due to missing setscene tasks. Those missing in this build were: %s' % pprint.pformat(self.scenequeue_notcovered))
2662 logger.error("".join(msg))
Brad Bishop96ff1982019-08-19 13:50:42 -04002663 return True
2664 return False
2665
2666class SQData(object):
2667 def __init__(self):
2668 # SceneQueue dependencies
2669 self.sq_deps = {}
2670 # SceneQueue reverse dependencies
2671 self.sq_revdeps = {}
Brad Bishop96ff1982019-08-19 13:50:42 -04002672 # Injected inter-setscene task dependencies
2673 self.sq_harddeps = {}
2674 # Cache of stamp files so duplicates can't run in parallel
2675 self.stamps = {}
2676 # Setscene tasks directly depended upon by the build
2677 self.unskippable = set()
2678 # List of setscene tasks which aren't present
2679 self.outrightfail = set()
2680 # A list of normal tasks a setscene task covers
2681 self.sq_covered_tasks = {}
2682
2683def build_scenequeue_data(sqdata, rqdata, rq, cooker, stampcache, sqrq):
2684
2685 sq_revdeps = {}
2686 sq_revdeps_squash = {}
2687 sq_collated_deps = {}
2688
2689 # We need to construct a dependency graph for the setscene functions. Intermediate
2690 # dependencies between the setscene tasks only complicate the code. This code
2691 # therefore aims to collapse the huge runqueue dependency tree into a smaller one
2692 # only containing the setscene functions.
2693
2694 rqdata.init_progress_reporter.next_stage()
2695
2696 # First process the chains up to the first setscene task.
2697 endpoints = {}
2698 for tid in rqdata.runtaskentries:
2699 sq_revdeps[tid] = copy.copy(rqdata.runtaskentries[tid].revdeps)
2700 sq_revdeps_squash[tid] = set()
Andrew Geissler595f6302022-01-24 19:11:47 +00002701 if not sq_revdeps[tid] and tid not in rqdata.runq_setscene_tids:
Brad Bishop96ff1982019-08-19 13:50:42 -04002702 #bb.warn("Added endpoint %s" % (tid))
2703 endpoints[tid] = set()
2704
2705 rqdata.init_progress_reporter.next_stage()
2706
2707 # Secondly process the chains between setscene tasks.
2708 for tid in rqdata.runq_setscene_tids:
2709 sq_collated_deps[tid] = set()
2710 #bb.warn("Added endpoint 2 %s" % (tid))
2711 for dep in rqdata.runtaskentries[tid].depends:
2712 if tid in sq_revdeps[dep]:
2713 sq_revdeps[dep].remove(tid)
2714 if dep not in endpoints:
2715 endpoints[dep] = set()
2716 #bb.warn(" Added endpoint 3 %s" % (dep))
2717 endpoints[dep].add(tid)
2718
2719 rqdata.init_progress_reporter.next_stage()
2720
2721 def process_endpoints(endpoints):
2722 newendpoints = {}
2723 for point, task in endpoints.items():
2724 tasks = set()
2725 if task:
2726 tasks |= task
2727 if sq_revdeps_squash[point]:
2728 tasks |= sq_revdeps_squash[point]
2729 if point not in rqdata.runq_setscene_tids:
2730 for t in tasks:
2731 sq_collated_deps[t].add(point)
2732 sq_revdeps_squash[point] = set()
2733 if point in rqdata.runq_setscene_tids:
2734 sq_revdeps_squash[point] = tasks
Brad Bishop96ff1982019-08-19 13:50:42 -04002735 continue
2736 for dep in rqdata.runtaskentries[point].depends:
2737 if point in sq_revdeps[dep]:
2738 sq_revdeps[dep].remove(point)
2739 if tasks:
2740 sq_revdeps_squash[dep] |= tasks
Andrew Geissler595f6302022-01-24 19:11:47 +00002741 if not sq_revdeps[dep] and dep not in rqdata.runq_setscene_tids:
Brad Bishop96ff1982019-08-19 13:50:42 -04002742 newendpoints[dep] = task
Andrew Geissler595f6302022-01-24 19:11:47 +00002743 if newendpoints:
Brad Bishop96ff1982019-08-19 13:50:42 -04002744 process_endpoints(newendpoints)
2745
2746 process_endpoints(endpoints)
2747
2748 rqdata.init_progress_reporter.next_stage()
2749
Brad Bishop08902b02019-08-20 09:16:51 -04002750 # Build a list of tasks which are "unskippable"
2751 # These are direct endpoints referenced by the build upto and including setscene tasks
Brad Bishop96ff1982019-08-19 13:50:42 -04002752 # Take the build endpoints (no revdeps) and find the sstate tasks they depend upon
2753 new = True
2754 for tid in rqdata.runtaskentries:
Andrew Geissler595f6302022-01-24 19:11:47 +00002755 if not rqdata.runtaskentries[tid].revdeps:
Brad Bishop96ff1982019-08-19 13:50:42 -04002756 sqdata.unskippable.add(tid)
Brad Bishop08902b02019-08-20 09:16:51 -04002757 sqdata.unskippable |= sqrq.cantskip
Brad Bishop96ff1982019-08-19 13:50:42 -04002758 while new:
2759 new = False
Brad Bishop08902b02019-08-20 09:16:51 -04002760 orig = sqdata.unskippable.copy()
2761 for tid in sorted(orig, reverse=True):
Brad Bishop96ff1982019-08-19 13:50:42 -04002762 if tid in rqdata.runq_setscene_tids:
2763 continue
Andrew Geissler595f6302022-01-24 19:11:47 +00002764 if not rqdata.runtaskentries[tid].depends:
Brad Bishop96ff1982019-08-19 13:50:42 -04002765 # These are tasks which have no setscene tasks in their chain, need to mark as directly buildable
Brad Bishop96ff1982019-08-19 13:50:42 -04002766 sqrq.setbuildable(tid)
Brad Bishop96ff1982019-08-19 13:50:42 -04002767 sqdata.unskippable |= rqdata.runtaskentries[tid].depends
Brad Bishop08902b02019-08-20 09:16:51 -04002768 if sqdata.unskippable != orig:
2769 new = True
2770
2771 sqrq.tasks_scenequeue_done |= sqdata.unskippable.difference(rqdata.runq_setscene_tids)
Brad Bishop96ff1982019-08-19 13:50:42 -04002772
2773 rqdata.init_progress_reporter.next_stage(len(rqdata.runtaskentries))
2774
2775 # Sanity check all dependencies could be changed to setscene task references
2776 for taskcounter, tid in enumerate(rqdata.runtaskentries):
2777 if tid in rqdata.runq_setscene_tids:
2778 pass
Andrew Geissler595f6302022-01-24 19:11:47 +00002779 elif sq_revdeps_squash[tid]:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002780 bb.msg.fatal("RunQueue", "Something went badly wrong during scenequeue generation, halting. Please report this problem.")
Brad Bishop96ff1982019-08-19 13:50:42 -04002781 else:
2782 del sq_revdeps_squash[tid]
2783 rqdata.init_progress_reporter.update(taskcounter)
2784
2785 rqdata.init_progress_reporter.next_stage()
2786
2787 # Resolve setscene inter-task dependencies
2788 # e.g. do_sometask_setscene[depends] = "targetname:do_someothertask_setscene"
2789 # Note that anything explicitly depended upon will have its reverse dependencies removed to avoid circular dependencies
2790 for tid in rqdata.runq_setscene_tids:
2791 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
2792 realtid = tid + "_setscene"
2793 idepends = rqdata.taskData[mc].taskentries[realtid].idepends
2794 sqdata.stamps[tid] = bb.build.stampfile(taskname + "_setscene", rqdata.dataCaches[mc], taskfn, noextra=True)
2795 for (depname, idependtask) in idepends:
2796
2797 if depname not in rqdata.taskData[mc].build_targets:
2798 continue
2799
2800 depfn = rqdata.taskData[mc].build_targets[depname][0]
2801 if depfn is None:
2802 continue
2803 deptid = depfn + ":" + idependtask.replace("_setscene", "")
2804 if deptid not in rqdata.runtaskentries:
2805 bb.msg.fatal("RunQueue", "Task %s depends upon non-existent task %s:%s" % (realtid, depfn, idependtask))
2806
2807 if not deptid in sqdata.sq_harddeps:
2808 sqdata.sq_harddeps[deptid] = set()
2809 sqdata.sq_harddeps[deptid].add(tid)
2810
2811 sq_revdeps_squash[tid].add(deptid)
2812 # Have to zero this to avoid circular dependencies
2813 sq_revdeps_squash[deptid] = set()
2814
2815 rqdata.init_progress_reporter.next_stage()
2816
2817 for task in sqdata.sq_harddeps:
2818 for dep in sqdata.sq_harddeps[task]:
2819 sq_revdeps_squash[dep].add(task)
2820
2821 rqdata.init_progress_reporter.next_stage()
2822
2823 #for tid in sq_revdeps_squash:
2824 # data = ""
2825 # for dep in sq_revdeps_squash[tid]:
2826 # data = data + "\n %s" % dep
2827 # bb.warn("Task %s_setscene: is %s " % (tid, data))
2828
2829 sqdata.sq_revdeps = sq_revdeps_squash
Brad Bishop96ff1982019-08-19 13:50:42 -04002830 sqdata.sq_covered_tasks = sq_collated_deps
2831
2832 # Build reverse version of revdeps to populate deps structure
2833 for tid in sqdata.sq_revdeps:
2834 sqdata.sq_deps[tid] = set()
2835 for tid in sqdata.sq_revdeps:
2836 for dep in sqdata.sq_revdeps[tid]:
2837 sqdata.sq_deps[dep].add(tid)
2838
2839 rqdata.init_progress_reporter.next_stage()
2840
Brad Bishop00e122a2019-10-05 11:10:57 -04002841 sqdata.multiconfigs = set()
Brad Bishop96ff1982019-08-19 13:50:42 -04002842 for tid in sqdata.sq_revdeps:
Brad Bishop00e122a2019-10-05 11:10:57 -04002843 sqdata.multiconfigs.add(mc_from_tid(tid))
Andrew Geissler595f6302022-01-24 19:11:47 +00002844 if not sqdata.sq_revdeps[tid]:
Brad Bishop96ff1982019-08-19 13:50:42 -04002845 sqrq.sq_buildable.add(tid)
2846
2847 rqdata.init_progress_reporter.finish()
2848
Brad Bishop00e122a2019-10-05 11:10:57 -04002849 sqdata.noexec = set()
2850 sqdata.stamppresent = set()
2851 sqdata.valid = set()
Brad Bishop96ff1982019-08-19 13:50:42 -04002852
Patrick Williams213cb262021-08-07 19:21:33 -05002853 sqdata.hashes = {}
2854 sqrq.sq_deferred = {}
2855 for mc in sorted(sqdata.multiconfigs):
2856 for tid in sorted(sqdata.sq_revdeps):
2857 if mc_from_tid(tid) != mc:
2858 continue
2859 h = pending_hash_index(tid, rqdata)
2860 if h not in sqdata.hashes:
2861 sqdata.hashes[h] = tid
2862 else:
2863 sqrq.sq_deferred[tid] = sqdata.hashes[h]
2864 bb.note("Deferring %s after %s" % (tid, sqdata.hashes[h]))
2865
Brad Bishop1d80a2e2019-11-15 16:35:03 -05002866 update_scenequeue_data(sqdata.sq_revdeps, sqdata, rqdata, rq, cooker, stampcache, sqrq, summary=True)
Brad Bishop00e122a2019-10-05 11:10:57 -04002867
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002868 # Compute a list of 'stale' sstate tasks where the current hash does not match the one
2869 # in any stamp files. Pass the list out to metadata as an event.
2870 found = {}
2871 for tid in rqdata.runq_setscene_tids:
2872 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
2873 stamps = bb.build.find_stale_stamps(taskname, rqdata.dataCaches[mc], taskfn)
2874 if stamps:
2875 if mc not in found:
2876 found[mc] = {}
2877 found[mc][tid] = stamps
2878 for mc in found:
2879 event = bb.event.StaleSetSceneTasks(found[mc])
2880 bb.event.fire(event, cooker.databuilder.mcdata[mc])
2881
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05002882def check_setscene_stamps(tid, rqdata, rq, stampcache, noexecstamp=False):
2883
2884 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
2885
2886 taskdep = rqdata.dataCaches[mc].task_deps[taskfn]
2887
2888 if 'noexec' in taskdep and taskname in taskdep['noexec']:
2889 bb.build.make_stamp(taskname + "_setscene", rqdata.dataCaches[mc], taskfn)
2890 return True, False
2891
2892 if rq.check_stamp_task(tid, taskname + "_setscene", cache=stampcache):
2893 logger.debug2('Setscene stamp current for task %s', tid)
2894 return False, True
2895
2896 if rq.check_stamp_task(tid, taskname, recurse = True, cache=stampcache):
2897 logger.debug2('Normal stamp current for task %s', tid)
2898 return False, True
2899
2900 return False, False
2901
Brad Bishop1d80a2e2019-11-15 16:35:03 -05002902def update_scenequeue_data(tids, sqdata, rqdata, rq, cooker, stampcache, sqrq, summary=True):
Brad Bishop00e122a2019-10-05 11:10:57 -04002903
2904 tocheck = set()
2905
2906 for tid in sorted(tids):
2907 if tid in sqdata.stamppresent:
2908 sqdata.stamppresent.remove(tid)
2909 if tid in sqdata.valid:
2910 sqdata.valid.remove(tid)
Andrew Geisslerc926e172021-05-07 16:11:35 -05002911 if tid in sqdata.outrightfail:
2912 sqdata.outrightfail.remove(tid)
Brad Bishop00e122a2019-10-05 11:10:57 -04002913
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05002914 noexec, stamppresent = check_setscene_stamps(tid, rqdata, rq, stampcache, noexecstamp=True)
Brad Bishop00e122a2019-10-05 11:10:57 -04002915
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05002916 if noexec:
Brad Bishop00e122a2019-10-05 11:10:57 -04002917 sqdata.noexec.add(tid)
2918 sqrq.sq_task_skip(tid)
Brad Bishop00e122a2019-10-05 11:10:57 -04002919 continue
2920
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05002921 if stamppresent:
Brad Bishop00e122a2019-10-05 11:10:57 -04002922 sqdata.stamppresent.add(tid)
2923 sqrq.sq_task_skip(tid)
2924 continue
2925
2926 tocheck.add(tid)
2927
Brad Bishop1d80a2e2019-11-15 16:35:03 -05002928 sqdata.valid |= rq.validate_hashes(tocheck, cooker.data, len(sqdata.stamppresent), False, summary=summary)
Brad Bishop00e122a2019-10-05 11:10:57 -04002929
Patrick Williams213cb262021-08-07 19:21:33 -05002930 for tid in tids:
2931 if tid in sqdata.stamppresent:
2932 continue
2933 if tid in sqdata.valid:
2934 continue
2935 if tid in sqdata.noexec:
2936 continue
2937 if tid in sqrq.scenequeue_covered:
2938 continue
2939 if tid in sqrq.scenequeue_notcovered:
2940 continue
2941 if tid in sqrq.sq_deferred:
2942 continue
2943 sqdata.outrightfail.add(tid)
Brad Bishop96ff1982019-08-19 13:50:42 -04002944
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002945class TaskFailure(Exception):
2946 """
2947 Exception raised when a task in a runqueue fails
2948 """
2949 def __init__(self, x):
2950 self.args = x
2951
2952
2953class runQueueExitWait(bb.event.Event):
2954 """
2955 Event when waiting for task processes to exit
2956 """
2957
2958 def __init__(self, remain):
2959 self.remain = remain
2960 self.message = "Waiting for %s active tasks to finish" % remain
2961 bb.event.Event.__init__(self)
2962
2963class runQueueEvent(bb.event.Event):
2964 """
2965 Base runQueue event class
2966 """
2967 def __init__(self, task, stats, rq):
2968 self.taskid = task
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002969 self.taskstring = task
2970 self.taskname = taskname_from_tid(task)
2971 self.taskfile = fn_from_tid(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002972 self.taskhash = rq.rqdata.get_task_hash(task)
2973 self.stats = stats.copy()
2974 bb.event.Event.__init__(self)
2975
2976class sceneQueueEvent(runQueueEvent):
2977 """
2978 Base sceneQueue event class
2979 """
2980 def __init__(self, task, stats, rq, noexec=False):
2981 runQueueEvent.__init__(self, task, stats, rq)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002982 self.taskstring = task + "_setscene"
2983 self.taskname = taskname_from_tid(task) + "_setscene"
2984 self.taskfile = fn_from_tid(task)
2985 self.taskhash = rq.rqdata.get_task_hash(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002986
2987class runQueueTaskStarted(runQueueEvent):
2988 """
2989 Event notifying a task was started
2990 """
2991 def __init__(self, task, stats, rq, noexec=False):
2992 runQueueEvent.__init__(self, task, stats, rq)
2993 self.noexec = noexec
2994
2995class sceneQueueTaskStarted(sceneQueueEvent):
2996 """
2997 Event notifying a setscene task was started
2998 """
2999 def __init__(self, task, stats, rq, noexec=False):
3000 sceneQueueEvent.__init__(self, task, stats, rq)
3001 self.noexec = noexec
3002
3003class runQueueTaskFailed(runQueueEvent):
3004 """
3005 Event notifying a task failed
3006 """
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003007 def __init__(self, task, stats, exitcode, rq, fakeroot_log=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003008 runQueueEvent.__init__(self, task, stats, rq)
3009 self.exitcode = exitcode
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003010 self.fakeroot_log = fakeroot_log
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003011
Brad Bishopd7bf8c12018-02-25 22:55:05 -05003012 def __str__(self):
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003013 if self.fakeroot_log:
3014 return "Task (%s) failed with exit code '%s' \nPseudo log:\n%s" % (self.taskstring, self.exitcode, self.fakeroot_log)
3015 else:
3016 return "Task (%s) failed with exit code '%s'" % (self.taskstring, self.exitcode)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05003017
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003018class sceneQueueTaskFailed(sceneQueueEvent):
3019 """
3020 Event notifying a setscene task failed
3021 """
3022 def __init__(self, task, stats, exitcode, rq):
3023 sceneQueueEvent.__init__(self, task, stats, rq)
3024 self.exitcode = exitcode
3025
Brad Bishopd7bf8c12018-02-25 22:55:05 -05003026 def __str__(self):
3027 return "Setscene task (%s) failed with exit code '%s' - real task will be run instead" % (self.taskstring, self.exitcode)
3028
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003029class sceneQueueComplete(sceneQueueEvent):
3030 """
3031 Event when all the sceneQueue tasks are complete
3032 """
3033 def __init__(self, stats, rq):
3034 self.stats = stats.copy()
3035 bb.event.Event.__init__(self)
3036
3037class runQueueTaskCompleted(runQueueEvent):
3038 """
3039 Event notifying a task completed
3040 """
3041
3042class sceneQueueTaskCompleted(sceneQueueEvent):
3043 """
3044 Event notifying a setscene task completed
3045 """
3046
3047class runQueueTaskSkipped(runQueueEvent):
3048 """
3049 Event notifying a task was skipped
3050 """
3051 def __init__(self, task, stats, rq, reason):
3052 runQueueEvent.__init__(self, task, stats, rq)
3053 self.reason = reason
3054
Brad Bishop08902b02019-08-20 09:16:51 -04003055class taskUniHashUpdate(bb.event.Event):
3056 """
3057 Base runQueue event class
3058 """
3059 def __init__(self, task, unihash):
3060 self.taskid = task
3061 self.unihash = unihash
3062 bb.event.Event.__init__(self)
3063
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003064class runQueuePipe():
3065 """
3066 Abstraction for a pipe between a worker thread and the server
3067 """
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003068 def __init__(self, pipein, pipeout, d, rq, rqexec, fakerootlogs=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003069 self.input = pipein
3070 if pipeout:
3071 pipeout.close()
3072 bb.utils.nonblockingfd(self.input)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003073 self.queue = b""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003074 self.d = d
3075 self.rq = rq
3076 self.rqexec = rqexec
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003077 self.fakerootlogs = fakerootlogs
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003078
3079 def setrunqueueexec(self, rqexec):
3080 self.rqexec = rqexec
3081
3082 def read(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003083 for workers, name in [(self.rq.worker, "Worker"), (self.rq.fakeworker, "Fakeroot")]:
3084 for worker in workers.values():
3085 worker.process.poll()
3086 if worker.process.returncode is not None and not self.rq.teardown:
3087 bb.error("%s process (%s) exited unexpectedly (%s), shutting down..." % (name, worker.process.pid, str(worker.process.returncode)))
3088 self.rq.finish_runqueue(True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003089
3090 start = len(self.queue)
3091 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003092 self.queue = self.queue + (self.input.read(102400) or b"")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003093 except (OSError, IOError) as e:
3094 if e.errno != errno.EAGAIN:
3095 raise
3096 end = len(self.queue)
3097 found = True
Andrew Geissler595f6302022-01-24 19:11:47 +00003098 while found and self.queue:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003099 found = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003100 index = self.queue.find(b"</event>")
3101 while index != -1 and self.queue.startswith(b"<event>"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003102 try:
3103 event = pickle.loads(self.queue[7:index])
Andrew Geissler475cb722020-07-10 16:00:51 -05003104 except (ValueError, pickle.UnpicklingError, AttributeError, IndexError) as e:
3105 if isinstance(e, pickle.UnpicklingError) and "truncated" in str(e):
3106 # The pickled data could contain "</event>" so search for the next occurance
3107 # unpickling again, this should be the only way an unpickle error could occur
3108 index = self.queue.find(b"</event>", index + 1)
3109 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003110 bb.msg.fatal("RunQueue", "failed load pickle '%s': '%s'" % (e, self.queue[7:index]))
3111 bb.event.fire_from_worker(event, self.d)
Brad Bishop08902b02019-08-20 09:16:51 -04003112 if isinstance(event, taskUniHashUpdate):
3113 self.rqexec.updated_taskhash_queue.append((event.taskid, event.unihash))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003114 found = True
3115 self.queue = self.queue[index+8:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003116 index = self.queue.find(b"</event>")
3117 index = self.queue.find(b"</exitcode>")
3118 while index != -1 and self.queue.startswith(b"<exitcode>"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003119 try:
3120 task, status = pickle.loads(self.queue[10:index])
Andrew Geissler475cb722020-07-10 16:00:51 -05003121 except (ValueError, pickle.UnpicklingError, AttributeError, IndexError) as e:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003122 bb.msg.fatal("RunQueue", "failed load pickle '%s': '%s'" % (e, self.queue[10:index]))
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003123 (_, _, _, taskfn) = split_tid_mcfn(task)
3124 fakerootlog = None
3125 if self.fakerootlogs and taskfn and taskfn in self.fakerootlogs:
3126 fakerootlog = self.fakerootlogs[taskfn]
3127 self.rqexec.runqueue_process_waitpid(task, status, fakerootlog=fakerootlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003128 found = True
3129 self.queue = self.queue[index+11:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003130 index = self.queue.find(b"</exitcode>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003131 return (end > start)
3132
3133 def close(self):
3134 while self.read():
3135 continue
Andrew Geissler595f6302022-01-24 19:11:47 +00003136 if self.queue:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003137 print("Warning, worker left partial message: %s" % self.queue)
3138 self.input.close()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003139
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003140def get_setscene_enforce_ignore_tasks(d, targets):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05003141 if d.getVar('BB_SETSCENE_ENFORCE') != '1':
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003142 return None
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003143 ignore_tasks = (d.getVar("BB_SETSCENE_ENFORCE_IGNORE_TASKS") or "").split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003144 outlist = []
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003145 for item in ignore_tasks[:]:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003146 if item.startswith('%:'):
Andrew Geisslerc9f78652020-09-18 14:11:35 -05003147 for (mc, target, task, fn) in targets:
3148 outlist.append(target + ':' + item.split(':')[1])
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003149 else:
3150 outlist.append(item)
3151 return outlist
3152
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003153def check_setscene_enforce_ignore_tasks(pn, taskname, ignore_tasks):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003154 import fnmatch
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003155 if ignore_tasks is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003156 item = '%s:%s' % (pn, taskname)
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003157 for ignore_tasks in ignore_tasks:
3158 if fnmatch.fnmatch(item, ignore_tasks):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003159 return True
3160 return False
3161 return True