summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/asyncrpc/serv.py
diff options
context:
space:
mode:
authorJoshua Watt <jpewhacker@gmail.com>2021-07-22 11:19:37 -0500
committerRichard Purdie <richard.purdie@linuxfoundation.org>2021-07-29 23:21:24 +0100
commita83ea01b99d799025caede57512648d3258579d0 (patch)
tree72b5d1858931bc1e5f7244c9dcff36493650e8a7 /bitbake/lib/bb/asyncrpc/serv.py
parent445c5b9324a6243a0a3941c5f00e369d7749efde (diff)
downloadpoky-a83ea01b99d799025caede57512648d3258579d0.tar.gz
bitbake: bitbake: asyncrpc: Catch early SIGTERM
If the SIGTERM signal is sent to an asyncrpc server before it has installed the SIGTERM handler in the main loop, it may miss the signal which will can cause the calling process to wait forever on the join(). To resolve this, the calling process should mask of SIGTERM before forking the server process and the server should unmask the signal only after the handler is installed. To simplify the usage of the server, an new helper function called serve_as_process() is added to do this automatically and correctly. Thanks: Scott Murray <scott.murray@konsulko.com> for helping debug (Bitbake rev: ef2865efa98ad20823267364f2159d8d8c931400) Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/asyncrpc/serv.py')
-rw-r--r--bitbake/lib/bb/asyncrpc/serv.py21
1 files changed, 21 insertions, 0 deletions
diff --git a/bitbake/lib/bb/asyncrpc/serv.py b/bitbake/lib/bb/asyncrpc/serv.py
index ef20cb71df..4084f300df 100644
--- a/bitbake/lib/bb/asyncrpc/serv.py
+++ b/bitbake/lib/bb/asyncrpc/serv.py
@@ -9,6 +9,7 @@ import os
9import signal 9import signal
10import socket 10import socket
11import sys 11import sys
12import multiprocessing
12from . import chunkify, DEFAULT_MAX_CHUNK 13from . import chunkify, DEFAULT_MAX_CHUNK
13 14
14 15
@@ -201,12 +202,14 @@ class AsyncServer(object):
201 pass 202 pass
202 203
203 def signal_handler(self): 204 def signal_handler(self):
205 self.logger.debug("Got exit signal")
204 self.loop.stop() 206 self.loop.stop()
205 207
206 def serve_forever(self): 208 def serve_forever(self):
207 asyncio.set_event_loop(self.loop) 209 asyncio.set_event_loop(self.loop)
208 try: 210 try:
209 self.loop.add_signal_handler(signal.SIGTERM, self.signal_handler) 211 self.loop.add_signal_handler(signal.SIGTERM, self.signal_handler)
212 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGTERM])
210 213
211 self.run_loop_forever() 214 self.run_loop_forever()
212 self.server.close() 215 self.server.close()
@@ -221,3 +224,21 @@ class AsyncServer(object):
221 224
222 if self._cleanup_socket is not None: 225 if self._cleanup_socket is not None:
223 self._cleanup_socket() 226 self._cleanup_socket()
227
228 def serve_as_process(self, *, prefunc=None, args=()):
229 def run():
230 if prefunc is not None:
231 prefunc(self, *args)
232 self.serve_forever()
233
234 # Temporarily block SIGTERM. The server process will inherit this
235 # block which will ensure it doesn't receive the SIGTERM until the
236 # handler is ready for it
237 mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGTERM])
238 try:
239 self.process = multiprocessing.Process(target=run)
240 self.process.start()
241
242 return self.process
243 finally:
244 signal.pthread_sigmask(signal.SIG_SETMASK, mask)