1190064b4SSimon Glass# Copyright (c) 2014 Google, Inc 2190064b4SSimon Glass# 3190064b4SSimon Glass# SPDX-License-Identifier: GPL-2.0+ 4190064b4SSimon Glass# 5190064b4SSimon Glass 6190064b4SSimon Glassimport errno 7190064b4SSimon Glassimport glob 8190064b4SSimon Glassimport os 9190064b4SSimon Glassimport shutil 10190064b4SSimon Glassimport threading 11190064b4SSimon Glass 12190064b4SSimon Glassimport command 13190064b4SSimon Glassimport gitutil 14190064b4SSimon Glass 15f3d015cbSThierry Redingdef Mkdir(dirname, parents = False): 16190064b4SSimon Glass """Make a directory if it doesn't already exist. 17190064b4SSimon Glass 18190064b4SSimon Glass Args: 19190064b4SSimon Glass dirname: Directory to create 20190064b4SSimon Glass """ 21190064b4SSimon Glass try: 22f3d015cbSThierry Reding if parents: 23f3d015cbSThierry Reding os.makedirs(dirname) 24f3d015cbSThierry Reding else: 25190064b4SSimon Glass os.mkdir(dirname) 26190064b4SSimon Glass except OSError as err: 27190064b4SSimon Glass if err.errno == errno.EEXIST: 28190064b4SSimon Glass pass 29190064b4SSimon Glass else: 30190064b4SSimon Glass raise 31190064b4SSimon Glass 32190064b4SSimon Glassclass BuilderJob: 33190064b4SSimon Glass """Holds information about a job to be performed by a thread 34190064b4SSimon Glass 35190064b4SSimon Glass Members: 36190064b4SSimon Glass board: Board object to build 37190064b4SSimon Glass commits: List of commit options to build. 38190064b4SSimon Glass """ 39190064b4SSimon Glass def __init__(self): 40190064b4SSimon Glass self.board = None 41190064b4SSimon Glass self.commits = [] 42190064b4SSimon Glass 43190064b4SSimon Glass 44190064b4SSimon Glassclass ResultThread(threading.Thread): 45190064b4SSimon Glass """This thread processes results from builder threads. 46190064b4SSimon Glass 47190064b4SSimon Glass It simply passes the results on to the builder. There is only one 48190064b4SSimon Glass result thread, and this helps to serialise the build output. 49190064b4SSimon Glass """ 50190064b4SSimon Glass def __init__(self, builder): 51190064b4SSimon Glass """Set up a new result thread 52190064b4SSimon Glass 53190064b4SSimon Glass Args: 54190064b4SSimon Glass builder: Builder which will be sent each result 55190064b4SSimon Glass """ 56190064b4SSimon Glass threading.Thread.__init__(self) 57190064b4SSimon Glass self.builder = builder 58190064b4SSimon Glass 59190064b4SSimon Glass def run(self): 60190064b4SSimon Glass """Called to start up the result thread. 61190064b4SSimon Glass 62190064b4SSimon Glass We collect the next result job and pass it on to the build. 63190064b4SSimon Glass """ 64190064b4SSimon Glass while True: 65190064b4SSimon Glass result = self.builder.out_queue.get() 66190064b4SSimon Glass self.builder.ProcessResult(result) 67190064b4SSimon Glass self.builder.out_queue.task_done() 68190064b4SSimon Glass 69190064b4SSimon Glass 70190064b4SSimon Glassclass BuilderThread(threading.Thread): 71190064b4SSimon Glass """This thread builds U-Boot for a particular board. 72190064b4SSimon Glass 73190064b4SSimon Glass An input queue provides each new job. We run 'make' to build U-Boot 74190064b4SSimon Glass and then pass the results on to the output queue. 75190064b4SSimon Glass 76190064b4SSimon Glass Members: 77190064b4SSimon Glass builder: The builder which contains information we might need 78190064b4SSimon Glass thread_num: Our thread number (0-n-1), used to decide on a 79190064b4SSimon Glass temporary directory 80190064b4SSimon Glass """ 81190064b4SSimon Glass def __init__(self, builder, thread_num): 82190064b4SSimon Glass """Set up a new builder thread""" 83190064b4SSimon Glass threading.Thread.__init__(self) 84190064b4SSimon Glass self.builder = builder 85190064b4SSimon Glass self.thread_num = thread_num 86190064b4SSimon Glass 87190064b4SSimon Glass def Make(self, commit, brd, stage, cwd, *args, **kwargs): 88190064b4SSimon Glass """Run 'make' on a particular commit and board. 89190064b4SSimon Glass 90190064b4SSimon Glass The source code will already be checked out, so the 'commit' 91190064b4SSimon Glass argument is only for information. 92190064b4SSimon Glass 93190064b4SSimon Glass Args: 94190064b4SSimon Glass commit: Commit object that is being built 95190064b4SSimon Glass brd: Board object that is being built 96190064b4SSimon Glass stage: Stage of the build. Valid stages are: 97fd18a89eSRoger Meier mrproper - can be called to clean source 98190064b4SSimon Glass config - called to configure for a board 99190064b4SSimon Glass build - the main make invocation - it does the build 100190064b4SSimon Glass args: A list of arguments to pass to 'make' 101190064b4SSimon Glass kwargs: A list of keyword arguments to pass to command.RunPipe() 102190064b4SSimon Glass 103190064b4SSimon Glass Returns: 104190064b4SSimon Glass CommandResult object 105190064b4SSimon Glass """ 106190064b4SSimon Glass return self.builder.do_make(commit, brd, stage, cwd, *args, 107190064b4SSimon Glass **kwargs) 108190064b4SSimon Glass 109190064b4SSimon Glass def RunCommit(self, commit_upto, brd, work_dir, do_config, force_build, 110190064b4SSimon Glass force_build_failures): 111190064b4SSimon Glass """Build a particular commit. 112190064b4SSimon Glass 113190064b4SSimon Glass If the build is already done, and we are not forcing a build, we skip 114190064b4SSimon Glass the build and just return the previously-saved results. 115190064b4SSimon Glass 116190064b4SSimon Glass Args: 117190064b4SSimon Glass commit_upto: Commit number to build (0...n-1) 118190064b4SSimon Glass brd: Board object to build 119190064b4SSimon Glass work_dir: Directory to which the source will be checked out 120190064b4SSimon Glass do_config: True to run a make <board>_defconfig on the source 121190064b4SSimon Glass force_build: Force a build even if one was previously done 122190064b4SSimon Glass force_build_failures: Force a bulid if the previous result showed 123190064b4SSimon Glass failure 124190064b4SSimon Glass 125190064b4SSimon Glass Returns: 126190064b4SSimon Glass tuple containing: 127190064b4SSimon Glass - CommandResult object containing the results of the build 128190064b4SSimon Glass - boolean indicating whether 'make config' is still needed 129190064b4SSimon Glass """ 130190064b4SSimon Glass # Create a default result - it will be overwritte by the call to 131190064b4SSimon Glass # self.Make() below, in the event that we do a build. 132190064b4SSimon Glass result = command.CommandResult() 133190064b4SSimon Glass result.return_code = 0 134190064b4SSimon Glass if self.builder.in_tree: 135190064b4SSimon Glass out_dir = work_dir 136190064b4SSimon Glass else: 137190064b4SSimon Glass out_dir = os.path.join(work_dir, 'build') 138190064b4SSimon Glass 139190064b4SSimon Glass # Check if the job was already completed last time 140190064b4SSimon Glass done_file = self.builder.GetDoneFile(commit_upto, brd.target) 141190064b4SSimon Glass result.already_done = os.path.exists(done_file) 142190064b4SSimon Glass will_build = (force_build or force_build_failures or 143190064b4SSimon Glass not result.already_done) 144fb3954f9SSimon Glass if result.already_done: 145190064b4SSimon Glass # Get the return code from that build and use it 146190064b4SSimon Glass with open(done_file, 'r') as fd: 147190064b4SSimon Glass result.return_code = int(fd.readline()) 148fb3954f9SSimon Glass if will_build: 149190064b4SSimon Glass err_file = self.builder.GetErrFile(commit_upto, brd.target) 150190064b4SSimon Glass if os.path.exists(err_file) and os.stat(err_file).st_size: 151190064b4SSimon Glass result.stderr = 'bad' 152190064b4SSimon Glass elif not force_build: 153190064b4SSimon Glass # The build passed, so no need to build it again 154190064b4SSimon Glass will_build = False 155190064b4SSimon Glass 156190064b4SSimon Glass if will_build: 157190064b4SSimon Glass # We are going to have to build it. First, get a toolchain 158190064b4SSimon Glass if not self.toolchain: 159190064b4SSimon Glass try: 160190064b4SSimon Glass self.toolchain = self.builder.toolchains.Select(brd.arch) 161190064b4SSimon Glass except ValueError as err: 162190064b4SSimon Glass result.return_code = 10 163190064b4SSimon Glass result.stdout = '' 164190064b4SSimon Glass result.stderr = str(err) 165190064b4SSimon Glass # TODO(sjg@chromium.org): This gets swallowed, but needs 166190064b4SSimon Glass # to be reported. 167190064b4SSimon Glass 168190064b4SSimon Glass if self.toolchain: 169190064b4SSimon Glass # Checkout the right commit 170190064b4SSimon Glass if self.builder.commits: 171190064b4SSimon Glass commit = self.builder.commits[commit_upto] 172190064b4SSimon Glass if self.builder.checkout: 173190064b4SSimon Glass git_dir = os.path.join(work_dir, '.git') 174190064b4SSimon Glass gitutil.Checkout(commit.hash, git_dir, work_dir, 175190064b4SSimon Glass force=True) 176190064b4SSimon Glass else: 177190064b4SSimon Glass commit = 'current' 178190064b4SSimon Glass 179190064b4SSimon Glass # Set up the environment and command line 180bb1501f2SSimon Glass env = self.toolchain.MakeEnvironment(self.builder.full_path) 181190064b4SSimon Glass Mkdir(out_dir) 182190064b4SSimon Glass args = [] 183190064b4SSimon Glass cwd = work_dir 18448c1b6a8SSimon Glass src_dir = os.path.realpath(work_dir) 185190064b4SSimon Glass if not self.builder.in_tree: 186190064b4SSimon Glass if commit_upto is None: 187190064b4SSimon Glass # In this case we are building in the original source 188190064b4SSimon Glass # directory (i.e. the current directory where buildman 189190064b4SSimon Glass # is invoked. The output directory is set to this 190190064b4SSimon Glass # thread's selected work directory. 191190064b4SSimon Glass # 192190064b4SSimon Glass # Symlinks can confuse U-Boot's Makefile since 193190064b4SSimon Glass # we may use '..' in our path, so remove them. 194190064b4SSimon Glass work_dir = os.path.realpath(work_dir) 195190064b4SSimon Glass args.append('O=%s/build' % work_dir) 196190064b4SSimon Glass cwd = None 19748c1b6a8SSimon Glass src_dir = os.getcwd() 198190064b4SSimon Glass else: 199190064b4SSimon Glass args.append('O=build') 200d2ce658dSSimon Glass if not self.builder.verbose_build: 201190064b4SSimon Glass args.append('-s') 202190064b4SSimon Glass if self.builder.num_jobs is not None: 203190064b4SSimon Glass args.extend(['-j', str(self.builder.num_jobs)]) 204190064b4SSimon Glass config_args = ['%s_defconfig' % brd.target] 205190064b4SSimon Glass config_out = '' 206190064b4SSimon Glass args.extend(self.builder.toolchains.GetMakeArguments(brd)) 207190064b4SSimon Glass 208190064b4SSimon Glass # If we need to reconfigure, do that now 209190064b4SSimon Glass if do_config: 210fd18a89eSRoger Meier result = self.Make(commit, brd, 'mrproper', cwd, 211fd18a89eSRoger Meier 'mrproper', *args, env=env) 212*40f11fceSSimon Glass config_out = result.combined 213190064b4SSimon Glass result = self.Make(commit, brd, 'config', cwd, 214190064b4SSimon Glass *(args + config_args), env=env) 215*40f11fceSSimon Glass config_out += result.combined 216190064b4SSimon Glass do_config = False # No need to configure next time 217190064b4SSimon Glass if result.return_code == 0: 218190064b4SSimon Glass result = self.Make(commit, brd, 'build', cwd, *args, 219190064b4SSimon Glass env=env) 22048c1b6a8SSimon Glass result.stderr = result.stderr.replace(src_dir + '/', '') 221*40f11fceSSimon Glass if self.builder.verbose_build: 222*40f11fceSSimon Glass result.stdout = config_out + result.stdout 223190064b4SSimon Glass else: 224190064b4SSimon Glass result.return_code = 1 225190064b4SSimon Glass result.stderr = 'No tool chain for %s\n' % brd.arch 226190064b4SSimon Glass result.already_done = False 227190064b4SSimon Glass 228190064b4SSimon Glass result.toolchain = self.toolchain 229190064b4SSimon Glass result.brd = brd 230190064b4SSimon Glass result.commit_upto = commit_upto 231190064b4SSimon Glass result.out_dir = out_dir 232190064b4SSimon Glass return result, do_config 233190064b4SSimon Glass 234190064b4SSimon Glass def _WriteResult(self, result, keep_outputs): 235190064b4SSimon Glass """Write a built result to the output directory. 236190064b4SSimon Glass 237190064b4SSimon Glass Args: 238190064b4SSimon Glass result: CommandResult object containing result to write 239190064b4SSimon Glass keep_outputs: True to store the output binaries, False 240190064b4SSimon Glass to delete them 241190064b4SSimon Glass """ 242190064b4SSimon Glass # Fatal error 243190064b4SSimon Glass if result.return_code < 0: 244190064b4SSimon Glass return 245190064b4SSimon Glass 246190064b4SSimon Glass # Aborted? 247190064b4SSimon Glass if result.stderr and 'No child processes' in result.stderr: 248190064b4SSimon Glass return 249190064b4SSimon Glass 250190064b4SSimon Glass if result.already_done: 251190064b4SSimon Glass return 252190064b4SSimon Glass 253190064b4SSimon Glass # Write the output and stderr 254190064b4SSimon Glass output_dir = self.builder._GetOutputDir(result.commit_upto) 255190064b4SSimon Glass Mkdir(output_dir) 256190064b4SSimon Glass build_dir = self.builder.GetBuildDir(result.commit_upto, 257190064b4SSimon Glass result.brd.target) 258190064b4SSimon Glass Mkdir(build_dir) 259190064b4SSimon Glass 260190064b4SSimon Glass outfile = os.path.join(build_dir, 'log') 261190064b4SSimon Glass with open(outfile, 'w') as fd: 262190064b4SSimon Glass if result.stdout: 263190064b4SSimon Glass fd.write(result.stdout) 264190064b4SSimon Glass 265190064b4SSimon Glass errfile = self.builder.GetErrFile(result.commit_upto, 266190064b4SSimon Glass result.brd.target) 267190064b4SSimon Glass if result.stderr: 268190064b4SSimon Glass with open(errfile, 'w') as fd: 269190064b4SSimon Glass fd.write(result.stderr) 270190064b4SSimon Glass elif os.path.exists(errfile): 271190064b4SSimon Glass os.remove(errfile) 272190064b4SSimon Glass 273190064b4SSimon Glass if result.toolchain: 274190064b4SSimon Glass # Write the build result and toolchain information. 275190064b4SSimon Glass done_file = self.builder.GetDoneFile(result.commit_upto, 276190064b4SSimon Glass result.brd.target) 277190064b4SSimon Glass with open(done_file, 'w') as fd: 278190064b4SSimon Glass fd.write('%s' % result.return_code) 279190064b4SSimon Glass with open(os.path.join(build_dir, 'toolchain'), 'w') as fd: 280190064b4SSimon Glass print >>fd, 'gcc', result.toolchain.gcc 281190064b4SSimon Glass print >>fd, 'path', result.toolchain.path 282190064b4SSimon Glass print >>fd, 'cross', result.toolchain.cross 283190064b4SSimon Glass print >>fd, 'arch', result.toolchain.arch 284190064b4SSimon Glass fd.write('%s' % result.return_code) 285190064b4SSimon Glass 286190064b4SSimon Glass with open(os.path.join(build_dir, 'toolchain'), 'w') as fd: 287190064b4SSimon Glass print >>fd, 'gcc', result.toolchain.gcc 288190064b4SSimon Glass print >>fd, 'path', result.toolchain.path 289190064b4SSimon Glass 290190064b4SSimon Glass # Write out the image and function size information and an objdump 291bb1501f2SSimon Glass env = result.toolchain.MakeEnvironment(self.builder.full_path) 292190064b4SSimon Glass lines = [] 293190064b4SSimon Glass for fname in ['u-boot', 'spl/u-boot-spl']: 294190064b4SSimon Glass cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname] 295190064b4SSimon Glass nm_result = command.RunPipe([cmd], capture=True, 296190064b4SSimon Glass capture_stderr=True, cwd=result.out_dir, 297190064b4SSimon Glass raise_on_error=False, env=env) 298190064b4SSimon Glass if nm_result.stdout: 299190064b4SSimon Glass nm = self.builder.GetFuncSizesFile(result.commit_upto, 300190064b4SSimon Glass result.brd.target, fname) 301190064b4SSimon Glass with open(nm, 'w') as fd: 302190064b4SSimon Glass print >>fd, nm_result.stdout, 303190064b4SSimon Glass 304190064b4SSimon Glass cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname] 305190064b4SSimon Glass dump_result = command.RunPipe([cmd], capture=True, 306190064b4SSimon Glass capture_stderr=True, cwd=result.out_dir, 307190064b4SSimon Glass raise_on_error=False, env=env) 308190064b4SSimon Glass rodata_size = '' 309190064b4SSimon Glass if dump_result.stdout: 310190064b4SSimon Glass objdump = self.builder.GetObjdumpFile(result.commit_upto, 311190064b4SSimon Glass result.brd.target, fname) 312190064b4SSimon Glass with open(objdump, 'w') as fd: 313190064b4SSimon Glass print >>fd, dump_result.stdout, 314190064b4SSimon Glass for line in dump_result.stdout.splitlines(): 315190064b4SSimon Glass fields = line.split() 316190064b4SSimon Glass if len(fields) > 5 and fields[1] == '.rodata': 317190064b4SSimon Glass rodata_size = fields[2] 318190064b4SSimon Glass 319190064b4SSimon Glass cmd = ['%ssize' % self.toolchain.cross, fname] 320190064b4SSimon Glass size_result = command.RunPipe([cmd], capture=True, 321190064b4SSimon Glass capture_stderr=True, cwd=result.out_dir, 322190064b4SSimon Glass raise_on_error=False, env=env) 323190064b4SSimon Glass if size_result.stdout: 324190064b4SSimon Glass lines.append(size_result.stdout.splitlines()[1] + ' ' + 325190064b4SSimon Glass rodata_size) 326190064b4SSimon Glass 327190064b4SSimon Glass # Write out the image sizes file. This is similar to the output 328190064b4SSimon Glass # of binutil's 'size' utility, but it omits the header line and 329190064b4SSimon Glass # adds an additional hex value at the end of each line for the 330190064b4SSimon Glass # rodata size 331190064b4SSimon Glass if len(lines): 332190064b4SSimon Glass sizes = self.builder.GetSizesFile(result.commit_upto, 333190064b4SSimon Glass result.brd.target) 334190064b4SSimon Glass with open(sizes, 'w') as fd: 335190064b4SSimon Glass print >>fd, '\n'.join(lines) 336190064b4SSimon Glass 337190064b4SSimon Glass # Now write the actual build output 338190064b4SSimon Glass if keep_outputs: 339ce267335STom Rini patterns = ['u-boot', '*.bin', 'u-boot.dtb', '*.map', '*.img', 340190064b4SSimon Glass 'include/autoconf.mk', 'spl/u-boot-spl', 341190064b4SSimon Glass 'spl/u-boot-spl.bin'] 342190064b4SSimon Glass for pattern in patterns: 343190064b4SSimon Glass file_list = glob.glob(os.path.join(result.out_dir, pattern)) 344190064b4SSimon Glass for fname in file_list: 345190064b4SSimon Glass shutil.copy(fname, build_dir) 346190064b4SSimon Glass 347190064b4SSimon Glass 348190064b4SSimon Glass def RunJob(self, job): 349190064b4SSimon Glass """Run a single job 350190064b4SSimon Glass 351190064b4SSimon Glass A job consists of a building a list of commits for a particular board. 352190064b4SSimon Glass 353190064b4SSimon Glass Args: 354190064b4SSimon Glass job: Job to build 355190064b4SSimon Glass """ 356190064b4SSimon Glass brd = job.board 357190064b4SSimon Glass work_dir = self.builder.GetThreadDir(self.thread_num) 358190064b4SSimon Glass self.toolchain = None 359190064b4SSimon Glass if job.commits: 360190064b4SSimon Glass # Run 'make board_defconfig' on the first commit 361190064b4SSimon Glass do_config = True 362190064b4SSimon Glass commit_upto = 0 363190064b4SSimon Glass force_build = False 364190064b4SSimon Glass for commit_upto in range(0, len(job.commits), job.step): 365190064b4SSimon Glass result, request_config = self.RunCommit(commit_upto, brd, 366190064b4SSimon Glass work_dir, do_config, 367190064b4SSimon Glass force_build or self.builder.force_build, 368190064b4SSimon Glass self.builder.force_build_failures) 369190064b4SSimon Glass failed = result.return_code or result.stderr 370190064b4SSimon Glass did_config = do_config 371190064b4SSimon Glass if failed and not do_config: 372190064b4SSimon Glass # If our incremental build failed, try building again 373190064b4SSimon Glass # with a reconfig. 374190064b4SSimon Glass if self.builder.force_config_on_failure: 375190064b4SSimon Glass result, request_config = self.RunCommit(commit_upto, 376190064b4SSimon Glass brd, work_dir, True, True, False) 377190064b4SSimon Glass did_config = True 378190064b4SSimon Glass if not self.builder.force_reconfig: 379190064b4SSimon Glass do_config = request_config 380190064b4SSimon Glass 381190064b4SSimon Glass # If we built that commit, then config is done. But if we got 382190064b4SSimon Glass # an warning, reconfig next time to force it to build the same 383190064b4SSimon Glass # files that created warnings this time. Otherwise an 384190064b4SSimon Glass # incremental build may not build the same file, and we will 385190064b4SSimon Glass # think that the warning has gone away. 386190064b4SSimon Glass # We could avoid this by using -Werror everywhere... 387190064b4SSimon Glass # For errors, the problem doesn't happen, since presumably 388190064b4SSimon Glass # the build stopped and didn't generate output, so will retry 389190064b4SSimon Glass # that file next time. So we could detect warnings and deal 390190064b4SSimon Glass # with them specially here. For now, we just reconfigure if 391190064b4SSimon Glass # anything goes work. 392190064b4SSimon Glass # Of course this is substantially slower if there are build 393190064b4SSimon Glass # errors/warnings (e.g. 2-3x slower even if only 10% of builds 394190064b4SSimon Glass # have problems). 395190064b4SSimon Glass if (failed and not result.already_done and not did_config and 396190064b4SSimon Glass self.builder.force_config_on_failure): 397190064b4SSimon Glass # If this build failed, try the next one with a 398190064b4SSimon Glass # reconfigure. 399190064b4SSimon Glass # Sometimes if the board_config.h file changes it can mess 400190064b4SSimon Glass # with dependencies, and we get: 401190064b4SSimon Glass # make: *** No rule to make target `include/autoconf.mk', 402190064b4SSimon Glass # needed by `depend'. 403190064b4SSimon Glass do_config = True 404190064b4SSimon Glass force_build = True 405190064b4SSimon Glass else: 406190064b4SSimon Glass force_build = False 407190064b4SSimon Glass if self.builder.force_config_on_failure: 408190064b4SSimon Glass if failed: 409190064b4SSimon Glass do_config = True 410190064b4SSimon Glass result.commit_upto = commit_upto 411190064b4SSimon Glass if result.return_code < 0: 412190064b4SSimon Glass raise ValueError('Interrupt') 413190064b4SSimon Glass 414190064b4SSimon Glass # We have the build results, so output the result 415190064b4SSimon Glass self._WriteResult(result, job.keep_outputs) 416190064b4SSimon Glass self.builder.out_queue.put(result) 417190064b4SSimon Glass else: 418190064b4SSimon Glass # Just build the currently checked-out build 419190064b4SSimon Glass result, request_config = self.RunCommit(None, brd, work_dir, True, 420190064b4SSimon Glass True, self.builder.force_build_failures) 421190064b4SSimon Glass result.commit_upto = 0 422190064b4SSimon Glass self._WriteResult(result, job.keep_outputs) 423190064b4SSimon Glass self.builder.out_queue.put(result) 424190064b4SSimon Glass 425190064b4SSimon Glass def run(self): 426190064b4SSimon Glass """Our thread's run function 427190064b4SSimon Glass 428190064b4SSimon Glass This thread picks a job from the queue, runs it, and then goes to the 429190064b4SSimon Glass next job. 430190064b4SSimon Glass """ 431190064b4SSimon Glass alive = True 432190064b4SSimon Glass while True: 433190064b4SSimon Glass job = self.builder.queue.get() 434190064b4SSimon Glass if self.builder.active and alive: 435190064b4SSimon Glass self.RunJob(job) 436190064b4SSimon Glass ''' 437190064b4SSimon Glass try: 438190064b4SSimon Glass if self.builder.active and alive: 439190064b4SSimon Glass self.RunJob(job) 440190064b4SSimon Glass except Exception as err: 441190064b4SSimon Glass alive = False 442190064b4SSimon Glass print err 443190064b4SSimon Glass ''' 444190064b4SSimon Glass self.builder.queue.task_done() 445