diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py index b673fe10ee..c631ec7e6d 100644 --- a/bitbake/lib/bb/cooker.py +++ b/bitbake/lib/bb/cooker.py @@ -345,6 +345,7 @@ class BBCooker: elif signum == signal.SIGHUP: bb.warn("Cooker received SIGHUP, shutting down...") self.state = state.forceshutdown + bb.event._should_exit.set() def setFeatures(self, features): # we only accept a new feature set if we're in state initial, so we can reset without problems @@ -1520,6 +1521,7 @@ class BBCooker: msg = None interrupted = 0 if halt or self.state == state.forceshutdown: + bb.event._should_exit.set() rq.finish_runqueue(True) msg = "Forced shutdown" interrupted = 2 @@ -1760,6 +1762,7 @@ class BBCooker: self.state = state.forceshutdown else: self.state = state.shutdown + bb.event._should_exit.set() if self.parser: self.parser.shutdown(clean=False) @@ -1770,6 +1773,7 @@ class BBCooker: self.parser.shutdown(clean=False) self.parser.final_cleanup() self.state = state.initial + bb.event._should_exit.clear() def reset(self): if hasattr(bb.parse, "siggen"): diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py index 8b05f93e2f..37cc630c63 100644 --- a/bitbake/lib/bb/event.py +++ b/bitbake/lib/bb/event.py @@ -69,6 +69,7 @@ _eventfilter = None _uiready = False _thread_lock = threading.Lock() _heartbeat_enabled = False +_should_exit = threading.Event() def enable_threadlock(): # Always needed now @@ -86,6 +87,16 @@ def disable_heartbeat(): global _heartbeat_enabled _heartbeat_enabled = False +# +# In long running code, this function should be called periodically +# to check if we should exit due to an interuption (.e.g Ctrl+C from the UI) +# +def check_for_interrupts(d): + global _should_exit + if _should_exit.is_set(): + bb.warn("Exiting due to interrupt.") + raise bb.BBHandledException() + def execute_handler(name, handler, event, d): event.data = d try: diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py index e5bd9311f2..e629ab7e7b 100644 --- a/bitbake/lib/bb/runqueue.py +++ b/bitbake/lib/bb/runqueue.py @@ -655,6 +655,7 @@ class RunQueueData: self.init_progress_reporter.start() self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Step A - Work out a list of tasks to run # @@ -803,6 +804,7 @@ class RunQueueData: #self.dump_data() self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Resolve recursive 'recrdeptask' dependencies (Part B) # @@ -899,6 +901,7 @@ class RunQueueData: self.runtaskentries[tid].depends.difference_update(recursivetasksselfref) self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) #self.dump_data() @@ -980,6 +983,7 @@ class RunQueueData: mark_active(tid, 1) self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Step C - Prune all inactive tasks # @@ -1019,6 +1023,7 @@ class RunQueueData: 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))) self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Handle runonly if self.cooker.configuration.runonly: @@ -1059,6 +1064,7 @@ class RunQueueData: logger.verbose("Assign Weightings") self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Generate a list of reverse dependencies to ease future calculations for tid in self.runtaskentries: @@ -1066,6 +1072,7 @@ class RunQueueData: self.runtaskentries[dep].revdeps.add(tid) self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Identify tasks at the end of dependency chains # Error on circular dependency loops (length two) @@ -1082,12 +1089,14 @@ class RunQueueData: logger.verbose("Compute totals (have %s endpoint(s))", len(endpoints)) self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Calculate task weights # Check of higher length circular dependencies self.runq_weight = self.calculate_task_weights(endpoints) self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Sanity Check - Check for multiple tasks building the same provider for mc in self.dataCaches: @@ -1188,6 +1197,7 @@ class RunQueueData: self.init_progress_reporter.next_stage() self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Iterate over the task list looking for tasks with a 'setscene' function self.runq_setscene_tids = set() @@ -1200,6 +1210,7 @@ class RunQueueData: self.runq_setscene_tids.add(tid) self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Invalidate task if force mode active if self.cooker.configuration.force: @@ -1216,6 +1227,7 @@ class RunQueueData: invalidate_task(fn + ":" + st, True) self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) # Create and print to the logs a virtual/xxxx -> PN (fn) table for mc in taskData: @@ -1228,6 +1240,7 @@ class RunQueueData: bb.parse.siggen.tasks_resolved(virtmap, virtpnmap, self.dataCaches[mc]) self.init_progress_reporter.next_stage() + bb.event.check_for_interrupts(self.cooker.data) bb.parse.siggen.set_setscene_tasks(self.runq_setscene_tids) @@ -1240,6 +1253,7 @@ class RunQueueData: dealtwith.add(tid) todeal.remove(tid) self.prepare_task_hash(tid) + bb.event.check_for_interrupts(self.cooker.data) bb.parse.siggen.writeout_file_checksum_cache() @@ -1483,6 +1497,7 @@ class RunQueue: """ retval = True + bb.event.check_for_interrupts(self.cooker.data) if self.state is runQueuePrepare: # NOTE: if you add, remove or significantly refactor the stages of this