diff options
| author | Richard Purdie <richard@openedhand.com> | 2007-04-01 15:04:49 +0000 | 
|---|---|---|
| committer | Richard Purdie <richard@openedhand.com> | 2007-04-01 15:04:49 +0000 | 
| commit | 7371e6323c3fb6b0545712e3cf84606644073e77 (patch) | |
| tree | e08f25669ec0f0e9d11334909f3b68c0ab6aca19 /bitbake/lib/bb/runqueue.py | |
| parent | 8b36dc217443aeeec8493d39561d2bb010336774 (diff) | |
| download | poky-7371e6323c3fb6b0545712e3cf84606644073e77.tar.gz | |
bitbake: Update to 1.8.1 (inc. various bug fixes, epoch support)
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@1419 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake/lib/bb/runqueue.py')
| -rw-r--r-- | bitbake/lib/bb/runqueue.py | 355 | 
1 files changed, 201 insertions, 154 deletions
diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py index ec94b0f8ba..059f800b65 100644 --- a/bitbake/lib/bb/runqueue.py +++ b/bitbake/lib/bb/runqueue.py  | |||
| @@ -25,20 +25,47 @@ Handles preparation and execution of a queue of tasks | |||
| 25 | from bb import msg, data, fetch, event, mkdirhier, utils | 25 | from bb import msg, data, fetch, event, mkdirhier, utils | 
| 26 | from sets import Set | 26 | from sets import Set | 
| 27 | import bb, os, sys | 27 | import bb, os, sys | 
| 28 | import signal | ||
| 28 | 29 | ||
| 29 | class TaskFailure(Exception): | 30 | class TaskFailure(Exception): | 
| 30 | """Exception raised when a task in a runqueue fails""" | 31 | """Exception raised when a task in a runqueue fails""" | 
| 31 | def __init__(self, x): | 32 | def __init__(self, x): | 
| 32 | self.args = x | 33 | self.args = x | 
| 33 | 34 | ||
| 35 | |||
| 36 | class RunQueueStats: | ||
| 37 | """ | ||
| 38 | Holds statistics on the tasks handled by the associated runQueue | ||
| 39 | """ | ||
| 40 | def __init__(self): | ||
| 41 | self.completed = 0 | ||
| 42 | self.skipped = 0 | ||
| 43 | self.failed = 0 | ||
| 44 | |||
| 45 | def taskFailed(self): | ||
| 46 | self.failed = self.failed + 1 | ||
| 47 | |||
| 48 | def taskCompleted(self): | ||
| 49 | self.completed = self.completed + 1 | ||
| 50 | |||
| 51 | def taskSkipped(self): | ||
| 52 | self.skipped = self.skipped + 1 | ||
| 53 | |||
| 34 | class RunQueue: | 54 | class RunQueue: | 
| 35 | """ | 55 | """ | 
| 36 | BitBake Run Queue implementation | 56 | BitBake Run Queue implementation | 
| 37 | """ | 57 | """ | 
| 38 | def __init__(self): | 58 | def __init__(self, cooker, cfgData, dataCache, taskData, targets): | 
| 39 | self.reset_runqueue() | 59 | self.reset_runqueue() | 
| 60 | self.cooker = cooker | ||
| 61 | self.dataCache = dataCache | ||
| 62 | self.taskData = taskData | ||
| 63 | self.targets = targets | ||
| 64 | |||
| 65 | self.number_tasks = int(bb.data.getVar("BB_NUMBER_THREADS", cfgData) or 1) | ||
| 40 | 66 | ||
| 41 | def reset_runqueue(self): | 67 | def reset_runqueue(self): | 
| 68 | |||
| 42 | self.runq_fnid = [] | 69 | self.runq_fnid = [] | 
| 43 | self.runq_task = [] | 70 | self.runq_task = [] | 
| 44 | self.runq_depends = [] | 71 | self.runq_depends = [] | 
| @@ -46,16 +73,15 @@ class RunQueue: | |||
| 46 | self.runq_weight = [] | 73 | self.runq_weight = [] | 
| 47 | self.prio_map = [] | 74 | self.prio_map = [] | 
| 48 | 75 | ||
| 49 | def get_user_idstring(self, task, taskData): | 76 | def get_user_idstring(self, task): | 
| 50 | fn = taskData.fn_index[self.runq_fnid[task]] | 77 | fn = self.taskData.fn_index[self.runq_fnid[task]] | 
| 51 | taskname = self.runq_task[task] | 78 | taskname = self.runq_task[task] | 
| 52 | return "%s, %s" % (fn, taskname) | 79 | return "%s, %s" % (fn, taskname) | 
| 53 | 80 | ||
| 54 | def prepare_runqueue(self, cooker, cfgData, dataCache, taskData, targets): | 81 | def prepare_runqueue(self): | 
| 55 | """ | 82 | """ | 
| 56 | Turn a set of taskData into a RunQueue and compute data needed | 83 | Turn a set of taskData into a RunQueue and compute data needed | 
| 57 | to optimise the execution order. | 84 | to optimise the execution order. | 
| 58 | targets is list of paired values - a provider name and the task to run | ||
| 59 | """ | 85 | """ | 
| 60 | 86 | ||
| 61 | depends = [] | 87 | depends = [] | 
| @@ -63,12 +89,14 @@ class RunQueue: | |||
| 63 | runq_build = [] | 89 | runq_build = [] | 
| 64 | runq_done = [] | 90 | runq_done = [] | 
| 65 | 91 | ||
| 92 | taskData = self.taskData | ||
| 93 | |||
| 66 | bb.msg.note(1, bb.msg.domain.RunQueue, "Preparing Runqueue") | 94 | bb.msg.note(1, bb.msg.domain.RunQueue, "Preparing Runqueue") | 
| 67 | 95 | ||
| 68 | for task in range(len(taskData.tasks_name)): | 96 | for task in range(len(taskData.tasks_name)): | 
| 69 | fnid = taskData.tasks_fnid[task] | 97 | fnid = taskData.tasks_fnid[task] | 
| 70 | fn = taskData.fn_index[fnid] | 98 | fn = taskData.fn_index[fnid] | 
| 71 | task_deps = dataCache.task_deps[fn] | 99 | task_deps = self.dataCache.task_deps[fn] | 
| 72 | 100 | ||
| 73 | if fnid not in taskData.failed_fnids: | 101 | if fnid not in taskData.failed_fnids: | 
| 74 | 102 | ||
| @@ -94,6 +122,15 @@ class RunQueue: | |||
| 94 | dep = taskData.fn_index[depdata] | 122 | dep = taskData.fn_index[depdata] | 
| 95 | depends.append(taskData.gettask_id(dep, taskname)) | 123 | depends.append(taskData.gettask_id(dep, taskname)) | 
| 96 | 124 | ||
| 125 | idepends = taskData.tasks_idepends[task] | ||
| 126 | for idepend in idepends: | ||
| 127 | depid = int(idepend.split(":")[0]) | ||
| 128 | if depid in taskData.build_targets: | ||
| 129 | depdata = taskData.build_targets[depid][0] | ||
| 130 | if depdata: | ||
| 131 | dep = taskData.fn_index[depdata] | ||
| 132 | depends.append(taskData.gettask_id(dep, idepend.split(":")[1])) | ||
| 133 | |||
| 97 | def add_recursive_build(depid): | 134 | def add_recursive_build(depid): | 
| 98 | """ | 135 | """ | 
| 99 | Add build depends of depid to depends | 136 | Add build depends of depid to depends | 
| @@ -197,7 +234,7 @@ class RunQueue: | |||
| 197 | for depend in depends: | 234 | for depend in depends: | 
| 198 | mark_active(depend, depth+1) | 235 | mark_active(depend, depth+1) | 
| 199 | 236 | ||
| 200 | for target in targets: | 237 | for target in self.targets: | 
| 201 | targetid = taskData.getbuild_id(target[0]) | 238 | targetid = taskData.getbuild_id(target[0]) | 
| 202 | 239 | ||
| 203 | if targetid not in taskData.build_targets: | 240 | if targetid not in taskData.build_targets: | 
| @@ -209,10 +246,10 @@ class RunQueue: | |||
| 209 | fnid = taskData.build_targets[targetid][0] | 246 | fnid = taskData.build_targets[targetid][0] | 
| 210 | 247 | ||
| 211 | # Remove stamps for targets if force mode active | 248 | # Remove stamps for targets if force mode active | 
| 212 | if cooker.configuration.force: | 249 | if self.cooker.configuration.force: | 
| 213 | fn = taskData.fn_index[fnid] | 250 | fn = taskData.fn_index[fnid] | 
| 214 | bb.msg.note(2, bb.msg.domain.RunQueue, "Remove stamp %s, %s" % (target[1], fn)) | 251 | bb.msg.note(2, bb.msg.domain.RunQueue, "Remove stamp %s, %s" % (target[1], fn)) | 
| 215 | bb.build.del_stamp(target[1], dataCache, fn) | 252 | bb.build.del_stamp(target[1], self.dataCache, fn) | 
| 216 | 253 | ||
| 217 | if fnid in taskData.failed_fnids: | 254 | if fnid in taskData.failed_fnids: | 
| 218 | continue | 255 | continue | 
| @@ -299,18 +336,18 @@ class RunQueue: | |||
| 299 | seen.append(taskid) | 336 | seen.append(taskid) | 
| 300 | for revdep in self.runq_revdeps[taskid]: | 337 | for revdep in self.runq_revdeps[taskid]: | 
| 301 | if runq_done[revdep] == 0 and revdep not in seen and not finish: | 338 | if runq_done[revdep] == 0 and revdep not in seen and not finish: | 
| 302 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) (depends: %s)" % (revdep, self.get_user_idstring(revdep, taskData), self.runq_depends[revdep])) | 339 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) (depends: %s)" % (revdep, self.get_user_idstring(revdep), self.runq_depends[revdep])) | 
| 303 | if revdep in deps_seen: | 340 | if revdep in deps_seen: | 
| 304 | bb.msg.error(bb.msg.domain.RunQueue, "Chain ends at Task %s (%s)" % (revdep, self.get_user_idstring(revdep, taskData))) | 341 | bb.msg.error(bb.msg.domain.RunQueue, "Chain ends at Task %s (%s)" % (revdep, self.get_user_idstring(revdep))) | 
| 305 | finish = True | 342 | finish = True | 
| 306 | return | 343 | return | 
| 307 | for dep in self.runq_depends[revdep]: | 344 | for dep in self.runq_depends[revdep]: | 
| 308 | deps_seen.append(dep) | 345 | deps_seen.append(dep) | 
| 309 | print_chain(revdep, finish) | 346 | print_chain(revdep, finish) | 
| 310 | print_chain(task, False) | 347 | print_chain(task, False) | 
| 311 | bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) not processed!\nThis is probably a circular dependency (the chain might be printed above)." % (task, self.get_user_idstring(task, taskData))) | 348 | bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) not processed!\nThis is probably a circular dependency (the chain might be printed above)." % (task, self.get_user_idstring(task))) | 
| 312 | if runq_weight1[task] != 0: | 349 | if runq_weight1[task] != 0: | 
| 313 | bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) count not zero!" % (task, self.get_user_idstring(task, taskData))) | 350 | bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) count not zero!" % (task, self.get_user_idstring(task))) | 
| 314 | 351 | ||
| 315 | # Make a weight sorted map | 352 | # Make a weight sorted map | 
| 316 | from copy import deepcopy | 353 | from copy import deepcopy | 
| @@ -328,7 +365,7 @@ class RunQueue: | |||
| 328 | 365 | ||
| 329 | #self.dump_data(taskData) | 366 | #self.dump_data(taskData) | 
| 330 | 367 | ||
| 331 | def execute_runqueue(self, cooker, cfgData, dataCache, taskData, runlist): | 368 | def execute_runqueue(self): | 
| 332 | """ | 369 | """ | 
| 333 | Run the tasks in a queue prepared by prepare_runqueue | 370 | Run the tasks in a queue prepared by prepare_runqueue | 
| 334 | Upon failure, optionally try to recover the build using any alternate providers | 371 | Upon failure, optionally try to recover the build using any alternate providers | 
| @@ -337,35 +374,86 @@ class RunQueue: | |||
| 337 | 374 | ||
| 338 | failures = 0 | 375 | failures = 0 | 
| 339 | while 1: | 376 | while 1: | 
| 340 | failed_fnids = self.execute_runqueue_internal(cooker, cfgData, dataCache, taskData) | 377 | failed_fnids = [] | 
| 378 | try: | ||
| 379 | self.execute_runqueue_internal() | ||
| 380 | finally: | ||
| 381 | if self.master_process: | ||
| 382 | failed_fnids = self.finish_runqueue() | ||
| 341 | if len(failed_fnids) == 0: | 383 | if len(failed_fnids) == 0: | 
| 342 | return failures | 384 | return failures | 
| 343 | if taskData.abort: | 385 | if self.taskData.abort: | 
| 344 | raise bb.runqueue.TaskFailure(failed_fnids) | 386 | raise bb.runqueue.TaskFailure(failed_fnids) | 
| 345 | for fnid in failed_fnids: | 387 | for fnid in failed_fnids: | 
| 346 | #print "Failure: %s %s %s" % (fnid, taskData.fn_index[fnid], self.runq_task[fnid]) | 388 | #print "Failure: %s %s %s" % (fnid, self.taskData.fn_index[fnid], self.runq_task[fnid]) | 
| 347 | taskData.fail_fnid(fnid) | 389 | self.taskData.fail_fnid(fnid) | 
| 348 | failures = failures + 1 | 390 | failures = failures + 1 | 
| 349 | self.reset_runqueue() | 391 | self.reset_runqueue() | 
| 350 | self.prepare_runqueue(cooker, cfgData, dataCache, taskData, runlist) | 392 | self.prepare_runqueue() | 
| 393 | |||
| 394 | def execute_runqueue_initVars(self): | ||
| 395 | |||
| 396 | self.stats = RunQueueStats() | ||
| 397 | |||
| 398 | self.active_builds = 0 | ||
| 399 | self.runq_buildable = [] | ||
| 400 | self.runq_running = [] | ||
| 401 | self.runq_complete = [] | ||
| 402 | self.build_pids = {} | ||
| 403 | self.failed_fnids = [] | ||
| 404 | self.master_process = True | ||
| 351 | 405 | ||
| 352 | def execute_runqueue_internal(self, cooker, cfgData, dataCache, taskData): | 406 | # Mark initial buildable tasks | 
| 407 | for task in range(len(self.runq_fnid)): | ||
| 408 | self.runq_running.append(0) | ||
| 409 | self.runq_complete.append(0) | ||
| 410 | if len(self.runq_depends[task]) == 0: | ||
| 411 | self.runq_buildable.append(1) | ||
| 412 | else: | ||
| 413 | self.runq_buildable.append(0) | ||
| 414 | |||
| 415 | def task_complete(self, task): | ||
| 416 | """ | ||
| 417 | Mark a task as completed | ||
| 418 | Look at the reverse dependencies and mark any task with | ||
| 419 | completed dependencies as buildable | ||
| 420 | """ | ||
| 421 | self.runq_complete[task] = 1 | ||
| 422 | for revdep in self.runq_revdeps[task]: | ||
| 423 | if self.runq_running[revdep] == 1: | ||
| 424 | continue | ||
| 425 | if self.runq_buildable[revdep] == 1: | ||
| 426 | continue | ||
| 427 | alldeps = 1 | ||
| 428 | for dep in self.runq_depends[revdep]: | ||
| 429 | if self.runq_complete[dep] != 1: | ||
| 430 | alldeps = 0 | ||
| 431 | if alldeps == 1: | ||
| 432 | self.runq_buildable[revdep] = 1 | ||
| 433 | fn = self.taskData.fn_index[self.runq_fnid[revdep]] | ||
| 434 | taskname = self.runq_task[revdep] | ||
| 435 | bb.msg.debug(1, bb.msg.domain.RunQueue, "Marking task %s (%s, %s) as buildable" % (revdep, fn, taskname)) | ||
| 436 | |||
| 437 | def get_next_task(self): | ||
| 438 | """ | ||
| 439 | Return the id of the highest priority task that is buildable | ||
| 440 | """ | ||
| 441 | for task1 in range(len(self.runq_fnid)): | ||
| 442 | task = self.prio_map[task1] | ||
| 443 | if self.runq_running[task] == 1: | ||
| 444 | continue | ||
| 445 | if self.runq_buildable[task] == 1: | ||
| 446 | return task | ||
| 447 | return None | ||
| 448 | |||
| 449 | def execute_runqueue_internal(self): | ||
| 353 | """ | 450 | """ | 
| 354 | Run the tasks in a queue prepared by prepare_runqueue | 451 | Run the tasks in a queue prepared by prepare_runqueue | 
| 355 | """ | 452 | """ | 
| 356 | import signal | ||
| 357 | 453 | ||
| 358 | bb.msg.note(1, bb.msg.domain.RunQueue, "Executing runqueue") | 454 | bb.msg.note(1, bb.msg.domain.RunQueue, "Executing runqueue") | 
| 359 | 455 | ||
| 360 | active_builds = 0 | 456 | self.execute_runqueue_initVars() | 
| 361 | tasks_completed = 0 | ||
| 362 | tasks_skipped = 0 | ||
| 363 | |||
| 364 | runq_buildable = [] | ||
| 365 | runq_running = [] | ||
| 366 | runq_complete = [] | ||
| 367 | build_pids = {} | ||
| 368 | failed_fnids = [] | ||
| 369 | 457 | ||
| 370 | if len(self.runq_fnid) == 0: | 458 | if len(self.runq_fnid) == 0: | 
| 371 | # nothing to do | 459 | # nothing to do | 
| @@ -374,144 +462,103 @@ class RunQueue: | |||
| 374 | def sigint_handler(signum, frame): | 462 | def sigint_handler(signum, frame): | 
| 375 | raise KeyboardInterrupt | 463 | raise KeyboardInterrupt | 
| 376 | 464 | ||
| 377 | def get_next_task(data): | 465 | while True: | 
| 378 | """ | 466 | task = self.get_next_task() | 
| 379 | Return the id of the highest priority task that is buildable | 467 | if task is not None: | 
| 380 | """ | 468 | fn = self.taskData.fn_index[self.runq_fnid[task]] | 
| 381 | for task1 in range(len(data.runq_fnid)): | 469 | |
| 382 | task = data.prio_map[task1] | 470 | taskname = self.runq_task[task] | 
| 383 | if runq_running[task] == 1: | 471 | if bb.build.stamp_is_current(taskname, self.dataCache, fn): | 
| 472 | bb.msg.debug(2, bb.msg.domain.RunQueue, "Stamp current task %s (%s)" % (task, self.get_user_idstring(task))) | ||
| 473 | self.runq_running[task] = 1 | ||
| 474 | self.task_complete(task) | ||
| 475 | self.stats.taskCompleted() | ||
| 476 | self.stats.taskSkipped() | ||
| 384 | continue | 477 | continue | 
| 385 | if runq_buildable[task] == 1: | ||
| 386 | return task | ||
| 387 | return None | ||
| 388 | 478 | ||
| 389 | def task_complete(data, task): | 479 | bb.msg.note(1, bb.msg.domain.RunQueue, "Running task %d of %d (ID: %s, %s)" % (self.stats.completed + self.active_builds + 1, len(self.runq_fnid), task, self.get_user_idstring(task))) | 
| 390 | """ | 480 | try: | 
| 391 | Mark a task as completed | 481 | pid = os.fork() | 
| 392 | Look at the reverse dependencies and mark any task with | 482 | except OSError, e: | 
| 393 | completed dependencies as buildable | 483 | bb.msg.fatal(bb.msg.domain.RunQueue, "fork failed: %d (%s)" % (e.errno, e.strerror)) | 
| 394 | """ | 484 | if pid == 0: | 
| 395 | runq_complete[task] = 1 | 485 | # Bypass master process' handling | 
| 396 | for revdep in data.runq_revdeps[task]: | 486 | self.master_process = False | 
| 397 | if runq_running[revdep] == 1: | 487 | # Stop Ctrl+C being sent to children | 
| 398 | continue | 488 | # signal.signal(signal.SIGINT, signal.SIG_IGN) | 
| 399 | if runq_buildable[revdep] == 1: | 489 | # Make the child the process group leader | 
| 490 | os.setpgid(0, 0) | ||
| 491 | sys.stdin = open('/dev/null', 'r') | ||
| 492 | self.cooker.configuration.cmd = taskname[3:] | ||
| 493 | try: | ||
| 494 | self.cooker.tryBuild(fn, False) | ||
| 495 | except bb.build.EventException: | ||
| 496 | bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed") | ||
| 497 | sys.exit(1) | ||
| 498 | except: | ||
| 499 | bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed") | ||
| 500 | raise | ||
| 501 | sys.exit(0) | ||
| 502 | self.build_pids[pid] = task | ||
| 503 | self.runq_running[task] = 1 | ||
| 504 | self.active_builds = self.active_builds + 1 | ||
| 505 | if self.active_builds < self.number_tasks: | ||
| 400 | continue | 506 | continue | 
| 401 | alldeps = 1 | 507 | if self.active_builds > 0: | 
| 402 | for dep in data.runq_depends[revdep]: | 508 | result = os.waitpid(-1, 0) | 
| 403 | if runq_complete[dep] != 1: | 509 | self.active_builds = self.active_builds - 1 | 
| 404 | alldeps = 0 | 510 | task = self.build_pids[result[0]] | 
| 405 | if alldeps == 1: | 511 | if result[1] != 0: | 
| 406 | runq_buildable[revdep] = 1 | 512 | del self.build_pids[result[0]] | 
| 407 | fn = taskData.fn_index[self.runq_fnid[revdep]] | 513 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) failed" % (task, self.get_user_idstring(task))) | 
| 408 | taskname = self.runq_task[revdep] | 514 | self.failed_fnids.append(self.runq_fnid[task]) | 
| 409 | bb.msg.debug(1, bb.msg.domain.RunQueue, "Marking task %s (%s, %s) as buildable" % (revdep, fn, taskname)) | 515 | self.stats.taskFailed() | 
| 410 | 516 | break | |
| 411 | # Mark initial buildable tasks | 517 | self.task_complete(task) | 
| 412 | for task in range(len(self.runq_fnid)): | 518 | self.stats.taskCompleted() | 
| 413 | runq_running.append(0) | 519 | del self.build_pids[result[0]] | 
| 414 | runq_complete.append(0) | 520 | continue | 
| 415 | if len(self.runq_depends[task]) == 0: | 521 | return | 
| 416 | runq_buildable.append(1) | ||
| 417 | else: | ||
| 418 | runq_buildable.append(0) | ||
| 419 | |||
| 420 | |||
| 421 | number_tasks = int(bb.data.getVar("BB_NUMBER_THREADS", cfgData) or 1) | ||
| 422 | 522 | ||
| 523 | def finish_runqueue(self): | ||
| 423 | try: | 524 | try: | 
| 424 | while 1: | 525 | while self.active_builds > 0: | 
| 425 | task = get_next_task(self) | 526 | bb.msg.note(1, bb.msg.domain.RunQueue, "Waiting for %s active tasks to finish" % self.active_builds) | 
| 426 | if task is not None: | 527 | tasknum = 1 | 
| 427 | fn = taskData.fn_index[self.runq_fnid[task]] | 528 | for k, v in self.build_pids.iteritems(): | 
| 428 | taskname = self.runq_task[task] | 529 | bb.msg.note(1, bb.msg.domain.RunQueue, "%s: %s (%s)" % (tasknum, self.get_user_idstring(v), k)) | 
| 429 | 530 | tasknum = tasknum + 1 | |
| 430 | if bb.build.stamp_is_current(taskname, dataCache, fn): | 531 | result = os.waitpid(-1, 0) | 
| 431 | bb.msg.debug(2, bb.msg.domain.RunQueue, "Stamp current task %s (%s)" % (task, self.get_user_idstring(task, taskData))) | 532 | task = self.build_pids[result[0]] | 
| 432 | runq_running[task] = 1 | 533 | if result[1] != 0: | 
| 433 | task_complete(self, task) | 534 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) failed" % (task, self.get_user_idstring(task))) | 
| 434 | tasks_completed = tasks_completed + 1 | 535 | self.failed_fnids.append(self.runq_fnid[task]) | 
| 435 | tasks_skipped = tasks_skipped + 1 | 536 | self.stats.taskFailed() | 
| 436 | continue | 537 | del self.build_pids[result[0]] | 
| 437 | 538 | self.active_builds = self.active_builds - 1 | |
| 438 | bb.msg.note(1, bb.msg.domain.RunQueue, "Running task %d of %d (ID: %s, %s)" % (tasks_completed + active_builds + 1, len(self.runq_fnid), task, self.get_user_idstring(task, taskData))) | 539 | if len(self.failed_fnids) > 0: | 
| 439 | try: | 540 | return self.failed_fnids | 
| 440 | pid = os.fork() | 541 | except KeyboardInterrupt: | 
| 441 | except OSError, e: | 542 | bb.msg.note(1, bb.msg.domain.RunQueue, "Sending SIGINT to remaining %s tasks" % self.active_builds) | 
| 442 | bb.msg.fatal(bb.msg.domain.RunQueue, "fork failed: %d (%s)" % (e.errno, e.strerror)) | 543 | for k, v in self.build_pids.iteritems(): | 
| 443 | if pid == 0: | 544 | try: | 
| 444 | # Bypass finally below | ||
| 445 | active_builds = 0 | ||
| 446 | # Stop Ctrl+C being sent to children | ||
| 447 | # signal.signal(signal.SIGINT, signal.SIG_IGN) | ||
| 448 | # Make the child the process group leader | ||
| 449 | os.setpgid(0, 0) | ||
| 450 | sys.stdin = open('/dev/null', 'r') | ||
| 451 | cooker.configuration.cmd = taskname[3:] | ||
| 452 | try: | ||
| 453 | cooker.tryBuild(fn, False) | ||
| 454 | except bb.build.EventException: | ||
| 455 | bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed") | ||
| 456 | sys.exit(1) | ||
| 457 | except: | ||
| 458 | bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed") | ||
| 459 | raise | ||
| 460 | sys.exit(0) | ||
| 461 | build_pids[pid] = task | ||
| 462 | runq_running[task] = 1 | ||
| 463 | active_builds = active_builds + 1 | ||
| 464 | if active_builds < number_tasks: | ||
| 465 | continue | ||
| 466 | if active_builds > 0: | ||
| 467 | result = os.waitpid(-1, 0) | ||
| 468 | active_builds = active_builds - 1 | ||
| 469 | task = build_pids[result[0]] | ||
| 470 | if result[1] != 0: | ||
| 471 | del build_pids[result[0]] | ||
| 472 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) failed" % (task, self.get_user_idstring(task, taskData))) | ||
| 473 | failed_fnids.append(self.runq_fnid[task]) | ||
| 474 | break | ||
| 475 | task_complete(self, task) | ||
| 476 | tasks_completed = tasks_completed + 1 | ||
| 477 | del build_pids[result[0]] | ||
| 478 | continue | ||
| 479 | break | ||
| 480 | finally: | ||
| 481 | try: | ||
| 482 | while active_builds > 0: | ||
| 483 | bb.msg.note(1, bb.msg.domain.RunQueue, "Waiting for %s active tasks to finish" % active_builds) | ||
| 484 | tasknum = 1 | ||
| 485 | for k, v in build_pids.iteritems(): | ||
| 486 | bb.msg.note(1, bb.msg.domain.RunQueue, "%s: %s (%s)" % (tasknum, self.get_user_idstring(v, taskData), k)) | ||
| 487 | tasknum = tasknum + 1 | ||
| 488 | result = os.waitpid(-1, 0) | ||
| 489 | task = build_pids[result[0]] | ||
| 490 | if result[1] != 0: | ||
| 491 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) failed" % (task, self.get_user_idstring(task, taskData))) | ||
| 492 | failed_fnids.append(self.runq_fnid[task]) | ||
| 493 | del build_pids[result[0]] | ||
| 494 | active_builds = active_builds - 1 | ||
| 495 | if len(failed_fnids) > 0: | ||
| 496 | return failed_fnids | ||
| 497 | except: | ||
| 498 | bb.msg.note(1, bb.msg.domain.RunQueue, "Sending SIGINT to remaining %s tasks" % active_builds) | ||
| 499 | for k, v in build_pids.iteritems(): | ||
| 500 | os.kill(-k, signal.SIGINT) | 545 | os.kill(-k, signal.SIGINT) | 
| 501 | raise | 546 | except: | 
| 547 | pass | ||
| 548 | raise | ||
| 502 | 549 | ||
| 503 | # Sanity Checks | 550 | # Sanity Checks | 
| 504 | for task in range(len(self.runq_fnid)): | 551 | for task in range(len(self.runq_fnid)): | 
| 505 | if runq_buildable[task] == 0: | 552 | if self.runq_buildable[task] == 0: | 
| 506 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s never buildable!" % task) | 553 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s never buildable!" % task) | 
| 507 | if runq_running[task] == 0: | 554 | if self.runq_running[task] == 0: | 
| 508 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s never ran!" % task) | 555 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s never ran!" % task) | 
| 509 | if runq_complete[task] == 0: | 556 | if self.runq_complete[task] == 0: | 
| 510 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s never completed!" % task) | 557 | bb.msg.error(bb.msg.domain.RunQueue, "Task %s never completed!" % task) | 
| 511 | 558 | ||
| 512 | bb.msg.note(1, bb.msg.domain.RunQueue, "Tasks Summary: Attempted %d tasks of which %d didn't need to be rerun and %d failed." % (tasks_completed, tasks_skipped, len(failed_fnids))) | 559 | bb.msg.note(1, bb.msg.domain.RunQueue, "Tasks Summary: Attempted %d tasks of which %d didn't need to be rerun and %d failed." % (self.stats.completed, self.stats.skipped, self.stats.failed)) | 
| 513 | 560 | ||
| 514 | return failed_fnids | 561 | return self.failed_fnids | 
| 515 | 562 | ||
| 516 | def dump_data(self, taskQueue): | 563 | def dump_data(self, taskQueue): | 
| 517 | """ | 564 | """ | 
