diff options
author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2023-01-09 23:17:56 +0000 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2023-01-11 10:58:36 +0000 |
commit | 165e8b563d400bf54c317659a267db85e8c34006 (patch) | |
tree | 7e4d05e7d3440b6f95c029afabf1822d3f7b2733 /bitbake/lib/bb/command.py | |
parent | 4e4f040a73ca81f830cf90af05b75e7c06f91d8d (diff) | |
download | poky-165e8b563d400bf54c317659a267db85e8c34006.tar.gz |
bitbake: process/cooker/command: Fix currentAsyncCommand locking/races
currentAsyncCommand currently doesn't have any locking and we have
a conflict in "idle" conditions since the idle functions count needs
to be zero *and* there needs to be no active command.
Move the changes/checks of currentAsyncCommand to within the lock
and then we can add it to the condition for idle, simplifying some
of the code.
(Bitbake rev: b5215887d2f8ea3f28f1ebda721bd5b8f93ec7f3)
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/command.py')
-rw-r--r-- | bitbake/lib/bb/command.py | 26 |
1 files changed, 12 insertions, 14 deletions
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py index a29e41afda..9e2cdc5c75 100644 --- a/bitbake/lib/bb/command.py +++ b/bitbake/lib/bb/command.py | |||
@@ -51,13 +51,14 @@ class Command: | |||
51 | """ | 51 | """ |
52 | A queue of asynchronous commands for bitbake | 52 | A queue of asynchronous commands for bitbake |
53 | """ | 53 | """ |
54 | def __init__(self, cooker): | 54 | def __init__(self, cooker, process_server): |
55 | self.cooker = cooker | 55 | self.cooker = cooker |
56 | self.cmds_sync = CommandsSync() | 56 | self.cmds_sync = CommandsSync() |
57 | self.cmds_async = CommandsAsync() | 57 | self.cmds_async = CommandsAsync() |
58 | self.remotedatastores = None | 58 | self.remotedatastores = None |
59 | 59 | ||
60 | # FIXME Add lock for this | 60 | self.process_server = process_server |
61 | # Access with locking using process_server.{get/set/clear}_async_cmd() | ||
61 | self.currentAsyncCommand = None | 62 | self.currentAsyncCommand = None |
62 | 63 | ||
63 | def runCommand(self, commandline, process_server, ro_only=False): | 64 | def runCommand(self, commandline, process_server, ro_only=False): |
@@ -99,18 +100,14 @@ class Command: | |||
99 | return None, traceback.format_exc() | 100 | return None, traceback.format_exc() |
100 | else: | 101 | else: |
101 | return result, None | 102 | return result, None |
102 | if self.currentAsyncCommand is not None: | ||
103 | # Wait for the idle loop to have cleared (30s max) | ||
104 | process_server.wait_for_idle(timeout=30) | ||
105 | if self.currentAsyncCommand is not None: | ||
106 | return None, "Busy (%s in progress)" % self.currentAsyncCommand[0] | ||
107 | if command not in CommandsAsync.__dict__: | 103 | if command not in CommandsAsync.__dict__: |
108 | return None, "No such command" | 104 | return None, "No such command" |
109 | self.currentAsyncCommand = (command, commandline) | 105 | if not process_server.set_async_cmd((command, commandline)): |
110 | self.cooker.idleCallBackRegister(self.runAsyncCommand, None) | 106 | return None, "Busy (%s in progress)" % self.process_server.get_async_cmd()[0] |
107 | self.cooker.idleCallBackRegister(self.runAsyncCommand, process_server) | ||
111 | return True, None | 108 | return True, None |
112 | 109 | ||
113 | def runAsyncCommand(self, _, _2, halt): | 110 | def runAsyncCommand(self, _, process_server, halt): |
114 | try: | 111 | try: |
115 | self.cooker.process_inotify_updates_apply() | 112 | self.cooker.process_inotify_updates_apply() |
116 | if self.cooker.state in (bb.cooker.state.error, bb.cooker.state.shutdown, bb.cooker.state.forceshutdown): | 113 | if self.cooker.state in (bb.cooker.state.error, bb.cooker.state.shutdown, bb.cooker.state.forceshutdown): |
@@ -118,8 +115,9 @@ class Command: | |||
118 | # and then raise BBHandledException triggering an exit | 115 | # and then raise BBHandledException triggering an exit |
119 | self.cooker.updateCache() | 116 | self.cooker.updateCache() |
120 | return bb.server.process.idleFinish("Cooker in error state") | 117 | return bb.server.process.idleFinish("Cooker in error state") |
121 | if self.currentAsyncCommand is not None: | 118 | cmd = process_server.get_async_cmd() |
122 | (command, options) = self.currentAsyncCommand | 119 | if cmd is not None: |
120 | (command, options) = cmd | ||
123 | commandmethod = getattr(CommandsAsync, command) | 121 | commandmethod = getattr(CommandsAsync, command) |
124 | needcache = getattr( commandmethod, "needcache" ) | 122 | needcache = getattr( commandmethod, "needcache" ) |
125 | if needcache and self.cooker.state != bb.cooker.state.running: | 123 | if needcache and self.cooker.state != bb.cooker.state.running: |
@@ -153,7 +151,7 @@ class Command: | |||
153 | else: | 151 | else: |
154 | bb.event.fire(CommandCompleted(), self.cooker.data) | 152 | bb.event.fire(CommandCompleted(), self.cooker.data) |
155 | self.cooker.finishcommand() | 153 | self.cooker.finishcommand() |
156 | self.currentAsyncCommand = None | 154 | self.process_server.clear_async_cmd() |
157 | 155 | ||
158 | def reset(self): | 156 | def reset(self): |
159 | if self.remotedatastores: | 157 | if self.remotedatastores: |
@@ -746,7 +744,7 @@ class CommandsAsync: | |||
746 | """ | 744 | """ |
747 | event = params[0] | 745 | event = params[0] |
748 | bb.event.fire(eval(event), command.cooker.data) | 746 | bb.event.fire(eval(event), command.cooker.data) |
749 | command.currentAsyncCommand = None | 747 | process_server.clear_async_cmd() |
750 | triggerEvent.needcache = False | 748 | triggerEvent.needcache = False |
751 | 749 | ||
752 | def resetCooker(self, command, params): | 750 | def resetCooker(self, command, params): |