blob: c88d7129caf5928baa41f67370ebd4d7b6083d9d [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)
Andrew Geissler517393d2023-01-13 08:55:19 -0600158 self.stamps[tid] = bb.parse.siggen.stampfile_mcfn(taskname, taskfn, extrainfo=False)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600159 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 """
Patrick Williams92b42cb2022-09-03 06:53:57 -0500171 if self.rq.max_cpu_pressure or self.rq.max_io_pressure or self.rq.max_memory_pressure:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500172 try:
Patrick Williams92b42cb2022-09-03 06:53:57 -0500173 with open("/proc/pressure/cpu") as cpu_pressure_fds, \
174 open("/proc/pressure/io") as io_pressure_fds, \
175 open("/proc/pressure/memory") as memory_pressure_fds:
176
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500177 self.prev_cpu_pressure = cpu_pressure_fds.readline().split()[4].split("=")[1]
178 self.prev_io_pressure = io_pressure_fds.readline().split()[4].split("=")[1]
Patrick Williams92b42cb2022-09-03 06:53:57 -0500179 self.prev_memory_pressure = memory_pressure_fds.readline().split()[4].split("=")[1]
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500180 self.prev_pressure_time = time.time()
181 self.check_pressure = True
182 except:
Patrick Williams92b42cb2022-09-03 06:53:57 -0500183 bb.note("The /proc/pressure files can't be read. Continuing build without monitoring pressure")
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500184 self.check_pressure = False
185 else:
186 self.check_pressure = False
187
188 def exceeds_max_pressure(self):
189 """
190 Monitor the difference in total pressure at least once per second, if
Patrick Williams92b42cb2022-09-03 06:53:57 -0500191 BB_PRESSURE_MAX_{CPU|IO|MEMORY} are set, return True if above threshold.
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500192 """
193 if self.check_pressure:
Patrick Williams92b42cb2022-09-03 06:53:57 -0500194 with open("/proc/pressure/cpu") as cpu_pressure_fds, \
195 open("/proc/pressure/io") as io_pressure_fds, \
196 open("/proc/pressure/memory") as memory_pressure_fds:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500197 # extract "total" from /proc/pressure/{cpu|io}
198 curr_cpu_pressure = cpu_pressure_fds.readline().split()[4].split("=")[1]
199 curr_io_pressure = io_pressure_fds.readline().split()[4].split("=")[1]
Patrick Williams92b42cb2022-09-03 06:53:57 -0500200 curr_memory_pressure = memory_pressure_fds.readline().split()[4].split("=")[1]
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500201 now = time.time()
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500202 tdiff = now - self.prev_pressure_time
Andrew Geissler5082cc72023-09-11 08:41:39 -0400203 psi_accumulation_interval = 1.0
204 cpu_pressure = (float(curr_cpu_pressure) - float(self.prev_cpu_pressure)) / tdiff
205 io_pressure = (float(curr_io_pressure) - float(self.prev_io_pressure)) / tdiff
206 memory_pressure = (float(curr_memory_pressure) - float(self.prev_memory_pressure)) / tdiff
207 exceeds_cpu_pressure = self.rq.max_cpu_pressure and cpu_pressure > self.rq.max_cpu_pressure
208 exceeds_io_pressure = self.rq.max_io_pressure and io_pressure > self.rq.max_io_pressure
209 exceeds_memory_pressure = self.rq.max_memory_pressure and memory_pressure > self.rq.max_memory_pressure
210
211 if tdiff > psi_accumulation_interval:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500212 self.prev_cpu_pressure = curr_cpu_pressure
213 self.prev_io_pressure = curr_io_pressure
Patrick Williams92b42cb2022-09-03 06:53:57 -0500214 self.prev_memory_pressure = curr_memory_pressure
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500215 self.prev_pressure_time = now
Andrew Geissler5082cc72023-09-11 08:41:39 -0400216
Andrew Geissler8f840682023-07-21 09:09:43 -0500217 pressure_state = (exceeds_cpu_pressure, exceeds_io_pressure, exceeds_memory_pressure)
Andrew Geissler5082cc72023-09-11 08:41:39 -0400218 pressure_values = (round(cpu_pressure,1), self.rq.max_cpu_pressure, round(io_pressure,1), self.rq.max_io_pressure, round(memory_pressure,1), self.rq.max_memory_pressure)
Andrew Geissler8f840682023-07-21 09:09:43 -0500219 if hasattr(self, "pressure_state") and pressure_state != self.pressure_state:
Andrew Geissler5082cc72023-09-11 08:41:39 -0400220 bb.note("Pressure status changed to CPU: %s, IO: %s, Mem: %s (CPU: %s/%s, IO: %s/%s, Mem: %s/%s) - using %s/%s bitbake threads" % (pressure_state + pressure_values + (len(self.rq.runq_running.difference(self.rq.runq_complete)), self.rq.number_tasks)))
Andrew Geissler8f840682023-07-21 09:09:43 -0500221 self.pressure_state = pressure_state
Patrick Williams92b42cb2022-09-03 06:53:57 -0500222 return (exceeds_cpu_pressure or exceeds_io_pressure or exceeds_memory_pressure)
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500223 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500224
225 def next_buildable_task(self):
226 """
227 Return the id of the first task we find that is buildable
228 """
Andrew Geissler82c905d2020-04-13 13:39:40 -0500229 # Once tasks are running we don't need to worry about them again
230 self.buildable.difference_update(self.rq.runq_running)
Brad Bishop08902b02019-08-20 09:16:51 -0400231 buildable = set(self.buildable)
Brad Bishop08902b02019-08-20 09:16:51 -0400232 buildable.difference_update(self.rq.holdoff_tasks)
233 buildable.intersection_update(self.rq.tasks_covered | self.rq.tasks_notcovered)
Brad Bishop96ff1982019-08-19 13:50:42 -0400234 if not buildable:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500235 return None
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800236
Patrick Williamsdb4c27e2022-08-05 08:10:29 -0500237 # Bitbake requires that at least one task be active. Only check for pressure if
238 # this is the case, otherwise the pressure limitation could result in no tasks
239 # being active and no new tasks started thereby, at times, breaking the scheduler.
240 if self.rq.stats.active and self.exceeds_max_pressure():
241 return None
242
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800243 # Filter out tasks that have a max number of threads that have been exceeded
244 skip_buildable = {}
245 for running in self.rq.runq_running.difference(self.rq.runq_complete):
246 rtaskname = taskname_from_tid(running)
247 if rtaskname not in self.skip_maxthread:
248 self.skip_maxthread[rtaskname] = self.rq.cfgData.getVarFlag(rtaskname, "number_threads")
249 if not self.skip_maxthread[rtaskname]:
250 continue
251 if rtaskname in skip_buildable:
252 skip_buildable[rtaskname] += 1
253 else:
254 skip_buildable[rtaskname] = 1
255
Brad Bishop96ff1982019-08-19 13:50:42 -0400256 if len(buildable) == 1:
Brad Bishop08902b02019-08-20 09:16:51 -0400257 tid = buildable.pop()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800258 taskname = taskname_from_tid(tid)
259 if taskname in skip_buildable and skip_buildable[taskname] >= int(self.skip_maxthread[taskname]):
260 return None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600261 stamp = self.stamps[tid]
262 if stamp not in self.rq.build_stamps.values():
263 return tid
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500264
265 if not self.rev_prio_map:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600266 self.rev_prio_map = {}
267 for tid in self.rqdata.runtaskentries:
268 self.rev_prio_map[tid] = self.prio_map.index(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500269
270 best = None
271 bestprio = None
Brad Bishop96ff1982019-08-19 13:50:42 -0400272 for tid in buildable:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800273 taskname = taskname_from_tid(tid)
274 if taskname in skip_buildable and skip_buildable[taskname] >= int(self.skip_maxthread[taskname]):
275 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600276 prio = self.rev_prio_map[tid]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500277 if bestprio is None or bestprio > prio:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600278 stamp = self.stamps[tid]
279 if stamp in self.rq.build_stamps.values():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280 continue
281 bestprio = prio
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600282 best = tid
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500283
284 return best
285
286 def next(self):
287 """
288 Return the id of the task we should build next
289 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800290 if self.rq.can_start_task():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500291 return self.next_buildable_task()
292
Brad Bishop316dfdd2018-06-25 12:45:53 -0400293 def newbuildable(self, task):
Brad Bishop08902b02019-08-20 09:16:51 -0400294 self.buildable.add(task)
295
296 def removebuildable(self, task):
297 self.buildable.remove(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500298
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500299 def describe_task(self, taskid):
300 result = 'ID %s' % taskid
301 if self.rev_prio_map:
302 result = result + (' pri %d' % self.rev_prio_map[taskid])
303 return result
304
305 def dump_prio(self, comment):
306 bb.debug(3, '%s (most important first):\n%s' %
307 (comment,
308 '\n'.join(['%d. %s' % (index + 1, self.describe_task(taskid)) for
309 index, taskid in enumerate(self.prio_map)])))
310
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500311class RunQueueSchedulerSpeed(RunQueueScheduler):
312 """
313 A scheduler optimised for speed. The priority map is sorted by task weight,
314 heavier weighted tasks (tasks needed by the most other tasks) are run first.
315 """
316 name = "speed"
317
318 def __init__(self, runqueue, rqdata):
319 """
320 The priority map is sorted by task weight.
321 """
322 RunQueueScheduler.__init__(self, runqueue, rqdata)
323
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600324 weights = {}
325 for tid in self.rqdata.runtaskentries:
326 weight = self.rqdata.runtaskentries[tid].weight
327 if not weight in weights:
328 weights[weight] = []
329 weights[weight].append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500330
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600331 self.prio_map = []
332 for weight in sorted(weights):
333 for w in weights[weight]:
334 self.prio_map.append(w)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500335
336 self.prio_map.reverse()
337
338class RunQueueSchedulerCompletion(RunQueueSchedulerSpeed):
339 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500340 A scheduler optimised to complete .bb files as quickly as possible. The
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500341 priority map is sorted by task weight, but then reordered so once a given
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500342 .bb file starts to build, it's completed as quickly as possible by
343 running all tasks related to the same .bb file one after the after.
344 This works well where disk space is at a premium and classes like OE's
345 rm_work are in force.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500346 """
347 name = "completion"
348
349 def __init__(self, runqueue, rqdata):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500350 super(RunQueueSchedulerCompletion, self).__init__(runqueue, rqdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500351
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500352 # Extract list of tasks for each recipe, with tasks sorted
353 # ascending from "must run first" (typically do_fetch) to
354 # "runs last" (do_build). The speed scheduler prioritizes
355 # tasks that must run first before the ones that run later;
356 # this is what we depend on here.
357 task_lists = {}
358 for taskid in self.prio_map:
359 fn, taskname = taskid.rsplit(':', 1)
360 task_lists.setdefault(fn, []).append(taskname)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500361
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500362 # Now unify the different task lists. The strategy is that
363 # common tasks get skipped and new ones get inserted after the
364 # preceeding common one(s) as they are found. Because task
365 # lists should differ only by their number of tasks, but not
366 # the ordering of the common tasks, this should result in a
367 # deterministic result that is a superset of the individual
368 # task ordering.
369 all_tasks = []
370 for recipe, new_tasks in task_lists.items():
371 index = 0
372 old_task = all_tasks[index] if index < len(all_tasks) else None
373 for new_task in new_tasks:
374 if old_task == new_task:
375 # Common task, skip it. This is the fast-path which
376 # avoids a full search.
377 index += 1
378 old_task = all_tasks[index] if index < len(all_tasks) else None
379 else:
380 try:
381 index = all_tasks.index(new_task)
382 # Already present, just not at the current
383 # place. We re-synchronized by changing the
384 # index so that it matches again. Now
385 # move on to the next existing task.
386 index += 1
387 old_task = all_tasks[index] if index < len(all_tasks) else None
388 except ValueError:
389 # Not present. Insert before old_task, which
390 # remains the same (but gets shifted back).
391 all_tasks.insert(index, new_task)
392 index += 1
393 bb.debug(3, 'merged task list: %s' % all_tasks)
394
395 # Now reverse the order so that tasks that finish the work on one
396 # recipe are considered more imporant (= come first). The ordering
397 # is now so that do_build is most important.
398 all_tasks.reverse()
399
400 # Group tasks of the same kind before tasks of less important
401 # kinds at the head of the queue (because earlier = lower
402 # priority number = runs earlier), while preserving the
403 # ordering by recipe. If recipe foo is more important than
404 # bar, then the goal is to work on foo's do_populate_sysroot
405 # before bar's do_populate_sysroot and on the more important
406 # tasks of foo before any of the less important tasks in any
407 # other recipe (if those other recipes are more important than
408 # foo).
409 #
410 # All of this only applies when tasks are runable. Explicit
411 # dependencies still override this ordering by priority.
412 #
413 # Here's an example why this priority re-ordering helps with
414 # minimizing disk usage. Consider a recipe foo with a higher
415 # priority than bar where foo DEPENDS on bar. Then the
416 # implicit rule (from base.bbclass) is that foo's do_configure
417 # depends on bar's do_populate_sysroot. This ensures that
418 # bar's do_populate_sysroot gets done first. Normally the
419 # tasks from foo would continue to run once that is done, and
420 # bar only gets completed and cleaned up later. By ordering
421 # bar's task that depend on bar's do_populate_sysroot before foo's
422 # do_configure, that problem gets avoided.
423 task_index = 0
424 self.dump_prio('original priorities')
425 for task in all_tasks:
426 for index in range(task_index, self.numTasks):
427 taskid = self.prio_map[index]
428 taskname = taskid.rsplit(':', 1)[1]
429 if taskname == task:
430 del self.prio_map[index]
431 self.prio_map.insert(task_index, taskid)
432 task_index += 1
433 self.dump_prio('completion priorities')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500434
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600435class RunTaskEntry(object):
436 def __init__(self):
437 self.depends = set()
438 self.revdeps = set()
439 self.hash = None
Brad Bishop19323692019-04-05 15:28:33 -0400440 self.unihash = None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600441 self.task = None
442 self.weight = 1
443
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500444class RunQueueData:
445 """
446 BitBake Run Queue implementation
447 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600448 def __init__(self, rq, cooker, cfgData, dataCaches, taskData, targets):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500449 self.cooker = cooker
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600450 self.dataCaches = dataCaches
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500451 self.taskData = taskData
452 self.targets = targets
453 self.rq = rq
454 self.warn_multi_bb = False
455
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000456 self.multi_provider_allowed = (cfgData.getVar("BB_MULTI_PROVIDER_ALLOWED") or "").split()
457 self.setscene_ignore_tasks = get_setscene_enforce_ignore_tasks(cfgData, targets)
458 self.setscene_ignore_tasks_checked = False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500459 self.setscene_enforce = (cfgData.getVar('BB_SETSCENE_ENFORCE') == "1")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600460 self.init_progress_reporter = bb.progress.DummyMultiStageProcessProgressReporter()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500461
462 self.reset()
463
464 def reset(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600465 self.runtaskentries = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500466
467 def runq_depends_names(self, ids):
468 import re
469 ret = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600470 for id in ids:
471 nam = os.path.basename(id)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500472 nam = re.sub("_[^,]*,", ",", nam)
473 ret.extend([nam])
474 return ret
475
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600476 def get_task_hash(self, tid):
477 return self.runtaskentries[tid].hash
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500478
Brad Bishop19323692019-04-05 15:28:33 -0400479 def get_task_unihash(self, tid):
480 return self.runtaskentries[tid].unihash
481
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600482 def get_user_idstring(self, tid, task_name_suffix = ""):
483 return tid + task_name_suffix
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500484
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500485 def get_short_user_idstring(self, task, task_name_suffix = ""):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500486 (mc, fn, taskname, taskfn) = split_tid_mcfn(task)
487 pn = self.dataCaches[mc].pkg_fn[taskfn]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600488 taskname = taskname_from_tid(task) + task_name_suffix
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500489 return "%s:%s" % (pn, taskname)
490
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500491 def circular_depchains_handler(self, tasks):
492 """
493 Some tasks aren't buildable, likely due to circular dependency issues.
494 Identify the circular dependencies and print them in a user readable format.
495 """
496 from copy import deepcopy
497
498 valid_chains = []
499 explored_deps = {}
500 msgs = []
501
Andrew Geissler99467da2019-02-25 18:54:23 -0600502 class TooManyLoops(Exception):
503 pass
504
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500505 def chain_reorder(chain):
506 """
507 Reorder a dependency chain so the lowest task id is first
508 """
509 lowest = 0
510 new_chain = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600511 for entry in range(len(chain)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500512 if chain[entry] < chain[lowest]:
513 lowest = entry
514 new_chain.extend(chain[lowest:])
515 new_chain.extend(chain[:lowest])
516 return new_chain
517
518 def chain_compare_equal(chain1, chain2):
519 """
520 Compare two dependency chains and see if they're the same
521 """
522 if len(chain1) != len(chain2):
523 return False
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600524 for index in range(len(chain1)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500525 if chain1[index] != chain2[index]:
526 return False
527 return True
528
529 def chain_array_contains(chain, chain_array):
530 """
531 Return True if chain_array contains chain
532 """
533 for ch in chain_array:
534 if chain_compare_equal(ch, chain):
535 return True
536 return False
537
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600538 def find_chains(tid, prev_chain):
539 prev_chain.append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500540 total_deps = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600541 total_deps.extend(self.runtaskentries[tid].revdeps)
542 for revdep in self.runtaskentries[tid].revdeps:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500543 if revdep in prev_chain:
544 idx = prev_chain.index(revdep)
545 # To prevent duplicates, reorder the chain to start with the lowest taskid
546 # and search through an array of those we've already printed
547 chain = prev_chain[idx:]
548 new_chain = chain_reorder(chain)
549 if not chain_array_contains(new_chain, valid_chains):
550 valid_chains.append(new_chain)
551 msgs.append("Dependency loop #%d found:\n" % len(valid_chains))
552 for dep in new_chain:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600553 msgs.append(" Task %s (dependent Tasks %s)\n" % (dep, self.runq_depends_names(self.runtaskentries[dep].depends)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500554 msgs.append("\n")
555 if len(valid_chains) > 10:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000556 msgs.append("Halted dependency loops search after 10 matches.\n")
Andrew Geissler99467da2019-02-25 18:54:23 -0600557 raise TooManyLoops
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500558 continue
559 scan = False
560 if revdep not in explored_deps:
561 scan = True
562 elif revdep in explored_deps[revdep]:
563 scan = True
564 else:
565 for dep in prev_chain:
566 if dep in explored_deps[revdep]:
567 scan = True
568 if scan:
569 find_chains(revdep, copy.deepcopy(prev_chain))
570 for dep in explored_deps[revdep]:
571 if dep not in total_deps:
572 total_deps.append(dep)
573
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600574 explored_deps[tid] = total_deps
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500575
Andrew Geissler99467da2019-02-25 18:54:23 -0600576 try:
577 for task in tasks:
578 find_chains(task, [])
579 except TooManyLoops:
580 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500581
582 return msgs
583
584 def calculate_task_weights(self, endpoints):
585 """
586 Calculate a number representing the "weight" of each task. Heavier weighted tasks
587 have more dependencies and hence should be executed sooner for maximum speed.
588
589 This function also sanity checks the task list finding tasks that are not
590 possible to execute due to circular dependencies.
591 """
592
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600593 numTasks = len(self.runtaskentries)
594 weight = {}
595 deps_left = {}
596 task_done = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500597
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600598 for tid in self.runtaskentries:
599 task_done[tid] = False
600 weight[tid] = 1
601 deps_left[tid] = len(self.runtaskentries[tid].revdeps)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500602
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600603 for tid in endpoints:
604 weight[tid] = 10
605 task_done[tid] = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500606
607 while True:
608 next_points = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600609 for tid in endpoints:
610 for revdep in self.runtaskentries[tid].depends:
611 weight[revdep] = weight[revdep] + weight[tid]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500612 deps_left[revdep] = deps_left[revdep] - 1
613 if deps_left[revdep] == 0:
614 next_points.append(revdep)
615 task_done[revdep] = True
616 endpoints = next_points
Andrew Geissler595f6302022-01-24 19:11:47 +0000617 if not next_points:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500618 break
619
620 # Circular dependency sanity check
621 problem_tasks = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600622 for tid in self.runtaskentries:
623 if task_done[tid] is False or deps_left[tid] != 0:
624 problem_tasks.append(tid)
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600625 logger.debug2("Task %s is not buildable", tid)
626 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 -0600627 self.runtaskentries[tid].weight = weight[tid]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500628
629 if problem_tasks:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600630 message = "%s unbuildable tasks were found.\n" % len(problem_tasks)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500631 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"
632 message = message + "Identifying dependency loops (this may take a short while)...\n"
633 logger.error(message)
634
635 msgs = self.circular_depchains_handler(problem_tasks)
636
637 message = "\n"
638 for msg in msgs:
639 message = message + msg
640 bb.msg.fatal("RunQueue", message)
641
642 return weight
643
644 def prepare(self):
645 """
646 Turn a set of taskData into a RunQueue and compute data needed
647 to optimise the execution order.
648 """
649
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600650 runq_build = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500651 recursivetasks = {}
652 recursiveitasks = {}
653 recursivetasksselfref = set()
654
655 taskData = self.taskData
656
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600657 found = False
658 for mc in self.taskData:
Andrew Geissler595f6302022-01-24 19:11:47 +0000659 if taskData[mc].taskentries:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600660 found = True
661 break
662 if not found:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500663 # Nothing to do
664 return 0
665
Andrew Geissler517393d2023-01-13 08:55:19 -0600666 bb.parse.siggen.setup_datacache(self.dataCaches)
667
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600668 self.init_progress_reporter.start()
669 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600670 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500671
672 # Step A - Work out a list of tasks to run
673 #
674 # Taskdata gives us a list of possible providers for every build and run
675 # target ordered by priority. It also gives information on each of those
676 # providers.
677 #
678 # To create the actual list of tasks to execute we fix the list of
679 # providers and then resolve the dependencies into task IDs. This
680 # process is repeated for each type of dependency (tdepends, deptask,
681 # rdeptast, recrdeptask, idepends).
682
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600683 def add_build_dependencies(depids, tasknames, depends, mc):
684 for depname in depids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500685 # Won't be in build_targets if ASSUME_PROVIDED
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600686 if depname not in taskData[mc].build_targets or not taskData[mc].build_targets[depname]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500687 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600688 depdata = taskData[mc].build_targets[depname][0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500689 if depdata is None:
690 continue
691 for taskname in tasknames:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600692 t = depdata + ":" + taskname
693 if t in taskData[mc].taskentries:
694 depends.add(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500695
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600696 def add_runtime_dependencies(depids, tasknames, depends, mc):
697 for depname in depids:
698 if depname not in taskData[mc].run_targets or not taskData[mc].run_targets[depname]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500699 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600700 depdata = taskData[mc].run_targets[depname][0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500701 if depdata is None:
702 continue
703 for taskname in tasknames:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600704 t = depdata + ":" + taskname
705 if t in taskData[mc].taskentries:
706 depends.add(t)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500707
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800708 def add_mc_dependencies(mc, tid):
709 mcdeps = taskData[mc].get_mcdepends()
710 for dep in mcdeps:
711 mcdependency = dep.split(':')
712 pn = mcdependency[3]
713 frommc = mcdependency[1]
714 mcdep = mcdependency[2]
715 deptask = mcdependency[4]
Andrew Geissler517393d2023-01-13 08:55:19 -0600716 if mcdep not in taskData:
717 bb.fatal("Multiconfig '%s' is referenced in multiconfig dependency '%s' but not enabled in BBMULTICONFIG?" % (mcdep, dep))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800718 if mc == frommc:
719 fn = taskData[mcdep].build_targets[pn][0]
720 newdep = '%s:%s' % (fn,deptask)
721 taskData[mc].taskentries[tid].tdepends.append(newdep)
722
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600723 for mc in taskData:
724 for tid in taskData[mc].taskentries:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500725
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600726 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
727 #runtid = build_tid(mc, fn, taskname)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500728
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600729 #logger.debug2("Processing %s,%s:%s", mc, fn, taskname)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600730
731 depends = set()
732 task_deps = self.dataCaches[mc].task_deps[taskfn]
733
734 self.runtaskentries[tid] = RunTaskEntry()
735
736 if fn in taskData[mc].failed_fns:
737 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500738
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800739 # We add multiconfig dependencies before processing internal task deps (tdepends)
740 if 'mcdepends' in task_deps and taskname in task_deps['mcdepends']:
741 add_mc_dependencies(mc, tid)
742
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500743 # Resolve task internal dependencies
744 #
745 # e.g. addtask before X after Y
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600746 for t in taskData[mc].taskentries[tid].tdepends:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800747 (depmc, depfn, deptaskname, _) = split_tid_mcfn(t)
748 depends.add(build_tid(depmc, depfn, deptaskname))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500749
750 # Resolve 'deptask' dependencies
751 #
752 # e.g. do_sometask[deptask] = "do_someothertask"
753 # (makes sure sometask runs after someothertask of all DEPENDS)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600754 if 'deptask' in task_deps and taskname in task_deps['deptask']:
755 tasknames = task_deps['deptask'][taskname].split()
756 add_build_dependencies(taskData[mc].depids[taskfn], tasknames, depends, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500757
758 # Resolve 'rdeptask' dependencies
759 #
760 # e.g. do_sometask[rdeptask] = "do_someothertask"
761 # (makes sure sometask runs after someothertask of all RDEPENDS)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600762 if 'rdeptask' in task_deps and taskname in task_deps['rdeptask']:
763 tasknames = task_deps['rdeptask'][taskname].split()
764 add_runtime_dependencies(taskData[mc].rdepids[taskfn], tasknames, depends, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500765
766 # Resolve inter-task dependencies
767 #
768 # e.g. do_sometask[depends] = "targetname:do_someothertask"
769 # (makes sure sometask runs after targetname's someothertask)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600770 idepends = taskData[mc].taskentries[tid].idepends
771 for (depname, idependtask) in idepends:
772 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 -0500773 # Won't be in build_targets if ASSUME_PROVIDED
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600774 depdata = taskData[mc].build_targets[depname][0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500775 if depdata is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600776 t = depdata + ":" + idependtask
777 depends.add(t)
778 if t not in taskData[mc].taskentries:
779 bb.msg.fatal("RunQueue", "Task %s in %s depends upon non-existent task %s in %s" % (taskname, fn, idependtask, depdata))
780 irdepends = taskData[mc].taskentries[tid].irdepends
781 for (depname, idependtask) in irdepends:
782 if depname in taskData[mc].run_targets:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500783 # Won't be in run_targets if ASSUME_PROVIDED
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500784 if not taskData[mc].run_targets[depname]:
785 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600786 depdata = taskData[mc].run_targets[depname][0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500787 if depdata is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600788 t = depdata + ":" + idependtask
789 depends.add(t)
790 if t not in taskData[mc].taskentries:
791 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 -0500792
793 # Resolve recursive 'recrdeptask' dependencies (Part A)
794 #
795 # e.g. do_sometask[recrdeptask] = "do_someothertask"
796 # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively)
797 # We cover the recursive part of the dependencies below
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600798 if 'recrdeptask' in task_deps and taskname in task_deps['recrdeptask']:
799 tasknames = task_deps['recrdeptask'][taskname].split()
800 recursivetasks[tid] = tasknames
801 add_build_dependencies(taskData[mc].depids[taskfn], tasknames, depends, mc)
802 add_runtime_dependencies(taskData[mc].rdepids[taskfn], tasknames, depends, mc)
803 if taskname in tasknames:
804 recursivetasksselfref.add(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500805
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600806 if 'recideptask' in task_deps and taskname in task_deps['recideptask']:
807 recursiveitasks[tid] = []
808 for t in task_deps['recideptask'][taskname].split():
809 newdep = build_tid(mc, fn, t)
810 recursiveitasks[tid].append(newdep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500811
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600812 self.runtaskentries[tid].depends = depends
Brad Bishop316dfdd2018-06-25 12:45:53 -0400813 # Remove all self references
814 self.runtaskentries[tid].depends.discard(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500815
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600816 #self.dump_data()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500817
Brad Bishop316dfdd2018-06-25 12:45:53 -0400818 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600819 bb.event.check_for_interrupts(self.cooker.data)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400820
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500821 # Resolve recursive 'recrdeptask' dependencies (Part B)
822 #
823 # e.g. do_sometask[recrdeptask] = "do_someothertask"
824 # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600825 # 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 -0600826
Brad Bishop316dfdd2018-06-25 12:45:53 -0400827 # Generating/interating recursive lists of dependencies is painful and potentially slow
828 # Precompute recursive task dependencies here by:
829 # a) create a temp list of reverse dependencies (revdeps)
830 # b) walk up the ends of the chains (when a given task no longer has dependencies i.e. len(deps) == 0)
831 # c) combine the total list of dependencies in cumulativedeps
832 # d) optimise by pre-truncating 'task' off the items in cumulativedeps (keeps items in sets lower)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500833
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500834
Brad Bishop316dfdd2018-06-25 12:45:53 -0400835 revdeps = {}
836 deps = {}
837 cumulativedeps = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600838 for tid in self.runtaskentries:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400839 deps[tid] = set(self.runtaskentries[tid].depends)
840 revdeps[tid] = set()
841 cumulativedeps[tid] = set()
842 # Generate a temp list of reverse dependencies
843 for tid in self.runtaskentries:
844 for dep in self.runtaskentries[tid].depends:
845 revdeps[dep].add(tid)
846 # Find the dependency chain endpoints
847 endpoints = set()
848 for tid in self.runtaskentries:
Andrew Geissler595f6302022-01-24 19:11:47 +0000849 if not deps[tid]:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400850 endpoints.add(tid)
851 # Iterate the chains collating dependencies
852 while endpoints:
853 next = set()
854 for tid in endpoints:
855 for dep in revdeps[tid]:
856 cumulativedeps[dep].add(fn_from_tid(tid))
857 cumulativedeps[dep].update(cumulativedeps[tid])
858 if tid in deps[dep]:
859 deps[dep].remove(tid)
Andrew Geissler595f6302022-01-24 19:11:47 +0000860 if not deps[dep]:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400861 next.add(dep)
862 endpoints = next
863 #for tid in deps:
Andrew Geissler595f6302022-01-24 19:11:47 +0000864 # if deps[tid]:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400865 # bb.warn("Sanity test failure, dependencies left for %s (%s)" % (tid, deps[tid]))
866
867 # Loop here since recrdeptasks can depend upon other recrdeptasks and we have to
868 # resolve these recursively until we aren't adding any further extra dependencies
869 extradeps = True
870 while extradeps:
871 extradeps = 0
872 for tid in recursivetasks:
873 tasknames = recursivetasks[tid]
874
875 totaldeps = set(self.runtaskentries[tid].depends)
876 if tid in recursiveitasks:
877 totaldeps.update(recursiveitasks[tid])
878 for dep in recursiveitasks[tid]:
879 if dep not in self.runtaskentries:
880 continue
881 totaldeps.update(self.runtaskentries[dep].depends)
882
883 deps = set()
884 for dep in totaldeps:
885 if dep in cumulativedeps:
886 deps.update(cumulativedeps[dep])
887
888 for t in deps:
889 for taskname in tasknames:
890 newtid = t + ":" + taskname
891 if newtid == tid:
892 continue
893 if newtid in self.runtaskentries and newtid not in self.runtaskentries[tid].depends:
894 extradeps += 1
895 self.runtaskentries[tid].depends.add(newtid)
896
897 # Handle recursive tasks which depend upon other recursive tasks
898 deps = set()
899 for dep in self.runtaskentries[tid].depends.intersection(recursivetasks):
900 deps.update(self.runtaskentries[dep].depends.difference(self.runtaskentries[tid].depends))
901 for newtid in deps:
902 for taskname in tasknames:
903 if not newtid.endswith(":" + taskname):
904 continue
905 if newtid in self.runtaskentries:
906 extradeps += 1
907 self.runtaskentries[tid].depends.add(newtid)
908
909 bb.debug(1, "Added %s recursive dependencies in this loop" % extradeps)
910
911 # Remove recrdeptask circular references so that do_a[recrdeptask] = "do_a do_b" can work
912 for tid in recursivetasksselfref:
913 self.runtaskentries[tid].depends.difference_update(recursivetasksselfref)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600914
915 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600916 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600917
918 #self.dump_data()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500919
920 # Step B - Mark all active tasks
921 #
922 # Start with the tasks we were asked to run and mark all dependencies
923 # as active too. If the task is to be 'forced', clear its stamp. Once
924 # all active tasks are marked, prune the ones we don't need.
925
926 logger.verbose("Marking Active Tasks")
927
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600928 def mark_active(tid, depth):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500929 """
930 Mark an item as active along with its depends
931 (calls itself recursively)
932 """
933
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600934 if tid in runq_build:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500935 return
936
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600937 runq_build[tid] = 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500938
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600939 depends = self.runtaskentries[tid].depends
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500940 for depend in depends:
941 mark_active(depend, depth+1)
942
Brad Bishop79641f22019-09-10 07:20:22 -0400943 def invalidate_task(tid, error_nostamp):
944 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
945 taskdep = self.dataCaches[mc].task_deps[taskfn]
946 if fn + ":" + taskname not in taskData[mc].taskentries:
947 logger.warning("Task %s does not exist, invalidating this task will have no effect" % taskname)
948 if 'nostamp' in taskdep and taskname in taskdep['nostamp']:
949 if error_nostamp:
950 bb.fatal("Task %s is marked nostamp, cannot invalidate this task" % taskname)
951 else:
952 bb.debug(1, "Task %s is marked nostamp, cannot invalidate this task" % taskname)
953 else:
954 logger.verbose("Invalidate task %s, %s", taskname, fn)
Andrew Geissler517393d2023-01-13 08:55:19 -0600955 bb.parse.siggen.invalidate_task(taskname, taskfn)
Brad Bishop79641f22019-09-10 07:20:22 -0400956
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600957 self.target_tids = []
958 for (mc, target, task, fn) in self.targets:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500959
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600960 if target not in taskData[mc].build_targets or not taskData[mc].build_targets[target]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500961 continue
962
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600963 if target in taskData[mc].failed_deps:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500964 continue
965
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500966 parents = False
967 if task.endswith('-'):
968 parents = True
969 task = task[:-1]
970
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600971 if fn in taskData[mc].failed_fns:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500972 continue
973
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600974 # fn already has mc prefix
975 tid = fn + ":" + task
976 self.target_tids.append(tid)
977 if tid not in taskData[mc].taskentries:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500978 import difflib
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600979 tasks = []
980 for x in taskData[mc].taskentries:
981 if x.startswith(fn + ":"):
982 tasks.append(taskname_from_tid(x))
983 close_matches = difflib.get_close_matches(task, tasks, cutoff=0.7)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500984 if close_matches:
985 extra = ". Close matches:\n %s" % "\n ".join(close_matches)
986 else:
987 extra = ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600988 bb.msg.fatal("RunQueue", "Task %s does not exist for target %s (%s)%s" % (task, target, tid, extra))
989
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500990 # For tasks called "XXXX-", ony run their dependencies
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500991 if parents:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600992 for i in self.runtaskentries[tid].depends:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500993 mark_active(i, 1)
994 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600995 mark_active(tid, 1)
996
997 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600998 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500999
1000 # Step C - Prune all inactive tasks
1001 #
1002 # Once all active tasks are marked, prune the ones we don't need.
1003
Brad Bishop316dfdd2018-06-25 12:45:53 -04001004 # Handle --runall
1005 if self.cooker.configuration.runall:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001006 # re-run the mark_active and then drop unused tasks from new list
Andrew Geissler595f6302022-01-24 19:11:47 +00001007 reduced_tasklist = set(self.runtaskentries.keys())
1008 for tid in list(self.runtaskentries.keys()):
1009 if tid not in runq_build:
1010 reduced_tasklist.remove(tid)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001011 runq_build = {}
Brad Bishop316dfdd2018-06-25 12:45:53 -04001012
1013 for task in self.cooker.configuration.runall:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001014 if not task.startswith("do_"):
1015 task = "do_{0}".format(task)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001016 runall_tids = set()
Andrew Geissler595f6302022-01-24 19:11:47 +00001017 for tid in reduced_tasklist:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001018 wanttid = "{0}:{1}".format(fn_from_tid(tid), task)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001019 if wanttid in self.runtaskentries:
1020 runall_tids.add(wanttid)
1021
1022 for tid in list(runall_tids):
Andrew Geissler595f6302022-01-24 19:11:47 +00001023 mark_active(tid, 1)
Brad Bishop79641f22019-09-10 07:20:22 -04001024 if self.cooker.configuration.force:
1025 invalidate_task(tid, False)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001026
Andrew Geissler595f6302022-01-24 19:11:47 +00001027 delcount = set()
1028 for tid in list(self.runtaskentries.keys()):
1029 if tid not in runq_build:
1030 delcount.add(tid)
1031 del self.runtaskentries[tid]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001032
Andrew Geissler595f6302022-01-24 19:11:47 +00001033 if self.cooker.configuration.runall:
1034 if not self.runtaskentries:
Brad Bishop316dfdd2018-06-25 12:45:53 -04001035 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)))
1036
1037 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001038 bb.event.check_for_interrupts(self.cooker.data)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001039
1040 # Handle runonly
1041 if self.cooker.configuration.runonly:
1042 # re-run the mark_active and then drop unused tasks from new list
1043 runq_build = {}
1044
1045 for task in self.cooker.configuration.runonly:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001046 if not task.startswith("do_"):
1047 task = "do_{0}".format(task)
Andrew Geissler595f6302022-01-24 19:11:47 +00001048 runonly_tids = [k for k in self.runtaskentries.keys() if taskname_from_tid(k) == task]
Brad Bishop316dfdd2018-06-25 12:45:53 -04001049
Andrew Geissler595f6302022-01-24 19:11:47 +00001050 for tid in runonly_tids:
1051 mark_active(tid, 1)
Brad Bishop79641f22019-09-10 07:20:22 -04001052 if self.cooker.configuration.force:
1053 invalidate_task(tid, False)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001054
1055 for tid in list(self.runtaskentries.keys()):
1056 if tid not in runq_build:
Andrew Geissler595f6302022-01-24 19:11:47 +00001057 delcount.add(tid)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001058 del self.runtaskentries[tid]
1059
Andrew Geissler595f6302022-01-24 19:11:47 +00001060 if not self.runtaskentries:
Brad Bishop316dfdd2018-06-25 12:45:53 -04001061 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 -05001062
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001063 #
1064 # Step D - Sanity checks and computation
1065 #
1066
1067 # Check to make sure we still have tasks to run
Andrew Geissler595f6302022-01-24 19:11:47 +00001068 if not self.runtaskentries:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001069 if not taskData[''].halt:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001070 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.")
1071 else:
1072 bb.msg.fatal("RunQueue", "No active tasks and not in --continue mode?! Please report this bug.")
1073
Brad Bishop316dfdd2018-06-25 12:45:53 -04001074 logger.verbose("Pruned %s inactive tasks, %s left", len(delcount), len(self.runtaskentries))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001075
1076 logger.verbose("Assign Weightings")
1077
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001078 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001079 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001080
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001081 # Generate a list of reverse dependencies to ease future calculations
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001082 for tid in self.runtaskentries:
1083 for dep in self.runtaskentries[tid].depends:
1084 self.runtaskentries[dep].revdeps.add(tid)
1085
1086 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001087 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001088
1089 # Identify tasks at the end of dependency chains
1090 # Error on circular dependency loops (length two)
1091 endpoints = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001092 for tid in self.runtaskentries:
1093 revdeps = self.runtaskentries[tid].revdeps
Andrew Geissler595f6302022-01-24 19:11:47 +00001094 if not revdeps:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001095 endpoints.append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001096 for dep in revdeps:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001097 if dep in self.runtaskentries[tid].depends:
1098 bb.msg.fatal("RunQueue", "Task %s has circular dependency on %s" % (tid, dep))
1099
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001100
1101 logger.verbose("Compute totals (have %s endpoint(s))", len(endpoints))
1102
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001103 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001104 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001105
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001106 # Calculate task weights
1107 # Check of higher length circular dependencies
1108 self.runq_weight = self.calculate_task_weights(endpoints)
1109
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001110 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001111 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001112
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001113 # Sanity Check - Check for multiple tasks building the same provider
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001114 for mc in self.dataCaches:
1115 prov_list = {}
1116 seen_fn = []
1117 for tid in self.runtaskentries:
1118 (tidmc, fn, taskname, taskfn) = split_tid_mcfn(tid)
1119 if taskfn in seen_fn:
1120 continue
1121 if mc != tidmc:
1122 continue
1123 seen_fn.append(taskfn)
1124 for prov in self.dataCaches[mc].fn_provides[taskfn]:
1125 if prov not in prov_list:
1126 prov_list[prov] = [taskfn]
1127 elif taskfn not in prov_list[prov]:
1128 prov_list[prov].append(taskfn)
1129 for prov in prov_list:
1130 if len(prov_list[prov]) < 2:
1131 continue
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001132 if prov in self.multi_provider_allowed:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001133 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001134 seen_pn = []
1135 # If two versions of the same PN are being built its fatal, we don't support it.
1136 for fn in prov_list[prov]:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001137 pn = self.dataCaches[mc].pkg_fn[fn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001138 if pn not in seen_pn:
1139 seen_pn.append(pn)
1140 else:
1141 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 +00001142 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 -05001143 #
1144 # Construct a list of things which uniquely depend on each provider
1145 # since this may help the user figure out which dependency is triggering this warning
1146 #
Andrew Geissler595f6302022-01-24 19:11:47 +00001147 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 -05001148 deplist = {}
1149 commondeps = None
1150 for provfn in prov_list[prov]:
1151 deps = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001152 for tid in self.runtaskentries:
1153 fn = fn_from_tid(tid)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001154 if fn != provfn:
1155 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001156 for dep in self.runtaskentries[tid].revdeps:
1157 fn = fn_from_tid(dep)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001158 if fn == provfn:
1159 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001160 deps.add(dep)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001161 if not commondeps:
1162 commondeps = set(deps)
1163 else:
1164 commondeps &= deps
1165 deplist[provfn] = deps
1166 for provfn in deplist:
Andrew Geissler595f6302022-01-24 19:11:47 +00001167 msgs.append("\n%s has unique dependees:\n %s" % (provfn, "\n ".join(deplist[provfn] - commondeps)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001168 #
1169 # Construct a list of provides and runtime providers for each recipe
1170 # (rprovides has to cover RPROVIDES, PACKAGES, PACKAGES_DYNAMIC)
1171 #
Andrew Geissler595f6302022-01-24 19:11:47 +00001172 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 -05001173 provide_results = {}
1174 rprovide_results = {}
1175 commonprovs = None
1176 commonrprovs = None
1177 for provfn in prov_list[prov]:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001178 provides = set(self.dataCaches[mc].fn_provides[provfn])
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001179 rprovides = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001180 for rprovide in self.dataCaches[mc].rproviders:
1181 if provfn in self.dataCaches[mc].rproviders[rprovide]:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001182 rprovides.add(rprovide)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001183 for package in self.dataCaches[mc].packages:
1184 if provfn in self.dataCaches[mc].packages[package]:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001185 rprovides.add(package)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001186 for package in self.dataCaches[mc].packages_dynamic:
1187 if provfn in self.dataCaches[mc].packages_dynamic[package]:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001188 rprovides.add(package)
1189 if not commonprovs:
1190 commonprovs = set(provides)
1191 else:
1192 commonprovs &= provides
1193 provide_results[provfn] = provides
1194 if not commonrprovs:
1195 commonrprovs = set(rprovides)
1196 else:
1197 commonrprovs &= rprovides
1198 rprovide_results[provfn] = rprovides
Andrew Geissler595f6302022-01-24 19:11:47 +00001199 #msgs.append("\nCommon provides:\n %s" % ("\n ".join(commonprovs)))
1200 #msgs.append("\nCommon rprovides:\n %s" % ("\n ".join(commonrprovs)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001201 for provfn in prov_list[prov]:
Andrew Geissler595f6302022-01-24 19:11:47 +00001202 msgs.append("\n%s has unique provides:\n %s" % (provfn, "\n ".join(provide_results[provfn] - commonprovs)))
1203 msgs.append("\n%s has unique rprovides:\n %s" % (provfn, "\n ".join(rprovide_results[provfn] - commonrprovs)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001204
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001205 if self.warn_multi_bb:
Andrew Geissler595f6302022-01-24 19:11:47 +00001206 logger.verbnote("".join(msgs))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001207 else:
Andrew Geissler595f6302022-01-24 19:11:47 +00001208 logger.error("".join(msgs))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001209
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001210 self.init_progress_reporter.next_stage()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001211 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001212 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001213
1214 # Iterate over the task list looking for tasks with a 'setscene' function
Andrew Geissler82c905d2020-04-13 13:39:40 -05001215 self.runq_setscene_tids = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001216 if not self.cooker.configuration.nosetscene:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001217 for tid in self.runtaskentries:
1218 (mc, fn, taskname, _) = split_tid_mcfn(tid)
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001219 setscenetid = tid + "_setscene"
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001220 if setscenetid not in taskData[mc].taskentries:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001221 continue
Andrew Geissler82c905d2020-04-13 13:39:40 -05001222 self.runq_setscene_tids.add(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001223
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001224 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001225 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001226
1227 # Invalidate task if force mode active
1228 if self.cooker.configuration.force:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001229 for tid in self.target_tids:
1230 invalidate_task(tid, False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001231
1232 # Invalidate task if invalidate mode active
1233 if self.cooker.configuration.invalidate_stamp:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001234 for tid in self.target_tids:
1235 fn = fn_from_tid(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001236 for st in self.cooker.configuration.invalidate_stamp.split(','):
1237 if not st.startswith("do_"):
1238 st = "do_%s" % st
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001239 invalidate_task(fn + ":" + st, True)
1240
1241 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001242 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001243
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001244 # Create and print to the logs a virtual/xxxx -> PN (fn) table
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001245 for mc in taskData:
1246 virtmap = taskData[mc].get_providermap(prefix="virtual/")
1247 virtpnmap = {}
1248 for v in virtmap:
1249 virtpnmap[v] = self.dataCaches[mc].pkg_fn[virtmap[v]]
1250 bb.debug(2, "%s resolved to: %s (%s)" % (v, virtpnmap[v], virtmap[v]))
1251 if hasattr(bb.parse.siggen, "tasks_resolved"):
1252 bb.parse.siggen.tasks_resolved(virtmap, virtpnmap, self.dataCaches[mc])
1253
1254 self.init_progress_reporter.next_stage()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001255 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001256
Brad Bishop00e122a2019-10-05 11:10:57 -04001257 bb.parse.siggen.set_setscene_tasks(self.runq_setscene_tids)
1258
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001259 # Iterate over the task list and call into the siggen code
1260 dealtwith = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001261 todeal = set(self.runtaskentries)
Andrew Geissler595f6302022-01-24 19:11:47 +00001262 while todeal:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001263 for tid in todeal.copy():
Andrew Geissler595f6302022-01-24 19:11:47 +00001264 if not (self.runtaskentries[tid].depends - dealtwith):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001265 dealtwith.add(tid)
1266 todeal.remove(tid)
Brad Bishop19323692019-04-05 15:28:33 -04001267 self.prepare_task_hash(tid)
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001268 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001269
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001270 bb.parse.siggen.writeout_file_checksum_cache()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001271
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001272 #self.dump_data()
1273 return len(self.runtaskentries)
1274
Brad Bishop19323692019-04-05 15:28:33 -04001275 def prepare_task_hash(self, tid):
Andrew Geissler517393d2023-01-13 08:55:19 -06001276 bb.parse.siggen.prep_taskhash(tid, self.runtaskentries[tid].depends, self.dataCaches)
1277 self.runtaskentries[tid].hash = bb.parse.siggen.get_taskhash(tid, self.runtaskentries[tid].depends, self.dataCaches)
Brad Bishop08902b02019-08-20 09:16:51 -04001278 self.runtaskentries[tid].unihash = bb.parse.siggen.get_unihash(tid)
Brad Bishop19323692019-04-05 15:28:33 -04001279
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001280 def dump_data(self):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001281 """
1282 Dump some debug information on the internal data structures
1283 """
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001284 logger.debug3("run_tasks:")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001285 for tid in self.runtaskentries:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001286 logger.debug3(" %s: %s Deps %s RevDeps %s", tid,
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001287 self.runtaskentries[tid].weight,
1288 self.runtaskentries[tid].depends,
1289 self.runtaskentries[tid].revdeps)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001290
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001291class RunQueueWorker():
1292 def __init__(self, process, pipe):
1293 self.process = process
1294 self.pipe = pipe
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001295
1296class RunQueue:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001297 def __init__(self, cooker, cfgData, dataCaches, taskData, targets):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001298
1299 self.cooker = cooker
1300 self.cfgData = cfgData
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001301 self.rqdata = RunQueueData(self, cooker, cfgData, dataCaches, taskData, targets)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001302
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001303 self.hashvalidate = cfgData.getVar("BB_HASHCHECK_FUNCTION") or None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001304 self.depvalidate = cfgData.getVar("BB_SETSCENE_DEPVALID") or None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001305
1306 self.state = runQueuePrepare
1307
1308 # For disk space monitor
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001309 # Invoked at regular time intervals via the bitbake heartbeat event
1310 # while the build is running. We generate a unique name for the handler
1311 # here, just in case that there ever is more than one RunQueue instance,
Brad Bishop96ff1982019-08-19 13:50:42 -04001312 # start the handler when reaching runQueueSceneInit, and stop it when
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001313 # done with the build.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001314 self.dm = monitordisk.diskMonitor(cfgData)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001315 self.dm_event_handler_name = '_bb_diskmonitor_' + str(id(self))
1316 self.dm_event_handler_registered = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001317 self.rqexe = None
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001318 self.worker = {}
1319 self.fakeworker = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001320
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001321 def _start_worker(self, mc, fakeroot = False, rqexec = None):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001322 logger.debug("Starting bitbake-worker")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001323 magic = "decafbad"
1324 if self.cooker.configuration.profile:
1325 magic = "decafbadbad"
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001326 fakerootlogs = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001327 if fakeroot:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001328 magic = magic + "beef"
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001329 mcdata = self.cooker.databuilder.mcdata[mc]
Brad Bishop19323692019-04-05 15:28:33 -04001330 fakerootcmd = shlex.split(mcdata.getVar("FAKEROOTCMD"))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001331 fakerootenv = (mcdata.getVar("FAKEROOTBASEENV") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001332 env = os.environ.copy()
1333 for key, value in (var.split('=') for var in fakerootenv):
1334 env[key] = value
Brad Bishop19323692019-04-05 15:28:33 -04001335 worker = subprocess.Popen(fakerootcmd + ["bitbake-worker", magic], stdout=subprocess.PIPE, stdin=subprocess.PIPE, env=env)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001336 fakerootlogs = self.rqdata.dataCaches[mc].fakerootlogs
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001337 else:
1338 worker = subprocess.Popen(["bitbake-worker", magic], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
1339 bb.utils.nonblockingfd(worker.stdout)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001340 workerpipe = runQueuePipe(worker.stdout, None, self.cfgData, self, rqexec, fakerootlogs=fakerootlogs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001341
1342 workerdata = {
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001343 "sigdata" : bb.parse.siggen.get_taskdata(),
Andrew Geissler82c905d2020-04-13 13:39:40 -05001344 "logdefaultlevel" : bb.msg.loggerDefaultLogLevel,
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001345 "build_verbose_shell" : self.cooker.configuration.build_verbose_shell,
1346 "build_verbose_stdout" : self.cooker.configuration.build_verbose_stdout,
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001347 "logdefaultdomain" : bb.msg.loggerDefaultDomains,
1348 "prhost" : self.cooker.prhost,
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001349 "buildname" : self.cfgData.getVar("BUILDNAME"),
1350 "date" : self.cfgData.getVar("DATE"),
1351 "time" : self.cfgData.getVar("TIME"),
Brad Bishopa34c0302019-09-23 22:34:48 -04001352 "hashservaddr" : self.cooker.hashservaddr,
Andrew Geissler9b4d8b02021-02-19 12:26:16 -06001353 "umask" : self.cfgData.getVar("BB_DEFAULT_UMASK"),
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001354 }
1355
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001356 worker.stdin.write(b"<cookerconfig>" + pickle.dumps(self.cooker.configuration) + b"</cookerconfig>")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001357 worker.stdin.write(b"<extraconfigdata>" + pickle.dumps(self.cooker.extraconfigdata) + b"</extraconfigdata>")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001358 worker.stdin.write(b"<workerdata>" + pickle.dumps(workerdata) + b"</workerdata>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001359 worker.stdin.flush()
1360
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001361 return RunQueueWorker(worker, workerpipe)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001362
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001363 def _teardown_worker(self, worker):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001364 if not worker:
1365 return
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001366 logger.debug("Teardown for bitbake-worker")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001367 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001368 worker.process.stdin.write(b"<quit></quit>")
1369 worker.process.stdin.flush()
1370 worker.process.stdin.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001371 except IOError:
1372 pass
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001373 while worker.process.returncode is None:
1374 worker.pipe.read()
1375 worker.process.poll()
1376 while worker.pipe.read():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001377 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001378 worker.pipe.close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001379
1380 def start_worker(self):
1381 if self.worker:
1382 self.teardown_workers()
1383 self.teardown = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001384 for mc in self.rqdata.dataCaches:
1385 self.worker[mc] = self._start_worker(mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001386
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001387 def start_fakeworker(self, rqexec, mc):
1388 if not mc in self.fakeworker:
1389 self.fakeworker[mc] = self._start_worker(mc, True, rqexec)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001390
1391 def teardown_workers(self):
1392 self.teardown = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001393 for mc in self.worker:
1394 self._teardown_worker(self.worker[mc])
1395 self.worker = {}
1396 for mc in self.fakeworker:
1397 self._teardown_worker(self.fakeworker[mc])
1398 self.fakeworker = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001399
1400 def read_workers(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001401 for mc in self.worker:
1402 self.worker[mc].pipe.read()
1403 for mc in self.fakeworker:
1404 self.fakeworker[mc].pipe.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001405
1406 def active_fds(self):
1407 fds = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001408 for mc in self.worker:
1409 fds.append(self.worker[mc].pipe.input)
1410 for mc in self.fakeworker:
1411 fds.append(self.fakeworker[mc].pipe.input)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001412 return fds
1413
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001414 def check_stamp_task(self, tid, taskname = None, recurse = False, cache = None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001415 def get_timestamp(f):
1416 try:
1417 if not os.access(f, os.F_OK):
1418 return None
1419 return os.stat(f)[stat.ST_MTIME]
1420 except:
1421 return None
1422
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001423 (mc, fn, tn, taskfn) = split_tid_mcfn(tid)
1424 if taskname is None:
1425 taskname = tn
1426
Andrew Geissler517393d2023-01-13 08:55:19 -06001427 stampfile = bb.parse.siggen.stampfile_mcfn(taskname, taskfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001428
1429 # If the stamp is missing, it's not current
1430 if not os.access(stampfile, os.F_OK):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001431 logger.debug2("Stampfile %s not available", stampfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001432 return False
1433 # If it's a 'nostamp' task, it's not current
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001434 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001435 if 'nostamp' in taskdep and taskname in taskdep['nostamp']:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001436 logger.debug2("%s.%s is nostamp\n", fn, taskname)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001437 return False
1438
Andrew Geissler517393d2023-01-13 08:55:19 -06001439 if taskname.endswith("_setscene"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001440 return True
1441
1442 if cache is None:
1443 cache = {}
1444
1445 iscurrent = True
1446 t1 = get_timestamp(stampfile)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001447 for dep in self.rqdata.runtaskentries[tid].depends:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001448 if iscurrent:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001449 (mc2, fn2, taskname2, taskfn2) = split_tid_mcfn(dep)
Andrew Geissler517393d2023-01-13 08:55:19 -06001450 stampfile2 = bb.parse.siggen.stampfile_mcfn(taskname2, taskfn2)
1451 stampfile3 = bb.parse.siggen.stampfile_mcfn(taskname2 + "_setscene", taskfn2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001452 t2 = get_timestamp(stampfile2)
1453 t3 = get_timestamp(stampfile3)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001454 if t3 and not t2:
1455 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001456 if t3 and t3 > t2:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001457 continue
Andrew Geissler595f6302022-01-24 19:11:47 +00001458 if fn == fn2:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001459 if not t2:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001460 logger.debug2('Stampfile %s does not exist', stampfile2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001461 iscurrent = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001462 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001463 if t1 < t2:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001464 logger.debug2('Stampfile %s < %s', stampfile, stampfile2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001465 iscurrent = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001466 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001467 if recurse and iscurrent:
1468 if dep in cache:
1469 iscurrent = cache[dep]
1470 if not iscurrent:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001471 logger.debug2('Stampfile for dependency %s:%s invalid (cached)' % (fn2, taskname2))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001472 else:
1473 iscurrent = self.check_stamp_task(dep, recurse=True, cache=cache)
1474 cache[dep] = iscurrent
1475 if recurse:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001476 cache[tid] = iscurrent
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001477 return iscurrent
1478
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001479 def validate_hashes(self, tocheck, data, currentcount=0, siginfo=False, summary=True):
Brad Bishop96ff1982019-08-19 13:50:42 -04001480 valid = set()
1481 if self.hashvalidate:
Brad Bishop08902b02019-08-20 09:16:51 -04001482 sq_data = {}
1483 sq_data['hash'] = {}
1484 sq_data['hashfn'] = {}
1485 sq_data['unihash'] = {}
Brad Bishop96ff1982019-08-19 13:50:42 -04001486 for tid in tocheck:
1487 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
Brad Bishop08902b02019-08-20 09:16:51 -04001488 sq_data['hash'][tid] = self.rqdata.runtaskentries[tid].hash
1489 sq_data['hashfn'][tid] = self.rqdata.dataCaches[mc].hashfn[taskfn]
1490 sq_data['unihash'][tid] = self.rqdata.runtaskentries[tid].unihash
Brad Bishop96ff1982019-08-19 13:50:42 -04001491
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001492 valid = self.validate_hash(sq_data, data, siginfo, currentcount, summary)
Brad Bishop96ff1982019-08-19 13:50:42 -04001493
1494 return valid
1495
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001496 def validate_hash(self, sq_data, d, siginfo, currentcount, summary):
1497 locs = {"sq_data" : sq_data, "d" : d, "siginfo" : siginfo, "currentcount" : currentcount, "summary" : summary}
Brad Bishop19323692019-04-05 15:28:33 -04001498
Brad Bishop08902b02019-08-20 09:16:51 -04001499 # Metadata has **kwargs so args can be added, sq_data can also gain new fields
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001500 call = self.hashvalidate + "(sq_data, d, siginfo=siginfo, currentcount=currentcount, summary=summary)"
Brad Bishop19323692019-04-05 15:28:33 -04001501
Brad Bishop19323692019-04-05 15:28:33 -04001502 return bb.utils.better_eval(call, locs)
1503
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001504 def _execute_runqueue(self):
1505 """
1506 Run the tasks in a queue prepared by rqdata.prepare()
1507 Upon failure, optionally try to recover the build using any alternate providers
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00001508 (if the halt on failure configuration option isn't set)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001509 """
1510
1511 retval = True
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001512 bb.event.check_for_interrupts(self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001513
1514 if self.state is runQueuePrepare:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001515 # NOTE: if you add, remove or significantly refactor the stages of this
1516 # process then you should recalculate the weightings here. This is quite
1517 # easy to do - just change the next line temporarily to pass debug=True as
1518 # the last parameter and you'll get a printout of the weightings as well
1519 # as a map to the lines where next_stage() was called. Of course this isn't
1520 # critical, but it helps to keep the progress reporting accurate.
1521 self.rqdata.init_progress_reporter = bb.progress.MultiStageProcessProgressReporter(self.cooker.data,
1522 "Initialising tasks",
1523 [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 -05001524 if self.rqdata.prepare() == 0:
1525 self.state = runQueueComplete
1526 else:
1527 self.state = runQueueSceneInit
Brad Bishop00e122a2019-10-05 11:10:57 -04001528 bb.parse.siggen.save_unitaskhashes()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001529
1530 if self.state is runQueueSceneInit:
Brad Bishop96ff1982019-08-19 13:50:42 -04001531 self.rqdata.init_progress_reporter.next_stage()
1532
1533 # we are ready to run, emit dependency info to any UI or class which
1534 # needs it
1535 depgraph = self.cooker.buildDependTree(self, self.rqdata.taskData)
1536 self.rqdata.init_progress_reporter.next_stage()
1537 bb.event.fire(bb.event.DepTreeGenerated(depgraph), self.cooker.data)
1538
Brad Bishope2d5b612018-11-23 10:55:50 +13001539 if not self.dm_event_handler_registered:
1540 res = bb.event.register(self.dm_event_handler_name,
Andrew Geissler517393d2023-01-13 08:55:19 -06001541 lambda x, y: self.dm.check(self) if self.state in [runQueueRunning, runQueueCleanUp] else False,
Andrew Geissler9b4d8b02021-02-19 12:26:16 -06001542 ('bb.event.HeartbeatEvent',), data=self.cfgData)
Brad Bishope2d5b612018-11-23 10:55:50 +13001543 self.dm_event_handler_registered = True
1544
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001545 dump = self.cooker.configuration.dump_signatures
1546 if dump:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001547 self.rqdata.init_progress_reporter.finish()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001548 if 'printdiff' in dump:
1549 invalidtasks = self.print_diffscenetasks()
1550 self.dump_signatures(dump)
1551 if 'printdiff' in dump:
1552 self.write_diffscenetasks(invalidtasks)
1553 self.state = runQueueComplete
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001554
Brad Bishop96ff1982019-08-19 13:50:42 -04001555 if self.state is runQueueSceneInit:
1556 self.rqdata.init_progress_reporter.next_stage()
1557 self.start_worker()
1558 self.rqdata.init_progress_reporter.next_stage()
1559 self.rqexe = RunQueueExecute(self)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001560
Brad Bishop96ff1982019-08-19 13:50:42 -04001561 # If we don't have any setscene functions, skip execution
Andrew Geissler595f6302022-01-24 19:11:47 +00001562 if not self.rqdata.runq_setscene_tids:
Brad Bishop96ff1982019-08-19 13:50:42 -04001563 logger.info('No setscene tasks')
1564 for tid in self.rqdata.runtaskentries:
Andrew Geissler595f6302022-01-24 19:11:47 +00001565 if not self.rqdata.runtaskentries[tid].depends:
Brad Bishop96ff1982019-08-19 13:50:42 -04001566 self.rqexe.setbuildable(tid)
1567 self.rqexe.tasks_notcovered.add(tid)
1568 self.rqexe.sqdone = True
1569 logger.info('Executing Tasks')
1570 self.state = runQueueRunning
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001571
1572 if self.state is runQueueRunning:
1573 retval = self.rqexe.execute()
1574
1575 if self.state is runQueueCleanUp:
1576 retval = self.rqexe.finish()
1577
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001578 build_done = self.state is runQueueComplete or self.state is runQueueFailed
1579
1580 if build_done and self.dm_event_handler_registered:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -06001581 bb.event.remove(self.dm_event_handler_name, None, data=self.cfgData)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001582 self.dm_event_handler_registered = False
1583
1584 if build_done and self.rqexe:
Brad Bishop08902b02019-08-20 09:16:51 -04001585 bb.parse.siggen.save_unitaskhashes()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001586 self.teardown_workers()
Brad Bishop96ff1982019-08-19 13:50:42 -04001587 if self.rqexe:
1588 if self.rqexe.stats.failed:
1589 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)
1590 else:
1591 # Let's avoid the word "failed" if nothing actually did
1592 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 -05001593
1594 if self.state is runQueueFailed:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001595 raise bb.runqueue.TaskFailure(self.rqexe.failed_tids)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001596
1597 if self.state is runQueueComplete:
1598 # All done
1599 return False
1600
1601 # Loop
1602 return retval
1603
1604 def execute_runqueue(self):
1605 # Catch unexpected exceptions and ensure we exit when an error occurs, not loop.
1606 try:
1607 return self._execute_runqueue()
1608 except bb.runqueue.TaskFailure:
1609 raise
1610 except SystemExit:
1611 raise
1612 except bb.BBHandledException:
1613 try:
1614 self.teardown_workers()
1615 except:
1616 pass
1617 self.state = runQueueComplete
1618 raise
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001619 except Exception as err:
1620 logger.exception("An uncaught exception occurred in runqueue")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001621 try:
1622 self.teardown_workers()
1623 except:
1624 pass
1625 self.state = runQueueComplete
1626 raise
1627
1628 def finish_runqueue(self, now = False):
1629 if not self.rqexe:
1630 self.state = runQueueComplete
1631 return
1632
1633 if now:
1634 self.rqexe.finish_now()
1635 else:
1636 self.rqexe.finish()
1637
Andrew Geissler517393d2023-01-13 08:55:19 -06001638 def _rq_dump_sigtid(self, tids):
1639 for tid in tids:
1640 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
1641 dataCaches = self.rqdata.dataCaches
1642 bb.parse.siggen.dump_sigtask(taskfn, taskname, dataCaches[mc].stamp[taskfn], True)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001643
1644 def dump_signatures(self, options):
Andrew Geissler517393d2023-01-13 08:55:19 -06001645 if bb.cooker.CookerFeatures.RECIPE_SIGGEN_INFO not in self.cooker.featureset:
1646 bb.fatal("The dump signatures functionality needs the RECIPE_SIGGEN_INFO feature enabled")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001647
Andrew Geissler517393d2023-01-13 08:55:19 -06001648 bb.note("Writing task signature files")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001649
1650 max_process = int(self.cfgData.getVar("BB_NUMBER_PARSE_THREADS") or os.cpu_count() or 1)
Andrew Geissler517393d2023-01-13 08:55:19 -06001651 def chunkify(l, n):
1652 return [l[i::n] for i in range(n)]
1653 tids = chunkify(list(self.rqdata.runtaskentries), max_process)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001654 # We cannot use the real multiprocessing.Pool easily due to some local data
1655 # that can't be pickled. This is a cheap multi-process solution.
1656 launched = []
Andrew Geissler517393d2023-01-13 08:55:19 -06001657 while tids:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001658 if len(launched) < max_process:
Andrew Geissler517393d2023-01-13 08:55:19 -06001659 p = Process(target=self._rq_dump_sigtid, args=(tids.pop(), ))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001660 p.start()
1661 launched.append(p)
1662 for q in launched:
1663 # The finished processes are joined when calling is_alive()
1664 if not q.is_alive():
1665 launched.remove(q)
1666 for p in launched:
1667 p.join()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001668
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001669 bb.parse.siggen.dump_sigs(self.rqdata.dataCaches, options)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001670
1671 return
1672
1673 def print_diffscenetasks(self):
1674
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001675 noexec = []
Brad Bishop96ff1982019-08-19 13:50:42 -04001676 tocheck = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001677
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001678 for tid in self.rqdata.runtaskentries:
1679 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
1680 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001681
1682 if 'noexec' in taskdep and taskname in taskdep['noexec']:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001683 noexec.append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001684 continue
1685
Brad Bishop96ff1982019-08-19 13:50:42 -04001686 tocheck.add(tid)
Brad Bishop19323692019-04-05 15:28:33 -04001687
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001688 valid_new = self.validate_hashes(tocheck, self.cooker.data, 0, True, summary=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001689
1690 # Tasks which are both setscene and noexec never care about dependencies
1691 # We therefore find tasks which are setscene and noexec and mark their
1692 # unique dependencies as valid.
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001693 for tid in noexec:
1694 if tid not in self.rqdata.runq_setscene_tids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001695 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001696 for dep in self.rqdata.runtaskentries[tid].depends:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001697 hasnoexecparents = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001698 for dep2 in self.rqdata.runtaskentries[dep].revdeps:
1699 if dep2 in self.rqdata.runq_setscene_tids and dep2 in noexec:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001700 continue
1701 hasnoexecparents = False
1702 break
1703 if hasnoexecparents:
1704 valid_new.add(dep)
1705
1706 invalidtasks = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001707 for tid in self.rqdata.runtaskentries:
1708 if tid not in valid_new and tid not in noexec:
1709 invalidtasks.add(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001710
1711 found = set()
1712 processed = set()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001713 for tid in invalidtasks:
1714 toprocess = set([tid])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001715 while toprocess:
1716 next = set()
1717 for t in toprocess:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001718 for dep in self.rqdata.runtaskentries[t].depends:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001719 if dep in invalidtasks:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001720 found.add(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001721 if dep not in processed:
1722 processed.add(dep)
1723 next.add(dep)
1724 toprocess = next
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001725 if tid in found:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001726 toprocess = set()
1727
1728 tasklist = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001729 for tid in invalidtasks.difference(found):
1730 tasklist.append(tid)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001731
1732 if tasklist:
1733 bb.plain("The differences between the current build and any cached tasks start at the following tasks:\n" + "\n".join(tasklist))
1734
1735 return invalidtasks.difference(found)
1736
1737 def write_diffscenetasks(self, invalidtasks):
1738
1739 # Define recursion callback
1740 def recursecb(key, hash1, hash2):
1741 hashes = [hash1, hash2]
1742 hashfiles = bb.siggen.find_siginfo(key, None, hashes, self.cfgData)
1743
1744 recout = []
1745 if len(hashfiles) == 2:
1746 out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb)
Brad Bishopc342db32019-05-15 21:57:59 -04001747 recout.extend(list(' ' + l for l in out2))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001748 else:
1749 recout.append("Unable to find matching sigdata for %s with hashes %s or %s" % (key, hash1, hash2))
1750
1751 return recout
1752
1753
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001754 for tid in invalidtasks:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001755 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
1756 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001757 h = self.rqdata.runtaskentries[tid].hash
Patrick Williams03907ee2022-05-01 06:28:52 -05001758 matches = bb.siggen.find_siginfo(pn, taskname, [], self.cooker.databuilder.mcdata[mc])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001759 match = None
1760 for m in matches:
1761 if h in m:
1762 match = m
1763 if match is None:
1764 bb.fatal("Can't find a task we're supposed to have written out? (hash: %s)?" % h)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001765 matches = {k : v for k, v in iter(matches.items()) if h not in k}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001766 if matches:
1767 latestmatch = sorted(matches.keys(), key=lambda f: matches[f])[-1]
Brad Bishop19323692019-04-05 15:28:33 -04001768 prevh = __find_sha256__.search(latestmatch).group(0)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001769 output = bb.siggen.compare_sigfiles(latestmatch, match, recursecb)
1770 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))
1771
Brad Bishop96ff1982019-08-19 13:50:42 -04001772
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001773class RunQueueExecute:
1774
1775 def __init__(self, rq):
1776 self.rq = rq
1777 self.cooker = rq.cooker
1778 self.cfgData = rq.cfgData
1779 self.rqdata = rq.rqdata
1780
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001781 self.number_tasks = int(self.cfgData.getVar("BB_NUMBER_THREADS") or 1)
1782 self.scheduler = self.cfgData.getVar("BB_SCHEDULER") or "speed"
Patrick Williamsdb4c27e2022-08-05 08:10:29 -05001783 self.max_cpu_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_CPU")
1784 self.max_io_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_IO")
Patrick Williams92b42cb2022-09-03 06:53:57 -05001785 self.max_memory_pressure = self.cfgData.getVar("BB_PRESSURE_MAX_MEMORY")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001786
Brad Bishop96ff1982019-08-19 13:50:42 -04001787 self.sq_buildable = set()
1788 self.sq_running = set()
1789 self.sq_live = set()
1790
Brad Bishop08902b02019-08-20 09:16:51 -04001791 self.updated_taskhash_queue = []
1792 self.pending_migrations = set()
1793
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001794 self.runq_buildable = set()
1795 self.runq_running = set()
1796 self.runq_complete = set()
Andrew Geissler82c905d2020-04-13 13:39:40 -05001797 self.runq_tasksrun = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001798
1799 self.build_stamps = {}
1800 self.build_stamps2 = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001801 self.failed_tids = []
Brad Bishop96ff1982019-08-19 13:50:42 -04001802 self.sq_deferred = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001803
1804 self.stampcache = {}
1805
Brad Bishop08902b02019-08-20 09:16:51 -04001806 self.holdoff_tasks = set()
Brad Bishopc68388fc2019-08-26 01:33:31 -04001807 self.holdoff_need_update = True
Brad Bishop96ff1982019-08-19 13:50:42 -04001808 self.sqdone = False
1809
Andrew Geissler5199d832021-09-24 16:47:35 -05001810 self.stats = RunQueueStats(len(self.rqdata.runtaskentries), len(self.rqdata.runq_setscene_tids))
Brad Bishop96ff1982019-08-19 13:50:42 -04001811
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001812 for mc in rq.worker:
1813 rq.worker[mc].pipe.setrunqueueexec(self)
1814 for mc in rq.fakeworker:
1815 rq.fakeworker[mc].pipe.setrunqueueexec(self)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001816
1817 if self.number_tasks <= 0:
1818 bb.fatal("Invalid BB_NUMBER_THREADS %s" % self.number_tasks)
1819
Patrick Williamsdb4c27e2022-08-05 08:10:29 -05001820 lower_limit = 1.0
1821 upper_limit = 1000000.0
1822 if self.max_cpu_pressure:
1823 self.max_cpu_pressure = float(self.max_cpu_pressure)
1824 if self.max_cpu_pressure < lower_limit:
1825 bb.fatal("Invalid BB_PRESSURE_MAX_CPU %s, minimum value is %s." % (self.max_cpu_pressure, lower_limit))
1826 if self.max_cpu_pressure > upper_limit:
1827 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))
1828
1829 if self.max_io_pressure:
1830 self.max_io_pressure = float(self.max_io_pressure)
1831 if self.max_io_pressure < lower_limit:
1832 bb.fatal("Invalid BB_PRESSURE_MAX_IO %s, minimum value is %s." % (self.max_io_pressure, lower_limit))
1833 if self.max_io_pressure > upper_limit:
1834 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))
1835
Patrick Williams92b42cb2022-09-03 06:53:57 -05001836 if self.max_memory_pressure:
1837 self.max_memory_pressure = float(self.max_memory_pressure)
1838 if self.max_memory_pressure < lower_limit:
1839 bb.fatal("Invalid BB_PRESSURE_MAX_MEMORY %s, minimum value is %s." % (self.max_memory_pressure, lower_limit))
1840 if self.max_memory_pressure > upper_limit:
1841 bb.warn("Your build will be largely unregulated since BB_PRESSURE_MAX_MEMORY is set to %s. It is very unlikely that such high pressure will be experienced." % (self.max_io_pressure))
1842
Brad Bishop96ff1982019-08-19 13:50:42 -04001843 # List of setscene tasks which we've covered
1844 self.scenequeue_covered = set()
1845 # List of tasks which are covered (including setscene ones)
1846 self.tasks_covered = set()
1847 self.tasks_scenequeue_done = set()
1848 self.scenequeue_notcovered = set()
1849 self.tasks_notcovered = set()
1850 self.scenequeue_notneeded = set()
1851
Brad Bishop08902b02019-08-20 09:16:51 -04001852 # We can't skip specified target tasks which aren't setscene tasks
1853 self.cantskip = set(self.rqdata.target_tids)
1854 self.cantskip.difference_update(self.rqdata.runq_setscene_tids)
1855 self.cantskip.intersection_update(self.rqdata.runtaskentries)
Brad Bishop96ff1982019-08-19 13:50:42 -04001856
1857 schedulers = self.get_schedulers()
1858 for scheduler in schedulers:
1859 if self.scheduler == scheduler.name:
1860 self.sched = scheduler(self, self.rqdata)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001861 logger.debug("Using runqueue scheduler '%s'", scheduler.name)
Brad Bishop96ff1982019-08-19 13:50:42 -04001862 break
1863 else:
1864 bb.fatal("Invalid scheduler '%s'. Available schedulers: %s" %
1865 (self.scheduler, ", ".join(obj.name for obj in schedulers)))
1866
Andrew Geissler595f6302022-01-24 19:11:47 +00001867 #if self.rqdata.runq_setscene_tids:
Brad Bishop08902b02019-08-20 09:16:51 -04001868 self.sqdata = SQData()
1869 build_scenequeue_data(self.sqdata, self.rqdata, self.rq, self.cooker, self.stampcache, self)
Brad Bishop96ff1982019-08-19 13:50:42 -04001870
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001871 def runqueue_process_waitpid(self, task, status, fakerootlog=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001872
1873 # self.build_stamps[pid] may not exist when use shared work directory.
1874 if task in self.build_stamps:
1875 self.build_stamps2.remove(self.build_stamps[task])
1876 del self.build_stamps[task]
1877
Brad Bishop96ff1982019-08-19 13:50:42 -04001878 if task in self.sq_live:
1879 if status != 0:
1880 self.sq_task_fail(task, status)
1881 else:
1882 self.sq_task_complete(task)
1883 self.sq_live.remove(task)
Andrew Geissler5199d832021-09-24 16:47:35 -05001884 self.stats.updateActiveSetscene(len(self.sq_live))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001885 else:
Brad Bishop96ff1982019-08-19 13:50:42 -04001886 if status != 0:
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001887 self.task_fail(task, status, fakerootlog=fakerootlog)
Brad Bishop96ff1982019-08-19 13:50:42 -04001888 else:
1889 self.task_complete(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001890 return True
1891
1892 def finish_now(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001893 for mc in self.rq.worker:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001894 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001895 self.rq.worker[mc].process.stdin.write(b"<finishnow></finishnow>")
1896 self.rq.worker[mc].process.stdin.flush()
1897 except IOError:
1898 # worker must have died?
1899 pass
1900 for mc in self.rq.fakeworker:
1901 try:
1902 self.rq.fakeworker[mc].process.stdin.write(b"<finishnow></finishnow>")
1903 self.rq.fakeworker[mc].process.stdin.flush()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001904 except IOError:
1905 # worker must have died?
1906 pass
1907
Andrew Geissler595f6302022-01-24 19:11:47 +00001908 if self.failed_tids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001909 self.rq.state = runQueueFailed
1910 return
1911
1912 self.rq.state = runQueueComplete
1913 return
1914
1915 def finish(self):
1916 self.rq.state = runQueueCleanUp
1917
Andrew Geissler5199d832021-09-24 16:47:35 -05001918 active = self.stats.active + len(self.sq_live)
Brad Bishop96ff1982019-08-19 13:50:42 -04001919 if active > 0:
1920 bb.event.fire(runQueueExitWait(active), self.cfgData)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001921 self.rq.read_workers()
1922 return self.rq.active_fds()
1923
Andrew Geissler595f6302022-01-24 19:11:47 +00001924 if self.failed_tids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001925 self.rq.state = runQueueFailed
1926 return True
1927
1928 self.rq.state = runQueueComplete
1929 return True
1930
Brad Bishop96ff1982019-08-19 13:50:42 -04001931 # Used by setscene only
1932 def check_dependencies(self, task, taskdeps):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001933 if not self.rq.depvalidate:
1934 return False
1935
Brad Bishop08902b02019-08-20 09:16:51 -04001936 # Must not edit parent data
1937 taskdeps = set(taskdeps)
1938
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001939 taskdata = {}
1940 taskdeps.add(task)
1941 for dep in taskdeps:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001942 (mc, fn, taskname, taskfn) = split_tid_mcfn(dep)
1943 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001944 taskdata[dep] = [pn, taskname, fn]
1945 call = self.rq.depvalidate + "(task, taskdata, notneeded, d)"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001946 locs = { "task" : task, "taskdata" : taskdata, "notneeded" : self.scenequeue_notneeded, "d" : self.cooker.data }
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001947 valid = bb.utils.better_eval(call, locs)
1948 return valid
1949
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001950 def can_start_task(self):
Andrew Geissler5199d832021-09-24 16:47:35 -05001951 active = self.stats.active + len(self.sq_live)
Brad Bishop96ff1982019-08-19 13:50:42 -04001952 can_start = active < self.number_tasks
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001953 return can_start
1954
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001955 def get_schedulers(self):
1956 schedulers = set(obj for obj in globals().values()
1957 if type(obj) is type and
1958 issubclass(obj, RunQueueScheduler))
1959
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001960 user_schedulers = self.cfgData.getVar("BB_SCHEDULERS")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001961 if user_schedulers:
1962 for sched in user_schedulers.split():
1963 if not "." in sched:
1964 bb.note("Ignoring scheduler '%s' from BB_SCHEDULERS: not an import" % sched)
1965 continue
1966
1967 modname, name = sched.rsplit(".", 1)
1968 try:
1969 module = __import__(modname, fromlist=(name,))
1970 except ImportError as exc:
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001971 bb.fatal("Unable to import scheduler '%s' from '%s': %s" % (name, modname, exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001972 else:
1973 schedulers.add(getattr(module, name))
1974 return schedulers
1975
1976 def setbuildable(self, task):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001977 self.runq_buildable.add(task)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001978 self.sched.newbuildable(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001979
1980 def task_completeoutright(self, task):
1981 """
1982 Mark a task as completed
1983 Look at the reverse dependencies and mark any task with
1984 completed dependencies as buildable
1985 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001986 self.runq_complete.add(task)
1987 for revdep in self.rqdata.runtaskentries[task].revdeps:
1988 if revdep in self.runq_running:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001989 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001990 if revdep in self.runq_buildable:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001991 continue
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001992 alldeps = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001993 for dep in self.rqdata.runtaskentries[revdep].depends:
1994 if dep not in self.runq_complete:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001995 alldeps = False
1996 break
1997 if alldeps:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001998 self.setbuildable(revdep)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001999 logger.debug("Marking task %s as buildable", revdep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002000
Andrew Geissler8f840682023-07-21 09:09:43 -05002001 found = None
2002 for t in sorted(self.sq_deferred.copy()):
Andrew Geissler5199d832021-09-24 16:47:35 -05002003 if self.sq_deferred[t] == task:
Andrew Geissler8f840682023-07-21 09:09:43 -05002004 # Allow the next deferred task to run. Any other deferred tasks should be deferred after that task.
2005 # We shouldn't allow all to run at once as it is prone to races.
2006 if not found:
2007 bb.debug(1, "Deferred task %s now buildable" % t)
2008 del self.sq_deferred[t]
2009 update_scenequeue_data([t], self.sqdata, self.rqdata, self.rq, self.cooker, self.stampcache, self, summary=False)
2010 found = t
2011 else:
2012 bb.debug(1, "Deferring %s after %s" % (t, found))
2013 self.sq_deferred[t] = found
Andrew Geissler5199d832021-09-24 16:47:35 -05002014
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002015 def task_complete(self, task):
2016 self.stats.taskCompleted()
2017 bb.event.fire(runQueueTaskCompleted(task, self.stats, self.rq), self.cfgData)
2018 self.task_completeoutright(task)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002019 self.runq_tasksrun.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002020
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002021 def task_fail(self, task, exitcode, fakerootlog=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002022 """
2023 Called when a task has failed
2024 Updates the state engine with the failure
2025 """
2026 self.stats.taskFailed()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002027 self.failed_tids.append(task)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002028
Andrew Geissler595f6302022-01-24 19:11:47 +00002029 fakeroot_log = []
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002030 if fakerootlog and os.path.exists(fakerootlog):
2031 with open(fakerootlog) as fakeroot_log_file:
2032 fakeroot_failed = False
2033 for line in reversed(fakeroot_log_file.readlines()):
2034 for fakeroot_error in ['mismatch', 'error', 'fatal']:
2035 if fakeroot_error in line.lower():
2036 fakeroot_failed = True
2037 if 'doing new pid setup and server start' in line:
2038 break
Andrew Geissler595f6302022-01-24 19:11:47 +00002039 fakeroot_log.append(line)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002040
2041 if not fakeroot_failed:
Andrew Geissler595f6302022-01-24 19:11:47 +00002042 fakeroot_log = []
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002043
Andrew Geissler595f6302022-01-24 19:11:47 +00002044 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 -05002045
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002046 if self.rqdata.taskData[''].halt:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002047 self.rq.state = runQueueCleanUp
2048
2049 def task_skip(self, task, reason):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002050 self.runq_running.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002051 self.setbuildable(task)
2052 bb.event.fire(runQueueTaskSkipped(task, self.stats, self.rq, reason), self.cfgData)
2053 self.task_completeoutright(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002054 self.stats.taskSkipped()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08002055 self.stats.taskCompleted()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002056
Brad Bishop08902b02019-08-20 09:16:51 -04002057 def summarise_scenequeue_errors(self):
2058 err = False
2059 if not self.sqdone:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002060 logger.debug('We could skip tasks %s', "\n".join(sorted(self.scenequeue_covered)))
Andrew Geissler5199d832021-09-24 16:47:35 -05002061 completeevent = sceneQueueComplete(self.stats, self.rq)
Brad Bishop08902b02019-08-20 09:16:51 -04002062 bb.event.fire(completeevent, self.cfgData)
2063 if self.sq_deferred:
2064 logger.error("Scenequeue had deferred entries: %s" % pprint.pformat(self.sq_deferred))
2065 err = True
2066 if self.updated_taskhash_queue:
2067 logger.error("Scenequeue had unprocessed changed taskhash entries: %s" % pprint.pformat(self.updated_taskhash_queue))
2068 err = True
2069 if self.holdoff_tasks:
2070 logger.error("Scenequeue had holdoff tasks: %s" % pprint.pformat(self.holdoff_tasks))
2071 err = True
2072
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002073 for tid in self.scenequeue_covered.intersection(self.scenequeue_notcovered):
2074 # No task should end up in both covered and uncovered, that is a bug.
2075 logger.error("Setscene task %s in both covered and notcovered." % tid)
2076
Brad Bishop08902b02019-08-20 09:16:51 -04002077 for tid in self.rqdata.runq_setscene_tids:
2078 if tid not in self.scenequeue_covered and tid not in self.scenequeue_notcovered:
2079 err = True
2080 logger.error("Setscene Task %s was never marked as covered or not covered" % tid)
2081 if tid not in self.sq_buildable:
2082 err = True
2083 logger.error("Setscene Task %s was never marked as buildable" % tid)
2084 if tid not in self.sq_running:
2085 err = True
2086 logger.error("Setscene Task %s was never marked as running" % tid)
2087
2088 for x in self.rqdata.runtaskentries:
2089 if x not in self.tasks_covered and x not in self.tasks_notcovered:
2090 logger.error("Task %s was never moved from the setscene queue" % x)
2091 err = True
2092 if x not in self.tasks_scenequeue_done:
2093 logger.error("Task %s was never processed by the setscene code" % x)
2094 err = True
Andrew Geissler595f6302022-01-24 19:11:47 +00002095 if not self.rqdata.runtaskentries[x].depends and x not in self.runq_buildable:
Brad Bishop08902b02019-08-20 09:16:51 -04002096 logger.error("Task %s was never marked as buildable by the setscene code" % x)
2097 err = True
2098 return err
2099
2100
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002101 def execute(self):
2102 """
Brad Bishop96ff1982019-08-19 13:50:42 -04002103 Run the tasks in a queue prepared by prepare_runqueue
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002104 """
2105
2106 self.rq.read_workers()
Andrew Geissler82c905d2020-04-13 13:39:40 -05002107 if self.updated_taskhash_queue or self.pending_migrations:
2108 self.process_possible_migrations()
2109
2110 if not hasattr(self, "sorted_setscene_tids"):
2111 # Don't want to sort this set every execution
2112 self.sorted_setscene_tids = sorted(self.rqdata.runq_setscene_tids)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002113
Brad Bishop96ff1982019-08-19 13:50:42 -04002114 task = None
2115 if not self.sqdone and self.can_start_task():
2116 # Find the next setscene to run
Andrew Geissler82c905d2020-04-13 13:39:40 -05002117 for nexttask in self.sorted_setscene_tids:
Brad Bishop96ff1982019-08-19 13:50:42 -04002118 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 +00002119 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 -04002120 if nexttask not in self.rqdata.target_tids:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002121 logger.debug2("Skipping setscene for task %s" % nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002122 self.sq_task_skip(nexttask)
2123 self.scenequeue_notneeded.add(nexttask)
2124 if nexttask in self.sq_deferred:
2125 del self.sq_deferred[nexttask]
2126 return True
Brad Bishop08902b02019-08-20 09:16:51 -04002127 # If covered tasks are running, need to wait for them to complete
2128 for t in self.sqdata.sq_covered_tasks[nexttask]:
2129 if t in self.runq_running and t not in self.runq_complete:
2130 continue
Brad Bishop96ff1982019-08-19 13:50:42 -04002131 if nexttask in self.sq_deferred:
2132 if self.sq_deferred[nexttask] not in self.runq_complete:
2133 continue
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002134 logger.debug("Task %s no longer deferred" % nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002135 del self.sq_deferred[nexttask]
Brad Bishop1d80a2e2019-11-15 16:35:03 -05002136 valid = self.rq.validate_hashes(set([nexttask]), self.cooker.data, 0, False, summary=False)
Brad Bishop96ff1982019-08-19 13:50:42 -04002137 if not valid:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002138 logger.debug("%s didn't become valid, skipping setscene" % nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002139 self.sq_task_failoutright(nexttask)
2140 return True
Brad Bishop96ff1982019-08-19 13:50:42 -04002141 if nexttask in self.sqdata.outrightfail:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002142 logger.debug2('No package found, so skipping setscene task %s', nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002143 self.sq_task_failoutright(nexttask)
2144 return True
2145 if nexttask in self.sqdata.unskippable:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002146 logger.debug2("Setscene task %s is unskippable" % nexttask)
Brad Bishop96ff1982019-08-19 13:50:42 -04002147 task = nexttask
2148 break
2149 if task is not None:
2150 (mc, fn, taskname, taskfn) = split_tid_mcfn(task)
2151 taskname = taskname + "_setscene"
2152 if self.rq.check_stamp_task(task, taskname_from_tid(task), recurse = True, cache=self.stampcache):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002153 logger.debug2('Stamp for underlying task %s is current, so skipping setscene variant', task)
Brad Bishop96ff1982019-08-19 13:50:42 -04002154 self.sq_task_failoutright(task)
2155 return True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002156
Brad Bishop96ff1982019-08-19 13:50:42 -04002157 if self.cooker.configuration.force:
2158 if task in self.rqdata.target_tids:
2159 self.sq_task_failoutright(task)
2160 return True
2161
2162 if self.rq.check_stamp_task(task, taskname, cache=self.stampcache):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002163 logger.debug2('Setscene stamp current task %s, so skip it and its dependencies', task)
Brad Bishop96ff1982019-08-19 13:50:42 -04002164 self.sq_task_skip(task)
2165 return True
2166
2167 if self.cooker.configuration.skipsetscene:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002168 logger.debug2('No setscene tasks should be executed. Skipping %s', task)
Brad Bishop96ff1982019-08-19 13:50:42 -04002169 self.sq_task_failoutright(task)
2170 return True
2171
Andrew Geissler5199d832021-09-24 16:47:35 -05002172 startevent = sceneQueueTaskStarted(task, self.stats, self.rq)
Brad Bishop96ff1982019-08-19 13:50:42 -04002173 bb.event.fire(startevent, self.cfgData)
2174
Brad Bishop96ff1982019-08-19 13:50:42 -04002175 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
Patrick Williams520786c2023-06-25 16:20:36 -05002176 realfn = bb.cache.virtualfn2realfn(taskfn)[0]
Andrew Geissler517393d2023-01-13 08:55:19 -06002177 runtask = {
2178 'fn' : taskfn,
2179 'task' : task,
2180 'taskname' : taskname,
2181 'taskhash' : self.rqdata.get_task_hash(task),
2182 'unihash' : self.rqdata.get_task_unihash(task),
2183 'quieterrors' : True,
2184 'appends' : self.cooker.collections[mc].get_file_appends(taskfn),
Patrick Williams520786c2023-06-25 16:20:36 -05002185 'layername' : self.cooker.collections[mc].calc_bbfile_priority(realfn)[2],
Andrew Geissler517393d2023-01-13 08:55:19 -06002186 'taskdepdata' : self.sq_build_taskdepdata(task),
2187 'dry_run' : False,
2188 'taskdep': taskdep,
2189 'fakerootenv' : self.rqdata.dataCaches[mc].fakerootenv[taskfn],
2190 'fakerootdirs' : self.rqdata.dataCaches[mc].fakerootdirs[taskfn],
2191 'fakerootnoenv' : self.rqdata.dataCaches[mc].fakerootnoenv[taskfn]
2192 }
2193
Brad Bishop96ff1982019-08-19 13:50:42 -04002194 if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not self.cooker.configuration.dry_run:
2195 if not mc in self.rq.fakeworker:
2196 self.rq.start_fakeworker(self, mc)
Andrew Geissler517393d2023-01-13 08:55:19 -06002197 self.rq.fakeworker[mc].process.stdin.write(b"<runtask>" + pickle.dumps(runtask) + b"</runtask>")
Brad Bishop96ff1982019-08-19 13:50:42 -04002198 self.rq.fakeworker[mc].process.stdin.flush()
2199 else:
Andrew Geissler517393d2023-01-13 08:55:19 -06002200 self.rq.worker[mc].process.stdin.write(b"<runtask>" + pickle.dumps(runtask) + b"</runtask>")
Brad Bishop96ff1982019-08-19 13:50:42 -04002201 self.rq.worker[mc].process.stdin.flush()
2202
Andrew Geissler517393d2023-01-13 08:55:19 -06002203 self.build_stamps[task] = bb.parse.siggen.stampfile_mcfn(taskname, taskfn, extrainfo=False)
Brad Bishop96ff1982019-08-19 13:50:42 -04002204 self.build_stamps2.append(self.build_stamps[task])
2205 self.sq_running.add(task)
2206 self.sq_live.add(task)
Andrew Geissler5199d832021-09-24 16:47:35 -05002207 self.stats.updateActiveSetscene(len(self.sq_live))
Brad Bishop96ff1982019-08-19 13:50:42 -04002208 if self.can_start_task():
2209 return True
2210
Brad Bishopc68388fc2019-08-26 01:33:31 -04002211 self.update_holdofftasks()
2212
Brad Bishop08902b02019-08-20 09:16:51 -04002213 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 -05002214 hashequiv_logger.verbose("Setscene tasks completed")
Brad Bishop96ff1982019-08-19 13:50:42 -04002215
Brad Bishop08902b02019-08-20 09:16:51 -04002216 err = self.summarise_scenequeue_errors()
Brad Bishop96ff1982019-08-19 13:50:42 -04002217 if err:
2218 self.rq.state = runQueueFailed
2219 return True
2220
2221 if self.cooker.configuration.setsceneonly:
2222 self.rq.state = runQueueComplete
2223 return True
2224 self.sqdone = True
2225
2226 if self.stats.total == 0:
2227 # nothing to do
2228 self.rq.state = runQueueComplete
2229 return True
2230
2231 if self.cooker.configuration.setsceneonly:
2232 task = None
2233 else:
2234 task = self.sched.next()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002235 if task is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002236 (mc, fn, taskname, taskfn) = split_tid_mcfn(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002237
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002238 if self.rqdata.setscene_ignore_tasks is not None:
2239 if self.check_setscene_ignore_tasks(task):
2240 self.task_fail(task, "setscene ignore_tasks")
Brad Bishop96ff1982019-08-19 13:50:42 -04002241 return True
2242
2243 if task in self.tasks_covered:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002244 logger.debug2("Setscene covered task %s", task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002245 self.task_skip(task, "covered")
2246 return True
2247
2248 if self.rq.check_stamp_task(task, taskname, cache=self.stampcache):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002249 logger.debug2("Stamp current task %s", task)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002250
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002251 self.task_skip(task, "existing")
Andrew Geissler82c905d2020-04-13 13:39:40 -05002252 self.runq_tasksrun.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002253 return True
2254
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002255 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002256 if 'noexec' in taskdep and taskname in taskdep['noexec']:
2257 startevent = runQueueTaskStarted(task, self.stats, self.rq,
2258 noexec=True)
2259 bb.event.fire(startevent, self.cfgData)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002260 self.runq_running.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002261 self.stats.taskActive()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002262 if not (self.cooker.configuration.dry_run or self.rqdata.setscene_enforce):
Andrew Geissler517393d2023-01-13 08:55:19 -06002263 bb.build.make_stamp_mcfn(taskname, taskfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002264 self.task_complete(task)
2265 return True
2266 else:
2267 startevent = runQueueTaskStarted(task, self.stats, self.rq)
2268 bb.event.fire(startevent, self.cfgData)
2269
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002270 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
Patrick Williams520786c2023-06-25 16:20:36 -05002271 realfn = bb.cache.virtualfn2realfn(taskfn)[0]
Andrew Geissler517393d2023-01-13 08:55:19 -06002272 runtask = {
2273 'fn' : taskfn,
2274 'task' : task,
2275 'taskname' : taskname,
2276 'taskhash' : self.rqdata.get_task_hash(task),
2277 'unihash' : self.rqdata.get_task_unihash(task),
2278 'quieterrors' : False,
2279 'appends' : self.cooker.collections[mc].get_file_appends(taskfn),
Patrick Williams520786c2023-06-25 16:20:36 -05002280 'layername' : self.cooker.collections[mc].calc_bbfile_priority(realfn)[2],
Andrew Geissler517393d2023-01-13 08:55:19 -06002281 'taskdepdata' : self.build_taskdepdata(task),
2282 'dry_run' : self.rqdata.setscene_enforce,
2283 'taskdep': taskdep,
2284 'fakerootenv' : self.rqdata.dataCaches[mc].fakerootenv[taskfn],
2285 'fakerootdirs' : self.rqdata.dataCaches[mc].fakerootdirs[taskfn],
2286 'fakerootnoenv' : self.rqdata.dataCaches[mc].fakerootnoenv[taskfn]
2287 }
2288
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002289 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 -05002290 if not mc in self.rq.fakeworker:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002291 try:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05002292 self.rq.start_fakeworker(self, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002293 except OSError as exc:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002294 logger.critical("Failed to spawn fakeroot worker to run %s: %s" % (task, str(exc)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002295 self.rq.state = runQueueFailed
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002296 self.stats.taskFailed()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002297 return True
Andrew Geissler517393d2023-01-13 08:55:19 -06002298 self.rq.fakeworker[mc].process.stdin.write(b"<runtask>" + pickle.dumps(runtask) + b"</runtask>")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002299 self.rq.fakeworker[mc].process.stdin.flush()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002300 else:
Andrew Geissler517393d2023-01-13 08:55:19 -06002301 self.rq.worker[mc].process.stdin.write(b"<runtask>" + pickle.dumps(runtask) + b"</runtask>")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002302 self.rq.worker[mc].process.stdin.flush()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002303
Andrew Geissler517393d2023-01-13 08:55:19 -06002304 self.build_stamps[task] = bb.parse.siggen.stampfile_mcfn(taskname, taskfn, extrainfo=False)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002305 self.build_stamps2.append(self.build_stamps[task])
2306 self.runq_running.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002307 self.stats.taskActive()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08002308 if self.can_start_task():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002309 return True
2310
Andrew Geissler595f6302022-01-24 19:11:47 +00002311 if self.stats.active > 0 or self.sq_live:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002312 self.rq.read_workers()
2313 return self.rq.active_fds()
2314
Brad Bishop96ff1982019-08-19 13:50:42 -04002315 # No more tasks can be run. If we have deferred setscene tasks we should run them.
2316 if self.sq_deferred:
Patrick Williams92b42cb2022-09-03 06:53:57 -05002317 deferred_tid = list(self.sq_deferred.keys())[0]
2318 blocking_tid = self.sq_deferred.pop(deferred_tid)
Patrick Williams2390b1b2022-11-03 13:47:49 -05002319 logger.warning("Runqueue deadlocked on deferred tasks, forcing task %s blocked by %s" % (deferred_tid, blocking_tid))
Brad Bishop96ff1982019-08-19 13:50:42 -04002320 return True
2321
Andrew Geissler595f6302022-01-24 19:11:47 +00002322 if self.failed_tids:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002323 self.rq.state = runQueueFailed
2324 return True
2325
2326 # Sanity Checks
Brad Bishop08902b02019-08-20 09:16:51 -04002327 err = self.summarise_scenequeue_errors()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002328 for task in self.rqdata.runtaskentries:
2329 if task not in self.runq_buildable:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002330 logger.error("Task %s never buildable!", task)
Brad Bishop08902b02019-08-20 09:16:51 -04002331 err = True
Brad Bishop96ff1982019-08-19 13:50:42 -04002332 elif task not in self.runq_running:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002333 logger.error("Task %s never ran!", task)
Brad Bishop08902b02019-08-20 09:16:51 -04002334 err = True
Brad Bishop96ff1982019-08-19 13:50:42 -04002335 elif task not in self.runq_complete:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002336 logger.error("Task %s never completed!", task)
Brad Bishop08902b02019-08-20 09:16:51 -04002337 err = True
2338
2339 if err:
2340 self.rq.state = runQueueFailed
2341 else:
2342 self.rq.state = runQueueComplete
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002343
2344 return True
2345
Brad Bishopc68388fc2019-08-26 01:33:31 -04002346 def filtermcdeps(self, task, mc, deps):
Andrew Geissler99467da2019-02-25 18:54:23 -06002347 ret = set()
Andrew Geissler99467da2019-02-25 18:54:23 -06002348 for dep in deps:
Brad Bishopc68388fc2019-08-26 01:33:31 -04002349 thismc = mc_from_tid(dep)
2350 if thismc != mc:
Andrew Geissler99467da2019-02-25 18:54:23 -06002351 continue
2352 ret.add(dep)
2353 return ret
2354
Brad Bishopa34c0302019-09-23 22:34:48 -04002355 # We filter out multiconfig dependencies from taskdepdata we pass to the tasks
Andrew Geissler99467da2019-02-25 18:54:23 -06002356 # as most code can't handle them
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002357 def build_taskdepdata(self, task):
2358 taskdepdata = {}
Brad Bishopc68388fc2019-08-26 01:33:31 -04002359 mc = mc_from_tid(task)
Brad Bishop08902b02019-08-20 09:16:51 -04002360 next = self.rqdata.runtaskentries[task].depends.copy()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002361 next.add(task)
Brad Bishopc68388fc2019-08-26 01:33:31 -04002362 next = self.filtermcdeps(task, mc, next)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002363 while next:
2364 additional = []
2365 for revdep in next:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002366 (mc, fn, taskname, taskfn) = split_tid_mcfn(revdep)
2367 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
2368 deps = self.rqdata.runtaskentries[revdep].depends
2369 provides = self.rqdata.dataCaches[mc].fn_provides[taskfn]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002370 taskhash = self.rqdata.runtaskentries[revdep].hash
Brad Bishop19323692019-04-05 15:28:33 -04002371 unihash = self.rqdata.runtaskentries[revdep].unihash
Brad Bishopc68388fc2019-08-26 01:33:31 -04002372 deps = self.filtermcdeps(task, mc, deps)
Patrick Williamsb542dec2023-06-09 01:26:37 -05002373 hashfn = self.rqdata.dataCaches[mc].hashfn[taskfn]
2374 taskdepdata[revdep] = [pn, taskname, fn, deps, provides, taskhash, unihash, hashfn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002375 for revdep2 in deps:
2376 if revdep2 not in taskdepdata:
2377 additional.append(revdep2)
2378 next = additional
2379
2380 #bb.note("Task %s: " % task + str(taskdepdata).replace("], ", "],\n"))
2381 return taskdepdata
2382
Brad Bishop08902b02019-08-20 09:16:51 -04002383 def update_holdofftasks(self):
Brad Bishopc68388fc2019-08-26 01:33:31 -04002384
2385 if not self.holdoff_need_update:
2386 return
2387
2388 notcovered = set(self.scenequeue_notcovered)
2389 notcovered |= self.cantskip
2390 for tid in self.scenequeue_notcovered:
2391 notcovered |= self.sqdata.sq_covered_tasks[tid]
2392 notcovered |= self.sqdata.unskippable.difference(self.rqdata.runq_setscene_tids)
2393 notcovered.intersection_update(self.tasks_scenequeue_done)
2394
2395 covered = set(self.scenequeue_covered)
2396 for tid in self.scenequeue_covered:
2397 covered |= self.sqdata.sq_covered_tasks[tid]
2398 covered.difference_update(notcovered)
2399 covered.intersection_update(self.tasks_scenequeue_done)
2400
2401 for tid in notcovered | covered:
Andrew Geissler595f6302022-01-24 19:11:47 +00002402 if not self.rqdata.runtaskentries[tid].depends:
Brad Bishopc68388fc2019-08-26 01:33:31 -04002403 self.setbuildable(tid)
2404 elif self.rqdata.runtaskentries[tid].depends.issubset(self.runq_complete):
2405 self.setbuildable(tid)
2406
2407 self.tasks_covered = covered
2408 self.tasks_notcovered = notcovered
2409
Brad Bishop08902b02019-08-20 09:16:51 -04002410 self.holdoff_tasks = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002411
Brad Bishop08902b02019-08-20 09:16:51 -04002412 for tid in self.rqdata.runq_setscene_tids:
2413 if tid not in self.scenequeue_covered and tid not in self.scenequeue_notcovered:
2414 self.holdoff_tasks.add(tid)
2415
2416 for tid in self.holdoff_tasks.copy():
2417 for dep in self.sqdata.sq_covered_tasks[tid]:
2418 if dep not in self.runq_complete:
2419 self.holdoff_tasks.add(dep)
2420
Brad Bishopc68388fc2019-08-26 01:33:31 -04002421 self.holdoff_need_update = False
2422
Brad Bishop08902b02019-08-20 09:16:51 -04002423 def process_possible_migrations(self):
2424
2425 changed = set()
Andrew Geissler82c905d2020-04-13 13:39:40 -05002426 toprocess = set()
Brad Bishop08902b02019-08-20 09:16:51 -04002427 for tid, unihash in self.updated_taskhash_queue.copy():
2428 if tid in self.runq_running and tid not in self.runq_complete:
2429 continue
2430
2431 self.updated_taskhash_queue.remove((tid, unihash))
2432
2433 if unihash != self.rqdata.runtaskentries[tid].unihash:
Andrew Geisslerc926e172021-05-07 16:11:35 -05002434 # Make sure we rehash any other tasks with the same task hash that we're deferred against.
2435 torehash = [tid]
2436 for deftid in self.sq_deferred:
2437 if self.sq_deferred[deftid] == tid:
2438 torehash.append(deftid)
2439 for hashtid in torehash:
2440 hashequiv_logger.verbose("Task %s unihash changed to %s" % (hashtid, unihash))
2441 self.rqdata.runtaskentries[hashtid].unihash = unihash
2442 bb.parse.siggen.set_unihash(hashtid, unihash)
2443 toprocess.add(hashtid)
Andrew Geissler78b72792022-06-14 06:47:25 -05002444 if torehash:
2445 # Need to save after set_unihash above
2446 bb.parse.siggen.save_unitaskhashes()
Brad Bishop08902b02019-08-20 09:16:51 -04002447
Andrew Geissler82c905d2020-04-13 13:39:40 -05002448 # Work out all tasks which depend upon these
2449 total = set()
2450 next = set()
2451 for p in toprocess:
2452 next |= self.rqdata.runtaskentries[p].revdeps
2453 while next:
2454 current = next.copy()
2455 total = total | next
2456 next = set()
2457 for ntid in current:
2458 next |= self.rqdata.runtaskentries[ntid].revdeps
2459 next.difference_update(total)
Brad Bishop08902b02019-08-20 09:16:51 -04002460
Andrew Geissler82c905d2020-04-13 13:39:40 -05002461 # Now iterate those tasks in dependency order to regenerate their taskhash/unihash
2462 next = set()
2463 for p in total:
Andrew Geissler595f6302022-01-24 19:11:47 +00002464 if not self.rqdata.runtaskentries[p].depends:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002465 next.add(p)
2466 elif self.rqdata.runtaskentries[p].depends.isdisjoint(total):
2467 next.add(p)
2468
2469 # When an item doesn't have dependencies in total, we can process it. Drop items from total when handled
2470 while next:
2471 current = next.copy()
2472 next = set()
2473 for tid in current:
Andrew Geissler595f6302022-01-24 19:11:47 +00002474 if self.rqdata.runtaskentries[p].depends and not self.rqdata.runtaskentries[tid].depends.isdisjoint(total):
Andrew Geissler82c905d2020-04-13 13:39:40 -05002475 continue
2476 orighash = self.rqdata.runtaskentries[tid].hash
Andrew Geissler517393d2023-01-13 08:55:19 -06002477 newhash = bb.parse.siggen.get_taskhash(tid, self.rqdata.runtaskentries[tid].depends, self.rqdata.dataCaches)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002478 origuni = self.rqdata.runtaskentries[tid].unihash
2479 newuni = bb.parse.siggen.get_unihash(tid)
2480 # FIXME, need to check it can come from sstate at all for determinism?
2481 remapped = False
2482 if newuni == origuni:
2483 # Nothing to do, we match, skip code below
2484 remapped = True
2485 elif tid in self.scenequeue_covered or tid in self.sq_live:
2486 # Already ran this setscene task or it running. Report the new taskhash
2487 bb.parse.siggen.report_unihash_equiv(tid, newhash, origuni, newuni, self.rqdata.dataCaches)
2488 hashequiv_logger.verbose("Already covered setscene for %s so ignoring rehash (remap)" % (tid))
2489 remapped = True
2490
2491 if not remapped:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002492 #logger.debug("Task %s hash changes: %s->%s %s->%s" % (tid, orighash, newhash, origuni, newuni))
Andrew Geissler82c905d2020-04-13 13:39:40 -05002493 self.rqdata.runtaskentries[tid].hash = newhash
2494 self.rqdata.runtaskentries[tid].unihash = newuni
2495 changed.add(tid)
2496
2497 next |= self.rqdata.runtaskentries[tid].revdeps
2498 total.remove(tid)
2499 next.intersection_update(total)
Brad Bishop08902b02019-08-20 09:16:51 -04002500
2501 if changed:
2502 for mc in self.rq.worker:
2503 self.rq.worker[mc].process.stdin.write(b"<newtaskhashes>" + pickle.dumps(bb.parse.siggen.get_taskhashes()) + b"</newtaskhashes>")
2504 for mc in self.rq.fakeworker:
2505 self.rq.fakeworker[mc].process.stdin.write(b"<newtaskhashes>" + pickle.dumps(bb.parse.siggen.get_taskhashes()) + b"</newtaskhashes>")
2506
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002507 hashequiv_logger.debug(pprint.pformat("Tasks changed:\n%s" % (changed)))
Brad Bishop08902b02019-08-20 09:16:51 -04002508
2509 for tid in changed:
2510 if tid not in self.rqdata.runq_setscene_tids:
2511 continue
Brad Bishop08902b02019-08-20 09:16:51 -04002512 if tid not in self.pending_migrations:
2513 self.pending_migrations.add(tid)
2514
Andrew Geissler82c905d2020-04-13 13:39:40 -05002515 update_tasks = []
Brad Bishop08902b02019-08-20 09:16:51 -04002516 for tid in self.pending_migrations.copy():
Andrew Geissler82c905d2020-04-13 13:39:40 -05002517 if tid in self.runq_running or tid in self.sq_live:
Brad Bishop6dbb3162019-11-25 09:41:34 -05002518 # Too late, task already running, not much we can do now
2519 self.pending_migrations.remove(tid)
2520 continue
2521
Brad Bishop08902b02019-08-20 09:16:51 -04002522 valid = True
2523 # Check no tasks this covers are running
2524 for dep in self.sqdata.sq_covered_tasks[tid]:
2525 if dep in self.runq_running and dep not in self.runq_complete:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002526 hashequiv_logger.debug2("Task %s is running which blocks setscene for %s from running" % (dep, tid))
Brad Bishop08902b02019-08-20 09:16:51 -04002527 valid = False
2528 break
2529 if not valid:
2530 continue
2531
2532 self.pending_migrations.remove(tid)
Brad Bishopc68388fc2019-08-26 01:33:31 -04002533 changed = True
Brad Bishop08902b02019-08-20 09:16:51 -04002534
2535 if tid in self.tasks_scenequeue_done:
2536 self.tasks_scenequeue_done.remove(tid)
2537 for dep in self.sqdata.sq_covered_tasks[tid]:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002538 if dep in self.runq_complete and dep not in self.runq_tasksrun:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002539 bb.error("Task %s marked as completed but now needing to rerun? Halting build." % dep)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002540 self.failed_tids.append(tid)
2541 self.rq.state = runQueueCleanUp
2542 return
2543
Brad Bishop08902b02019-08-20 09:16:51 -04002544 if dep not in self.runq_complete:
2545 if dep in self.tasks_scenequeue_done and dep not in self.sqdata.unskippable:
2546 self.tasks_scenequeue_done.remove(dep)
2547
2548 if tid in self.sq_buildable:
2549 self.sq_buildable.remove(tid)
2550 if tid in self.sq_running:
2551 self.sq_running.remove(tid)
Andrew Geissler517393d2023-01-13 08:55:19 -06002552 if tid in self.sqdata.outrightfail:
2553 self.sqdata.outrightfail.remove(tid)
2554 if tid in self.scenequeue_notcovered:
2555 self.scenequeue_notcovered.remove(tid)
2556 if tid in self.scenequeue_covered:
2557 self.scenequeue_covered.remove(tid)
2558 if tid in self.scenequeue_notneeded:
2559 self.scenequeue_notneeded.remove(tid)
2560
2561 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
2562 self.sqdata.stamps[tid] = bb.parse.siggen.stampfile_mcfn(taskname, taskfn, extrainfo=False)
2563
2564 if tid in self.stampcache:
2565 del self.stampcache[tid]
2566
2567 if tid in self.build_stamps:
2568 del self.build_stamps[tid]
2569
2570 update_tasks.append(tid)
2571
2572 update_tasks2 = []
2573 for tid in update_tasks:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002574 harddepfail = False
2575 for t in self.sqdata.sq_harddeps:
2576 if tid in self.sqdata.sq_harddeps[t] and t in self.scenequeue_notcovered:
2577 harddepfail = True
2578 break
2579 if not harddepfail and self.sqdata.sq_revdeps[tid].issubset(self.scenequeue_covered | self.scenequeue_notcovered):
Brad Bishop08902b02019-08-20 09:16:51 -04002580 if tid not in self.sq_buildable:
2581 self.sq_buildable.add(tid)
Andrew Geissler595f6302022-01-24 19:11:47 +00002582 if not self.sqdata.sq_revdeps[tid]:
Brad Bishop08902b02019-08-20 09:16:51 -04002583 self.sq_buildable.add(tid)
2584
Andrew Geissler517393d2023-01-13 08:55:19 -06002585 update_tasks2.append((tid, harddepfail, tid in self.sqdata.valid))
Brad Bishop08902b02019-08-20 09:16:51 -04002586
Andrew Geissler517393d2023-01-13 08:55:19 -06002587 if update_tasks2:
Brad Bishop08902b02019-08-20 09:16:51 -04002588 self.sqdone = False
Patrick Williams92b42cb2022-09-03 06:53:57 -05002589 for mc in sorted(self.sqdata.multiconfigs):
Andrew Geissler517393d2023-01-13 08:55:19 -06002590 for tid in sorted([t[0] for t in update_tasks2]):
Patrick Williams92b42cb2022-09-03 06:53:57 -05002591 if mc_from_tid(tid) != mc:
2592 continue
2593 h = pending_hash_index(tid, self.rqdata)
2594 if h in self.sqdata.hashes and tid != self.sqdata.hashes[h]:
2595 self.sq_deferred[tid] = self.sqdata.hashes[h]
2596 bb.note("Deferring %s after %s" % (tid, self.sqdata.hashes[h]))
Andrew Geissler517393d2023-01-13 08:55:19 -06002597 update_scenequeue_data([t[0] for t in update_tasks2], self.sqdata, self.rqdata, self.rq, self.cooker, self.stampcache, self, summary=False)
Andrew Geissler82c905d2020-04-13 13:39:40 -05002598
Andrew Geissler517393d2023-01-13 08:55:19 -06002599 for (tid, harddepfail, origvalid) in update_tasks2:
Brad Bishop1d80a2e2019-11-15 16:35:03 -05002600 if tid in self.sqdata.valid and not origvalid:
Andrew Geissler82c905d2020-04-13 13:39:40 -05002601 hashequiv_logger.verbose("Setscene task %s became valid" % tid)
2602 if harddepfail:
Andrew Geissler517393d2023-01-13 08:55:19 -06002603 logger.debug2("%s has an unavailable hard dependency so skipping" % (tid))
Andrew Geissler82c905d2020-04-13 13:39:40 -05002604 self.sq_task_failoutright(tid)
Brad Bishop08902b02019-08-20 09:16:51 -04002605
2606 if changed:
Andrew Geissler5199d832021-09-24 16:47:35 -05002607 self.stats.updateCovered(len(self.scenequeue_covered), len(self.scenequeue_notcovered))
Brad Bishopc68388fc2019-08-26 01:33:31 -04002608 self.holdoff_need_update = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002609
Brad Bishop96ff1982019-08-19 13:50:42 -04002610 def scenequeue_updatecounters(self, task, fail=False):
Brad Bishop08902b02019-08-20 09:16:51 -04002611
2612 for dep in sorted(self.sqdata.sq_deps[task]):
Brad Bishop96ff1982019-08-19 13:50:42 -04002613 if fail and task in self.sqdata.sq_harddeps and dep in self.sqdata.sq_harddeps[task]:
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002614 if dep in self.scenequeue_covered or dep in self.scenequeue_notcovered:
2615 # dependency could be already processed, e.g. noexec setscene task
2616 continue
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05002617 noexec, stamppresent = check_setscene_stamps(dep, self.rqdata, self.rq, self.stampcache)
2618 if noexec or stamppresent:
2619 continue
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002620 logger.debug2("%s was unavailable and is a hard dependency of %s so skipping" % (task, dep))
Brad Bishop96ff1982019-08-19 13:50:42 -04002621 self.sq_task_failoutright(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002622 continue
Brad Bishop08902b02019-08-20 09:16:51 -04002623 if self.sqdata.sq_revdeps[dep].issubset(self.scenequeue_covered | self.scenequeue_notcovered):
2624 if dep not in self.sq_buildable:
2625 self.sq_buildable.add(dep)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002626
Brad Bishop96ff1982019-08-19 13:50:42 -04002627 next = set([task])
2628 while next:
2629 new = set()
Brad Bishop08902b02019-08-20 09:16:51 -04002630 for t in sorted(next):
Brad Bishop96ff1982019-08-19 13:50:42 -04002631 self.tasks_scenequeue_done.add(t)
2632 # Look down the dependency chain for non-setscene things which this task depends on
2633 # and mark as 'done'
2634 for dep in self.rqdata.runtaskentries[t].depends:
2635 if dep in self.rqdata.runq_setscene_tids or dep in self.tasks_scenequeue_done:
2636 continue
2637 if self.rqdata.runtaskentries[dep].revdeps.issubset(self.tasks_scenequeue_done):
2638 new.add(dep)
Brad Bishop96ff1982019-08-19 13:50:42 -04002639 next = new
2640
Andrew Geissler5199d832021-09-24 16:47:35 -05002641 self.stats.updateCovered(len(self.scenequeue_covered), len(self.scenequeue_notcovered))
Brad Bishopc68388fc2019-08-26 01:33:31 -04002642 self.holdoff_need_update = True
Brad Bishop96ff1982019-08-19 13:50:42 -04002643
2644 def sq_task_completeoutright(self, task):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002645 """
2646 Mark a task as completed
2647 Look at the reverse dependencies and mark any task with
2648 completed dependencies as buildable
2649 """
2650
Andrew Geisslerd1e89492021-02-12 15:35:20 -06002651 logger.debug('Found task %s which could be accelerated', task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002652 self.scenequeue_covered.add(task)
2653 self.scenequeue_updatecounters(task)
2654
Brad Bishop96ff1982019-08-19 13:50:42 -04002655 def sq_check_taskfail(self, task):
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002656 if self.rqdata.setscene_ignore_tasks is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002657 realtask = task.split('_setscene')[0]
Brad Bishop37a0e4d2017-12-04 01:01:44 -05002658 (mc, fn, taskname, taskfn) = split_tid_mcfn(realtask)
2659 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002660 if not check_setscene_enforce_ignore_tasks(pn, taskname, self.rqdata.setscene_ignore_tasks):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002661 logger.error('Task %s.%s failed' % (pn, taskname + "_setscene"))
2662 self.rq.state = runQueueCleanUp
2663
Brad Bishop96ff1982019-08-19 13:50:42 -04002664 def sq_task_complete(self, task):
Andrew Geissler5199d832021-09-24 16:47:35 -05002665 bb.event.fire(sceneQueueTaskCompleted(task, self.stats, self.rq), self.cfgData)
Brad Bishop96ff1982019-08-19 13:50:42 -04002666 self.sq_task_completeoutright(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002667
Brad Bishop96ff1982019-08-19 13:50:42 -04002668 def sq_task_fail(self, task, result):
Andrew Geissler5199d832021-09-24 16:47:35 -05002669 bb.event.fire(sceneQueueTaskFailed(task, self.stats, result, self), self.cfgData)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002670 self.scenequeue_notcovered.add(task)
2671 self.scenequeue_updatecounters(task, True)
Brad Bishop96ff1982019-08-19 13:50:42 -04002672 self.sq_check_taskfail(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002673
Brad Bishop96ff1982019-08-19 13:50:42 -04002674 def sq_task_failoutright(self, task):
2675 self.sq_running.add(task)
2676 self.sq_buildable.add(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002677 self.scenequeue_notcovered.add(task)
2678 self.scenequeue_updatecounters(task, True)
2679
Brad Bishop96ff1982019-08-19 13:50:42 -04002680 def sq_task_skip(self, task):
2681 self.sq_running.add(task)
2682 self.sq_buildable.add(task)
2683 self.sq_task_completeoutright(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002684
Brad Bishop96ff1982019-08-19 13:50:42 -04002685 def sq_build_taskdepdata(self, task):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002686 def getsetscenedeps(tid):
2687 deps = set()
2688 (mc, fn, taskname, _) = split_tid_mcfn(tid)
2689 realtid = tid + "_setscene"
2690 idepends = self.rqdata.taskData[mc].taskentries[realtid].idepends
2691 for (depname, idependtask) in idepends:
2692 if depname not in self.rqdata.taskData[mc].build_targets:
2693 continue
2694
2695 depfn = self.rqdata.taskData[mc].build_targets[depname][0]
2696 if depfn is None:
2697 continue
2698 deptid = depfn + ":" + idependtask.replace("_setscene", "")
2699 deps.add(deptid)
2700 return deps
2701
2702 taskdepdata = {}
2703 next = getsetscenedeps(task)
2704 next.add(task)
2705 while next:
2706 additional = []
2707 for revdep in next:
2708 (mc, fn, taskname, taskfn) = split_tid_mcfn(revdep)
2709 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
2710 deps = getsetscenedeps(revdep)
2711 provides = self.rqdata.dataCaches[mc].fn_provides[taskfn]
2712 taskhash = self.rqdata.runtaskentries[revdep].hash
Brad Bishop19323692019-04-05 15:28:33 -04002713 unihash = self.rqdata.runtaskentries[revdep].unihash
Patrick Williamsb542dec2023-06-09 01:26:37 -05002714 hashfn = self.rqdata.dataCaches[mc].hashfn[taskfn]
2715 taskdepdata[revdep] = [pn, taskname, fn, deps, provides, taskhash, unihash, hashfn]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002716 for revdep2 in deps:
2717 if revdep2 not in taskdepdata:
2718 additional.append(revdep2)
2719 next = additional
2720
2721 #bb.note("Task %s: " % task + str(taskdepdata).replace("], ", "],\n"))
2722 return taskdepdata
2723
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002724 def check_setscene_ignore_tasks(self, tid):
2725 # Check task that is going to run against the ignore tasks list
Brad Bishop96ff1982019-08-19 13:50:42 -04002726 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
2727 # Ignore covered tasks
2728 if tid in self.tasks_covered:
2729 return False
2730 # Ignore stamped tasks
2731 if self.rq.check_stamp_task(tid, taskname, cache=self.stampcache):
2732 return False
2733 # Ignore noexec tasks
2734 taskdep = self.rqdata.dataCaches[mc].task_deps[taskfn]
2735 if 'noexec' in taskdep and taskname in taskdep['noexec']:
2736 return False
2737
2738 pn = self.rqdata.dataCaches[mc].pkg_fn[taskfn]
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002739 if not check_setscene_enforce_ignore_tasks(pn, taskname, self.rqdata.setscene_ignore_tasks):
Brad Bishop96ff1982019-08-19 13:50:42 -04002740 if tid in self.rqdata.runq_setscene_tids:
Andrew Geissler595f6302022-01-24 19:11:47 +00002741 msg = ['Task %s.%s attempted to execute unexpectedly and should have been setscened' % (pn, taskname)]
Brad Bishop96ff1982019-08-19 13:50:42 -04002742 else:
Andrew Geissler595f6302022-01-24 19:11:47 +00002743 msg = ['Task %s.%s attempted to execute unexpectedly' % (pn, taskname)]
Andrew Geissler82c905d2020-04-13 13:39:40 -05002744 for t in self.scenequeue_notcovered:
Andrew Geissler595f6302022-01-24 19:11:47 +00002745 msg.append("\nTask %s, unihash %s, taskhash %s" % (t, self.rqdata.runtaskentries[t].unihash, self.rqdata.runtaskentries[t].hash))
2746 msg.append('\nThis is usually due to missing setscene tasks. Those missing in this build were: %s' % pprint.pformat(self.scenequeue_notcovered))
2747 logger.error("".join(msg))
Brad Bishop96ff1982019-08-19 13:50:42 -04002748 return True
2749 return False
2750
2751class SQData(object):
2752 def __init__(self):
2753 # SceneQueue dependencies
2754 self.sq_deps = {}
2755 # SceneQueue reverse dependencies
2756 self.sq_revdeps = {}
Brad Bishop96ff1982019-08-19 13:50:42 -04002757 # Injected inter-setscene task dependencies
2758 self.sq_harddeps = {}
2759 # Cache of stamp files so duplicates can't run in parallel
2760 self.stamps = {}
2761 # Setscene tasks directly depended upon by the build
2762 self.unskippable = set()
2763 # List of setscene tasks which aren't present
2764 self.outrightfail = set()
2765 # A list of normal tasks a setscene task covers
2766 self.sq_covered_tasks = {}
2767
2768def build_scenequeue_data(sqdata, rqdata, rq, cooker, stampcache, sqrq):
2769
2770 sq_revdeps = {}
2771 sq_revdeps_squash = {}
2772 sq_collated_deps = {}
2773
2774 # We need to construct a dependency graph for the setscene functions. Intermediate
2775 # dependencies between the setscene tasks only complicate the code. This code
2776 # therefore aims to collapse the huge runqueue dependency tree into a smaller one
2777 # only containing the setscene functions.
2778
2779 rqdata.init_progress_reporter.next_stage()
2780
2781 # First process the chains up to the first setscene task.
2782 endpoints = {}
2783 for tid in rqdata.runtaskentries:
2784 sq_revdeps[tid] = copy.copy(rqdata.runtaskentries[tid].revdeps)
2785 sq_revdeps_squash[tid] = set()
Andrew Geissler595f6302022-01-24 19:11:47 +00002786 if not sq_revdeps[tid] and tid not in rqdata.runq_setscene_tids:
Brad Bishop96ff1982019-08-19 13:50:42 -04002787 #bb.warn("Added endpoint %s" % (tid))
2788 endpoints[tid] = set()
2789
2790 rqdata.init_progress_reporter.next_stage()
2791
2792 # Secondly process the chains between setscene tasks.
2793 for tid in rqdata.runq_setscene_tids:
2794 sq_collated_deps[tid] = set()
2795 #bb.warn("Added endpoint 2 %s" % (tid))
2796 for dep in rqdata.runtaskentries[tid].depends:
2797 if tid in sq_revdeps[dep]:
2798 sq_revdeps[dep].remove(tid)
2799 if dep not in endpoints:
2800 endpoints[dep] = set()
2801 #bb.warn(" Added endpoint 3 %s" % (dep))
2802 endpoints[dep].add(tid)
2803
2804 rqdata.init_progress_reporter.next_stage()
2805
2806 def process_endpoints(endpoints):
2807 newendpoints = {}
2808 for point, task in endpoints.items():
2809 tasks = set()
2810 if task:
2811 tasks |= task
2812 if sq_revdeps_squash[point]:
2813 tasks |= sq_revdeps_squash[point]
2814 if point not in rqdata.runq_setscene_tids:
2815 for t in tasks:
2816 sq_collated_deps[t].add(point)
2817 sq_revdeps_squash[point] = set()
2818 if point in rqdata.runq_setscene_tids:
2819 sq_revdeps_squash[point] = tasks
Brad Bishop96ff1982019-08-19 13:50:42 -04002820 continue
2821 for dep in rqdata.runtaskentries[point].depends:
2822 if point in sq_revdeps[dep]:
2823 sq_revdeps[dep].remove(point)
2824 if tasks:
2825 sq_revdeps_squash[dep] |= tasks
Andrew Geissler595f6302022-01-24 19:11:47 +00002826 if not sq_revdeps[dep] and dep not in rqdata.runq_setscene_tids:
Brad Bishop96ff1982019-08-19 13:50:42 -04002827 newendpoints[dep] = task
Andrew Geissler595f6302022-01-24 19:11:47 +00002828 if newendpoints:
Brad Bishop96ff1982019-08-19 13:50:42 -04002829 process_endpoints(newendpoints)
2830
2831 process_endpoints(endpoints)
2832
2833 rqdata.init_progress_reporter.next_stage()
2834
Brad Bishop08902b02019-08-20 09:16:51 -04002835 # Build a list of tasks which are "unskippable"
2836 # These are direct endpoints referenced by the build upto and including setscene tasks
Brad Bishop96ff1982019-08-19 13:50:42 -04002837 # Take the build endpoints (no revdeps) and find the sstate tasks they depend upon
2838 new = True
2839 for tid in rqdata.runtaskentries:
Andrew Geissler595f6302022-01-24 19:11:47 +00002840 if not rqdata.runtaskentries[tid].revdeps:
Brad Bishop96ff1982019-08-19 13:50:42 -04002841 sqdata.unskippable.add(tid)
Brad Bishop08902b02019-08-20 09:16:51 -04002842 sqdata.unskippable |= sqrq.cantskip
Brad Bishop96ff1982019-08-19 13:50:42 -04002843 while new:
2844 new = False
Brad Bishop08902b02019-08-20 09:16:51 -04002845 orig = sqdata.unskippable.copy()
2846 for tid in sorted(orig, reverse=True):
Brad Bishop96ff1982019-08-19 13:50:42 -04002847 if tid in rqdata.runq_setscene_tids:
2848 continue
Andrew Geissler595f6302022-01-24 19:11:47 +00002849 if not rqdata.runtaskentries[tid].depends:
Brad Bishop96ff1982019-08-19 13:50:42 -04002850 # These are tasks which have no setscene tasks in their chain, need to mark as directly buildable
Brad Bishop96ff1982019-08-19 13:50:42 -04002851 sqrq.setbuildable(tid)
Brad Bishop96ff1982019-08-19 13:50:42 -04002852 sqdata.unskippable |= rqdata.runtaskentries[tid].depends
Brad Bishop08902b02019-08-20 09:16:51 -04002853 if sqdata.unskippable != orig:
2854 new = True
2855
2856 sqrq.tasks_scenequeue_done |= sqdata.unskippable.difference(rqdata.runq_setscene_tids)
Brad Bishop96ff1982019-08-19 13:50:42 -04002857
2858 rqdata.init_progress_reporter.next_stage(len(rqdata.runtaskentries))
2859
2860 # Sanity check all dependencies could be changed to setscene task references
2861 for taskcounter, tid in enumerate(rqdata.runtaskentries):
2862 if tid in rqdata.runq_setscene_tids:
2863 pass
Andrew Geissler595f6302022-01-24 19:11:47 +00002864 elif sq_revdeps_squash[tid]:
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00002865 bb.msg.fatal("RunQueue", "Something went badly wrong during scenequeue generation, halting. Please report this problem.")
Brad Bishop96ff1982019-08-19 13:50:42 -04002866 else:
2867 del sq_revdeps_squash[tid]
2868 rqdata.init_progress_reporter.update(taskcounter)
2869
2870 rqdata.init_progress_reporter.next_stage()
2871
2872 # Resolve setscene inter-task dependencies
2873 # e.g. do_sometask_setscene[depends] = "targetname:do_someothertask_setscene"
2874 # Note that anything explicitly depended upon will have its reverse dependencies removed to avoid circular dependencies
2875 for tid in rqdata.runq_setscene_tids:
2876 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
2877 realtid = tid + "_setscene"
2878 idepends = rqdata.taskData[mc].taskentries[realtid].idepends
Andrew Geissler517393d2023-01-13 08:55:19 -06002879 sqdata.stamps[tid] = bb.parse.siggen.stampfile_mcfn(taskname, taskfn, extrainfo=False)
2880
Brad Bishop96ff1982019-08-19 13:50:42 -04002881 for (depname, idependtask) in idepends:
2882
2883 if depname not in rqdata.taskData[mc].build_targets:
2884 continue
2885
2886 depfn = rqdata.taskData[mc].build_targets[depname][0]
2887 if depfn is None:
2888 continue
2889 deptid = depfn + ":" + idependtask.replace("_setscene", "")
2890 if deptid not in rqdata.runtaskentries:
2891 bb.msg.fatal("RunQueue", "Task %s depends upon non-existent task %s:%s" % (realtid, depfn, idependtask))
2892
2893 if not deptid in sqdata.sq_harddeps:
2894 sqdata.sq_harddeps[deptid] = set()
2895 sqdata.sq_harddeps[deptid].add(tid)
2896
2897 sq_revdeps_squash[tid].add(deptid)
2898 # Have to zero this to avoid circular dependencies
2899 sq_revdeps_squash[deptid] = set()
2900
2901 rqdata.init_progress_reporter.next_stage()
2902
2903 for task in sqdata.sq_harddeps:
2904 for dep in sqdata.sq_harddeps[task]:
2905 sq_revdeps_squash[dep].add(task)
2906
2907 rqdata.init_progress_reporter.next_stage()
2908
2909 #for tid in sq_revdeps_squash:
2910 # data = ""
2911 # for dep in sq_revdeps_squash[tid]:
2912 # data = data + "\n %s" % dep
2913 # bb.warn("Task %s_setscene: is %s " % (tid, data))
2914
2915 sqdata.sq_revdeps = sq_revdeps_squash
Brad Bishop96ff1982019-08-19 13:50:42 -04002916 sqdata.sq_covered_tasks = sq_collated_deps
2917
2918 # Build reverse version of revdeps to populate deps structure
2919 for tid in sqdata.sq_revdeps:
2920 sqdata.sq_deps[tid] = set()
2921 for tid in sqdata.sq_revdeps:
2922 for dep in sqdata.sq_revdeps[tid]:
2923 sqdata.sq_deps[dep].add(tid)
2924
2925 rqdata.init_progress_reporter.next_stage()
2926
Brad Bishop00e122a2019-10-05 11:10:57 -04002927 sqdata.multiconfigs = set()
Brad Bishop96ff1982019-08-19 13:50:42 -04002928 for tid in sqdata.sq_revdeps:
Brad Bishop00e122a2019-10-05 11:10:57 -04002929 sqdata.multiconfigs.add(mc_from_tid(tid))
Andrew Geissler595f6302022-01-24 19:11:47 +00002930 if not sqdata.sq_revdeps[tid]:
Brad Bishop96ff1982019-08-19 13:50:42 -04002931 sqrq.sq_buildable.add(tid)
2932
2933 rqdata.init_progress_reporter.finish()
2934
Brad Bishop00e122a2019-10-05 11:10:57 -04002935 sqdata.noexec = set()
2936 sqdata.stamppresent = set()
2937 sqdata.valid = set()
Brad Bishop96ff1982019-08-19 13:50:42 -04002938
Patrick Williams213cb262021-08-07 19:21:33 -05002939 sqdata.hashes = {}
2940 sqrq.sq_deferred = {}
2941 for mc in sorted(sqdata.multiconfigs):
2942 for tid in sorted(sqdata.sq_revdeps):
2943 if mc_from_tid(tid) != mc:
2944 continue
2945 h = pending_hash_index(tid, rqdata)
2946 if h not in sqdata.hashes:
2947 sqdata.hashes[h] = tid
2948 else:
2949 sqrq.sq_deferred[tid] = sqdata.hashes[h]
Andrew Geissler8f840682023-07-21 09:09:43 -05002950 bb.debug(1, "Deferring %s after %s" % (tid, sqdata.hashes[h]))
Patrick Williams213cb262021-08-07 19:21:33 -05002951
Brad Bishop1d80a2e2019-11-15 16:35:03 -05002952 update_scenequeue_data(sqdata.sq_revdeps, sqdata, rqdata, rq, cooker, stampcache, sqrq, summary=True)
Brad Bishop00e122a2019-10-05 11:10:57 -04002953
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002954 # Compute a list of 'stale' sstate tasks where the current hash does not match the one
2955 # in any stamp files. Pass the list out to metadata as an event.
2956 found = {}
2957 for tid in rqdata.runq_setscene_tids:
2958 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
Andrew Geissler517393d2023-01-13 08:55:19 -06002959 stamps = bb.build.find_stale_stamps(taskname, taskfn)
Andrew Geissler95ac1b82021-03-31 14:34:31 -05002960 if stamps:
2961 if mc not in found:
2962 found[mc] = {}
2963 found[mc][tid] = stamps
2964 for mc in found:
2965 event = bb.event.StaleSetSceneTasks(found[mc])
2966 bb.event.fire(event, cooker.databuilder.mcdata[mc])
2967
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05002968def check_setscene_stamps(tid, rqdata, rq, stampcache, noexecstamp=False):
2969
2970 (mc, fn, taskname, taskfn) = split_tid_mcfn(tid)
2971
2972 taskdep = rqdata.dataCaches[mc].task_deps[taskfn]
2973
2974 if 'noexec' in taskdep and taskname in taskdep['noexec']:
Andrew Geissler517393d2023-01-13 08:55:19 -06002975 bb.build.make_stamp_mcfn(taskname + "_setscene", taskfn)
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05002976 return True, False
2977
2978 if rq.check_stamp_task(tid, taskname + "_setscene", cache=stampcache):
2979 logger.debug2('Setscene stamp current for task %s', tid)
2980 return False, True
2981
2982 if rq.check_stamp_task(tid, taskname, recurse = True, cache=stampcache):
2983 logger.debug2('Normal stamp current for task %s', tid)
2984 return False, True
2985
2986 return False, False
2987
Brad Bishop1d80a2e2019-11-15 16:35:03 -05002988def update_scenequeue_data(tids, sqdata, rqdata, rq, cooker, stampcache, sqrq, summary=True):
Brad Bishop00e122a2019-10-05 11:10:57 -04002989
2990 tocheck = set()
2991
2992 for tid in sorted(tids):
2993 if tid in sqdata.stamppresent:
2994 sqdata.stamppresent.remove(tid)
2995 if tid in sqdata.valid:
2996 sqdata.valid.remove(tid)
Andrew Geisslerc926e172021-05-07 16:11:35 -05002997 if tid in sqdata.outrightfail:
2998 sqdata.outrightfail.remove(tid)
Brad Bishop00e122a2019-10-05 11:10:57 -04002999
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05003000 noexec, stamppresent = check_setscene_stamps(tid, rqdata, rq, stampcache, noexecstamp=True)
Brad Bishop00e122a2019-10-05 11:10:57 -04003001
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05003002 if noexec:
Brad Bishop00e122a2019-10-05 11:10:57 -04003003 sqdata.noexec.add(tid)
3004 sqrq.sq_task_skip(tid)
Andrew Geissler517393d2023-01-13 08:55:19 -06003005 logger.debug2("%s is noexec so skipping setscene" % (tid))
Brad Bishop00e122a2019-10-05 11:10:57 -04003006 continue
3007
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05003008 if stamppresent:
Brad Bishop00e122a2019-10-05 11:10:57 -04003009 sqdata.stamppresent.add(tid)
3010 sqrq.sq_task_skip(tid)
Andrew Geissler517393d2023-01-13 08:55:19 -06003011 logger.debug2("%s has a valid stamp, skipping" % (tid))
Brad Bishop00e122a2019-10-05 11:10:57 -04003012 continue
3013
3014 tocheck.add(tid)
3015
Brad Bishop1d80a2e2019-11-15 16:35:03 -05003016 sqdata.valid |= rq.validate_hashes(tocheck, cooker.data, len(sqdata.stamppresent), False, summary=summary)
Brad Bishop00e122a2019-10-05 11:10:57 -04003017
Patrick Williams213cb262021-08-07 19:21:33 -05003018 for tid in tids:
3019 if tid in sqdata.stamppresent:
3020 continue
3021 if tid in sqdata.valid:
3022 continue
3023 if tid in sqdata.noexec:
3024 continue
3025 if tid in sqrq.scenequeue_covered:
3026 continue
3027 if tid in sqrq.scenequeue_notcovered:
3028 continue
3029 if tid in sqrq.sq_deferred:
3030 continue
3031 sqdata.outrightfail.add(tid)
Andrew Geissler517393d2023-01-13 08:55:19 -06003032 logger.debug2("%s already handled (fallthrough), skipping" % (tid))
Brad Bishop96ff1982019-08-19 13:50:42 -04003033
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003034class TaskFailure(Exception):
3035 """
3036 Exception raised when a task in a runqueue fails
3037 """
3038 def __init__(self, x):
3039 self.args = x
3040
3041
3042class runQueueExitWait(bb.event.Event):
3043 """
3044 Event when waiting for task processes to exit
3045 """
3046
3047 def __init__(self, remain):
3048 self.remain = remain
3049 self.message = "Waiting for %s active tasks to finish" % remain
3050 bb.event.Event.__init__(self)
3051
3052class runQueueEvent(bb.event.Event):
3053 """
3054 Base runQueue event class
3055 """
3056 def __init__(self, task, stats, rq):
3057 self.taskid = task
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003058 self.taskstring = task
3059 self.taskname = taskname_from_tid(task)
3060 self.taskfile = fn_from_tid(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003061 self.taskhash = rq.rqdata.get_task_hash(task)
3062 self.stats = stats.copy()
3063 bb.event.Event.__init__(self)
3064
3065class sceneQueueEvent(runQueueEvent):
3066 """
3067 Base sceneQueue event class
3068 """
3069 def __init__(self, task, stats, rq, noexec=False):
3070 runQueueEvent.__init__(self, task, stats, rq)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003071 self.taskstring = task + "_setscene"
3072 self.taskname = taskname_from_tid(task) + "_setscene"
3073 self.taskfile = fn_from_tid(task)
3074 self.taskhash = rq.rqdata.get_task_hash(task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003075
3076class runQueueTaskStarted(runQueueEvent):
3077 """
3078 Event notifying a task was started
3079 """
3080 def __init__(self, task, stats, rq, noexec=False):
3081 runQueueEvent.__init__(self, task, stats, rq)
3082 self.noexec = noexec
3083
3084class sceneQueueTaskStarted(sceneQueueEvent):
3085 """
3086 Event notifying a setscene task was started
3087 """
3088 def __init__(self, task, stats, rq, noexec=False):
3089 sceneQueueEvent.__init__(self, task, stats, rq)
3090 self.noexec = noexec
3091
3092class runQueueTaskFailed(runQueueEvent):
3093 """
3094 Event notifying a task failed
3095 """
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003096 def __init__(self, task, stats, exitcode, rq, fakeroot_log=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003097 runQueueEvent.__init__(self, task, stats, rq)
3098 self.exitcode = exitcode
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003099 self.fakeroot_log = fakeroot_log
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003100
Brad Bishopd7bf8c12018-02-25 22:55:05 -05003101 def __str__(self):
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003102 if self.fakeroot_log:
3103 return "Task (%s) failed with exit code '%s' \nPseudo log:\n%s" % (self.taskstring, self.exitcode, self.fakeroot_log)
3104 else:
3105 return "Task (%s) failed with exit code '%s'" % (self.taskstring, self.exitcode)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05003106
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003107class sceneQueueTaskFailed(sceneQueueEvent):
3108 """
3109 Event notifying a setscene task failed
3110 """
3111 def __init__(self, task, stats, exitcode, rq):
3112 sceneQueueEvent.__init__(self, task, stats, rq)
3113 self.exitcode = exitcode
3114
Brad Bishopd7bf8c12018-02-25 22:55:05 -05003115 def __str__(self):
3116 return "Setscene task (%s) failed with exit code '%s' - real task will be run instead" % (self.taskstring, self.exitcode)
3117
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003118class sceneQueueComplete(sceneQueueEvent):
3119 """
3120 Event when all the sceneQueue tasks are complete
3121 """
3122 def __init__(self, stats, rq):
3123 self.stats = stats.copy()
3124 bb.event.Event.__init__(self)
3125
3126class runQueueTaskCompleted(runQueueEvent):
3127 """
3128 Event notifying a task completed
3129 """
3130
3131class sceneQueueTaskCompleted(sceneQueueEvent):
3132 """
3133 Event notifying a setscene task completed
3134 """
3135
3136class runQueueTaskSkipped(runQueueEvent):
3137 """
3138 Event notifying a task was skipped
3139 """
3140 def __init__(self, task, stats, rq, reason):
3141 runQueueEvent.__init__(self, task, stats, rq)
3142 self.reason = reason
3143
Brad Bishop08902b02019-08-20 09:16:51 -04003144class taskUniHashUpdate(bb.event.Event):
3145 """
3146 Base runQueue event class
3147 """
3148 def __init__(self, task, unihash):
3149 self.taskid = task
3150 self.unihash = unihash
3151 bb.event.Event.__init__(self)
3152
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003153class runQueuePipe():
3154 """
3155 Abstraction for a pipe between a worker thread and the server
3156 """
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003157 def __init__(self, pipein, pipeout, d, rq, rqexec, fakerootlogs=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003158 self.input = pipein
3159 if pipeout:
3160 pipeout.close()
3161 bb.utils.nonblockingfd(self.input)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003162 self.queue = b""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003163 self.d = d
3164 self.rq = rq
3165 self.rqexec = rqexec
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003166 self.fakerootlogs = fakerootlogs
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003167
3168 def setrunqueueexec(self, rqexec):
3169 self.rqexec = rqexec
3170
3171 def read(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003172 for workers, name in [(self.rq.worker, "Worker"), (self.rq.fakeworker, "Fakeroot")]:
3173 for worker in workers.values():
3174 worker.process.poll()
3175 if worker.process.returncode is not None and not self.rq.teardown:
3176 bb.error("%s process (%s) exited unexpectedly (%s), shutting down..." % (name, worker.process.pid, str(worker.process.returncode)))
3177 self.rq.finish_runqueue(True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003178
3179 start = len(self.queue)
3180 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003181 self.queue = self.queue + (self.input.read(102400) or b"")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003182 except (OSError, IOError) as e:
3183 if e.errno != errno.EAGAIN:
3184 raise
3185 end = len(self.queue)
3186 found = True
Andrew Geissler595f6302022-01-24 19:11:47 +00003187 while found and self.queue:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003188 found = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003189 index = self.queue.find(b"</event>")
3190 while index != -1 and self.queue.startswith(b"<event>"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003191 try:
3192 event = pickle.loads(self.queue[7:index])
Andrew Geissler475cb722020-07-10 16:00:51 -05003193 except (ValueError, pickle.UnpicklingError, AttributeError, IndexError) as e:
3194 if isinstance(e, pickle.UnpicklingError) and "truncated" in str(e):
3195 # The pickled data could contain "</event>" so search for the next occurance
3196 # unpickling again, this should be the only way an unpickle error could occur
3197 index = self.queue.find(b"</event>", index + 1)
3198 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003199 bb.msg.fatal("RunQueue", "failed load pickle '%s': '%s'" % (e, self.queue[7:index]))
3200 bb.event.fire_from_worker(event, self.d)
Brad Bishop08902b02019-08-20 09:16:51 -04003201 if isinstance(event, taskUniHashUpdate):
3202 self.rqexec.updated_taskhash_queue.append((event.taskid, event.unihash))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003203 found = True
3204 self.queue = self.queue[index+8:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003205 index = self.queue.find(b"</event>")
3206 index = self.queue.find(b"</exitcode>")
3207 while index != -1 and self.queue.startswith(b"<exitcode>"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003208 try:
3209 task, status = pickle.loads(self.queue[10:index])
Andrew Geissler475cb722020-07-10 16:00:51 -05003210 except (ValueError, pickle.UnpicklingError, AttributeError, IndexError) as e:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003211 bb.msg.fatal("RunQueue", "failed load pickle '%s': '%s'" % (e, self.queue[10:index]))
Andrew Geissler95ac1b82021-03-31 14:34:31 -05003212 (_, _, _, taskfn) = split_tid_mcfn(task)
3213 fakerootlog = None
3214 if self.fakerootlogs and taskfn and taskfn in self.fakerootlogs:
3215 fakerootlog = self.fakerootlogs[taskfn]
3216 self.rqexec.runqueue_process_waitpid(task, status, fakerootlog=fakerootlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003217 found = True
3218 self.queue = self.queue[index+11:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003219 index = self.queue.find(b"</exitcode>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003220 return (end > start)
3221
3222 def close(self):
3223 while self.read():
3224 continue
Andrew Geissler595f6302022-01-24 19:11:47 +00003225 if self.queue:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003226 print("Warning, worker left partial message: %s" % self.queue)
3227 self.input.close()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003228
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003229def get_setscene_enforce_ignore_tasks(d, targets):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05003230 if d.getVar('BB_SETSCENE_ENFORCE') != '1':
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003231 return None
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003232 ignore_tasks = (d.getVar("BB_SETSCENE_ENFORCE_IGNORE_TASKS") or "").split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003233 outlist = []
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003234 for item in ignore_tasks[:]:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003235 if item.startswith('%:'):
Andrew Geisslerc9f78652020-09-18 14:11:35 -05003236 for (mc, target, task, fn) in targets:
3237 outlist.append(target + ':' + item.split(':')[1])
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003238 else:
3239 outlist.append(item)
3240 return outlist
3241
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003242def check_setscene_enforce_ignore_tasks(pn, taskname, ignore_tasks):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003243 import fnmatch
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003244 if ignore_tasks is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003245 item = '%s:%s' % (pn, taskname)
Andrew Geissler7e0e3c02022-02-25 20:34:39 +00003246 for ignore_tasks in ignore_tasks:
3247 if fnmatch.fnmatch(item, ignore_tasks):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06003248 return True
3249 return False
3250 return True