summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2013-08-24 11:56:31 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-08-26 11:29:46 +0100
commita03a423c607f53684789ebb5c3c5003568047a14 (patch)
tree9803adb898f92cfaa56cf63bac4ab06a5c61fe2d
parentaa0b23714499143e4eec2f919fddd377bdc182e7 (diff)
downloadpoky-a03a423c607f53684789ebb5c3c5003568047a14.tar.gz
bitbake: process: Improve exit handling and hangs
It turns out we have a number of different ways the process server termination can hang. If we call cancel_join_thread() on the event queue, it means that it can be left containing partial data. This means the reading of the event queue in the terminate() function can hang, the timeout and block parameters to Queue.get() don't make any difference. Equally, if we don't call cancel_join_thread(), the join_thread in terminate() will hang giving a different deadlock. The best solution I could find is to loop over the process is_alive() after requesting it stops, trying to join the thread and if that fails, try and flush the event queue again. It wasn't clear what difference a force option should make in this case, we're gracefully trying to empty queues and shut down regardless of whether its a SIGTERM so I've simply removed the force option. (Bitbake rev: c5c8f33ca4b81877a0115887849881001b745bf0) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/bb/server/process.py36
1 files changed, 17 insertions, 19 deletions
diff --git a/bitbake/lib/bb/server/process.py b/bitbake/lib/bb/server/process.py
index 0d4a26ced0..99a6bf55cc 100644
--- a/bitbake/lib/bb/server/process.py
+++ b/bitbake/lib/bb/server/process.py
@@ -105,7 +105,7 @@ class ProcessServer(Process, BaseImplServer):
105 except Exception: 105 except Exception:
106 logger.exception('Running command %s', command) 106 logger.exception('Running command %s', command)
107 107
108 self.event_queue.cancel_join_thread() 108 self.event_queue.close()
109 bb.event.unregister_UIHhandler(self.event_handle) 109 bb.event.unregister_UIHhandler(self.event_handle)
110 self.command_channel.close() 110 self.command_channel.close()
111 self.cooker.stop() 111 self.cooker.stop()
@@ -150,27 +150,25 @@ class BitBakeProcessServerConnection(BitBakeBaseServerConnection):
150 self.connection = ServerCommunicator(self.ui_channel) 150 self.connection = ServerCommunicator(self.ui_channel)
151 self.events = self.event_queue 151 self.events = self.event_queue
152 152
153 def terminate(self, force = False): 153 def terminate(self):
154 def flushevents():
155 while True:
156 try:
157 event = self.event_queue.get(block=False)
158 except (Empty, IOError):
159 break
160 if isinstance(event, logging.LogRecord):
161 logger.handle(event)
162
154 signal.signal(signal.SIGINT, signal.SIG_IGN) 163 signal.signal(signal.SIGINT, signal.SIG_IGN)
155 self.procserver.stop() 164 self.procserver.stop()
156 if force: 165
157 self.procserver.join(0.5) 166 while self.procserver.is_alive():
158 if self.procserver.is_alive(): 167 flushevents()
159 self.procserver.terminate() 168 self.procserver.join(0.1)
160 self.procserver.join() 169
161 else:
162 self.procserver.join()
163 while True:
164 try:
165 event = self.event_queue.get(block=False)
166 except (Empty, IOError):
167 break
168 if isinstance(event, logging.LogRecord):
169 logger.handle(event)
170 self.ui_channel.close() 170 self.ui_channel.close()
171 self.event_queue.close() 171 self.event_queue.close()
172 if force:
173 sys.exit(1)
174 172
175# Wrap Queue to provide API which isn't server implementation specific 173# Wrap Queue to provide API which isn't server implementation specific
176class ProcessEventQueue(multiprocessing.queues.Queue): 174class ProcessEventQueue(multiprocessing.queues.Queue):
@@ -203,5 +201,5 @@ class BitBakeServer(BitBakeBaseServer):
203 201
204 def establishConnection(self): 202 def establishConnection(self):
205 self.connection = BitBakeProcessServerConnection(self.serverImpl, self.ui_channel, self.event_queue) 203 self.connection = BitBakeProcessServerConnection(self.serverImpl, self.ui_channel, self.event_queue)
206 signal.signal(signal.SIGTERM, lambda i, s: self.connection.terminate(force=True)) 204 signal.signal(signal.SIGTERM, lambda i, s: self.connection.terminate())
207 return self.connection 205 return self.connection