summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2023-02-22 13:31:34 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2023-02-23 12:12:18 +0000
commit42c92cbc83a56249203aeb23fe524f9b4eebbdf9 (patch)
treeb9c4dbdaacd51acdf564e684712db7ab613f1d52
parent906657e9beef9a256b642ebb9857036710c24f62 (diff)
downloadpoky-42c92cbc83a56249203aeb23fe524f9b4eebbdf9.tar.gz
bitbake: event/cooker/runqueue: Add ability to interrupt longer running code
Bitbake is now able to understand when a UI wants it to stop the current processing. There are some long running functions which currently have no mechanism to interrupt them however. This patch adds a call, bb.event.check_for_interrupts(d) which can be placed in long running code and allows an internal state flag within bitbake to be checked. If set, that flag will trigger an exit. This means that Ctrl+C can be made to work in a variety of places where it currently would not. Long running event handlers in OE-Core can also then benefit from this new approach with the addition of the function call as well. (Bitbake rev: b7ed7e9a815c4e10447fd499508be3dbb47f06e8) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/bb/cooker.py4
-rw-r--r--bitbake/lib/bb/event.py11
-rw-r--r--bitbake/lib/bb/runqueue.py15
3 files changed, 30 insertions, 0 deletions
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:
345 elif signum == signal.SIGHUP: 345 elif signum == signal.SIGHUP:
346 bb.warn("Cooker received SIGHUP, shutting down...") 346 bb.warn("Cooker received SIGHUP, shutting down...")
347 self.state = state.forceshutdown 347 self.state = state.forceshutdown
348 bb.event._should_exit.set()
348 349
349 def setFeatures(self, features): 350 def setFeatures(self, features):
350 # we only accept a new feature set if we're in state initial, so we can reset without problems 351 # 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:
1520 msg = None 1521 msg = None
1521 interrupted = 0 1522 interrupted = 0
1522 if halt or self.state == state.forceshutdown: 1523 if halt or self.state == state.forceshutdown:
1524 bb.event._should_exit.set()
1523 rq.finish_runqueue(True) 1525 rq.finish_runqueue(True)
1524 msg = "Forced shutdown" 1526 msg = "Forced shutdown"
1525 interrupted = 2 1527 interrupted = 2
@@ -1760,6 +1762,7 @@ class BBCooker:
1760 self.state = state.forceshutdown 1762 self.state = state.forceshutdown
1761 else: 1763 else:
1762 self.state = state.shutdown 1764 self.state = state.shutdown
1765 bb.event._should_exit.set()
1763 1766
1764 if self.parser: 1767 if self.parser:
1765 self.parser.shutdown(clean=False) 1768 self.parser.shutdown(clean=False)
@@ -1770,6 +1773,7 @@ class BBCooker:
1770 self.parser.shutdown(clean=False) 1773 self.parser.shutdown(clean=False)
1771 self.parser.final_cleanup() 1774 self.parser.final_cleanup()
1772 self.state = state.initial 1775 self.state = state.initial
1776 bb.event._should_exit.clear()
1773 1777
1774 def reset(self): 1778 def reset(self):
1775 if hasattr(bb.parse, "siggen"): 1779 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
69_uiready = False 69_uiready = False
70_thread_lock = threading.Lock() 70_thread_lock = threading.Lock()
71_heartbeat_enabled = False 71_heartbeat_enabled = False
72_should_exit = threading.Event()
72 73
73def enable_threadlock(): 74def enable_threadlock():
74 # Always needed now 75 # Always needed now
@@ -86,6 +87,16 @@ def disable_heartbeat():
86 global _heartbeat_enabled 87 global _heartbeat_enabled
87 _heartbeat_enabled = False 88 _heartbeat_enabled = False
88 89
90#
91# In long running code, this function should be called periodically
92# to check if we should exit due to an interuption (.e.g Ctrl+C from the UI)
93#
94def check_for_interrupts(d):
95 global _should_exit
96 if _should_exit.is_set():
97 bb.warn("Exiting due to interrupt.")
98 raise bb.BBHandledException()
99
89def execute_handler(name, handler, event, d): 100def execute_handler(name, handler, event, d):
90 event.data = d 101 event.data = d
91 try: 102 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:
655 655
656 self.init_progress_reporter.start() 656 self.init_progress_reporter.start()
657 self.init_progress_reporter.next_stage() 657 self.init_progress_reporter.next_stage()
658 bb.event.check_for_interrupts(self.cooker.data)
658 659
659 # Step A - Work out a list of tasks to run 660 # Step A - Work out a list of tasks to run
660 # 661 #
@@ -803,6 +804,7 @@ class RunQueueData:
803 #self.dump_data() 804 #self.dump_data()
804 805
805 self.init_progress_reporter.next_stage() 806 self.init_progress_reporter.next_stage()
807 bb.event.check_for_interrupts(self.cooker.data)
806 808
807 # Resolve recursive 'recrdeptask' dependencies (Part B) 809 # Resolve recursive 'recrdeptask' dependencies (Part B)
808 # 810 #
@@ -899,6 +901,7 @@ class RunQueueData:
899 self.runtaskentries[tid].depends.difference_update(recursivetasksselfref) 901 self.runtaskentries[tid].depends.difference_update(recursivetasksselfref)
900 902
901 self.init_progress_reporter.next_stage() 903 self.init_progress_reporter.next_stage()
904 bb.event.check_for_interrupts(self.cooker.data)
902 905
903 #self.dump_data() 906 #self.dump_data()
904 907
@@ -980,6 +983,7 @@ class RunQueueData:
980 mark_active(tid, 1) 983 mark_active(tid, 1)
981 984
982 self.init_progress_reporter.next_stage() 985 self.init_progress_reporter.next_stage()
986 bb.event.check_for_interrupts(self.cooker.data)
983 987
984 # Step C - Prune all inactive tasks 988 # Step C - Prune all inactive tasks
985 # 989 #
@@ -1019,6 +1023,7 @@ class RunQueueData:
1019 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))) 1023 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)))
1020 1024
1021 self.init_progress_reporter.next_stage() 1025 self.init_progress_reporter.next_stage()
1026 bb.event.check_for_interrupts(self.cooker.data)
1022 1027
1023 # Handle runonly 1028 # Handle runonly
1024 if self.cooker.configuration.runonly: 1029 if self.cooker.configuration.runonly:
@@ -1059,6 +1064,7 @@ class RunQueueData:
1059 logger.verbose("Assign Weightings") 1064 logger.verbose("Assign Weightings")
1060 1065
1061 self.init_progress_reporter.next_stage() 1066 self.init_progress_reporter.next_stage()
1067 bb.event.check_for_interrupts(self.cooker.data)
1062 1068
1063 # Generate a list of reverse dependencies to ease future calculations 1069 # Generate a list of reverse dependencies to ease future calculations
1064 for tid in self.runtaskentries: 1070 for tid in self.runtaskentries:
@@ -1066,6 +1072,7 @@ class RunQueueData:
1066 self.runtaskentries[dep].revdeps.add(tid) 1072 self.runtaskentries[dep].revdeps.add(tid)
1067 1073
1068 self.init_progress_reporter.next_stage() 1074 self.init_progress_reporter.next_stage()
1075 bb.event.check_for_interrupts(self.cooker.data)
1069 1076
1070 # Identify tasks at the end of dependency chains 1077 # Identify tasks at the end of dependency chains
1071 # Error on circular dependency loops (length two) 1078 # Error on circular dependency loops (length two)
@@ -1082,12 +1089,14 @@ class RunQueueData:
1082 logger.verbose("Compute totals (have %s endpoint(s))", len(endpoints)) 1089 logger.verbose("Compute totals (have %s endpoint(s))", len(endpoints))
1083 1090
1084 self.init_progress_reporter.next_stage() 1091 self.init_progress_reporter.next_stage()
1092 bb.event.check_for_interrupts(self.cooker.data)
1085 1093
1086 # Calculate task weights 1094 # Calculate task weights
1087 # Check of higher length circular dependencies 1095 # Check of higher length circular dependencies
1088 self.runq_weight = self.calculate_task_weights(endpoints) 1096 self.runq_weight = self.calculate_task_weights(endpoints)
1089 1097
1090 self.init_progress_reporter.next_stage() 1098 self.init_progress_reporter.next_stage()
1099 bb.event.check_for_interrupts(self.cooker.data)
1091 1100
1092 # Sanity Check - Check for multiple tasks building the same provider 1101 # Sanity Check - Check for multiple tasks building the same provider
1093 for mc in self.dataCaches: 1102 for mc in self.dataCaches:
@@ -1188,6 +1197,7 @@ class RunQueueData:
1188 1197
1189 self.init_progress_reporter.next_stage() 1198 self.init_progress_reporter.next_stage()
1190 self.init_progress_reporter.next_stage() 1199 self.init_progress_reporter.next_stage()
1200 bb.event.check_for_interrupts(self.cooker.data)
1191 1201
1192 # Iterate over the task list looking for tasks with a 'setscene' function 1202 # Iterate over the task list looking for tasks with a 'setscene' function
1193 self.runq_setscene_tids = set() 1203 self.runq_setscene_tids = set()
@@ -1200,6 +1210,7 @@ class RunQueueData:
1200 self.runq_setscene_tids.add(tid) 1210 self.runq_setscene_tids.add(tid)
1201 1211
1202 self.init_progress_reporter.next_stage() 1212 self.init_progress_reporter.next_stage()
1213 bb.event.check_for_interrupts(self.cooker.data)
1203 1214
1204 # Invalidate task if force mode active 1215 # Invalidate task if force mode active
1205 if self.cooker.configuration.force: 1216 if self.cooker.configuration.force:
@@ -1216,6 +1227,7 @@ class RunQueueData:
1216 invalidate_task(fn + ":" + st, True) 1227 invalidate_task(fn + ":" + st, True)
1217 1228
1218 self.init_progress_reporter.next_stage() 1229 self.init_progress_reporter.next_stage()
1230 bb.event.check_for_interrupts(self.cooker.data)
1219 1231
1220 # Create and print to the logs a virtual/xxxx -> PN (fn) table 1232 # Create and print to the logs a virtual/xxxx -> PN (fn) table
1221 for mc in taskData: 1233 for mc in taskData:
@@ -1228,6 +1240,7 @@ class RunQueueData:
1228 bb.parse.siggen.tasks_resolved(virtmap, virtpnmap, self.dataCaches[mc]) 1240 bb.parse.siggen.tasks_resolved(virtmap, virtpnmap, self.dataCaches[mc])
1229 1241
1230 self.init_progress_reporter.next_stage() 1242 self.init_progress_reporter.next_stage()
1243 bb.event.check_for_interrupts(self.cooker.data)
1231 1244
1232 bb.parse.siggen.set_setscene_tasks(self.runq_setscene_tids) 1245 bb.parse.siggen.set_setscene_tasks(self.runq_setscene_tids)
1233 1246
@@ -1240,6 +1253,7 @@ class RunQueueData:
1240 dealtwith.add(tid) 1253 dealtwith.add(tid)
1241 todeal.remove(tid) 1254 todeal.remove(tid)
1242 self.prepare_task_hash(tid) 1255 self.prepare_task_hash(tid)
1256 bb.event.check_for_interrupts(self.cooker.data)
1243 1257
1244 bb.parse.siggen.writeout_file_checksum_cache() 1258 bb.parse.siggen.writeout_file_checksum_cache()
1245 1259
@@ -1483,6 +1497,7 @@ class RunQueue:
1483 """ 1497 """
1484 1498
1485 retval = True 1499 retval = True
1500 bb.event.check_for_interrupts(self.cooker.data)
1486 1501
1487 if self.state is runQueuePrepare: 1502 if self.state is runQueuePrepare:
1488 # NOTE: if you add, remove or significantly refactor the stages of this 1503 # NOTE: if you add, remove or significantly refactor the stages of this