diff options
author | Joshua Watt <jpewhacker@gmail.com> | 2021-07-22 11:19:37 -0500 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2021-07-29 23:21:24 +0100 |
commit | a83ea01b99d799025caede57512648d3258579d0 (patch) | |
tree | 72b5d1858931bc1e5f7244c9dcff36493650e8a7 /bitbake/lib/bb/asyncrpc/serv.py | |
parent | 445c5b9324a6243a0a3941c5f00e369d7749efde (diff) | |
download | poky-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.py | 21 |
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 | |||
9 | import signal | 9 | import signal |
10 | import socket | 10 | import socket |
11 | import sys | 11 | import sys |
12 | import multiprocessing | ||
12 | from . import chunkify, DEFAULT_MAX_CHUNK | 13 | from . 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) | ||