diff options
Diffstat (limited to 'lib/bb/cooker.py')
-rw-r--r-- | lib/bb/cooker.py | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/lib/bb/cooker.py b/lib/bb/cooker.py index d6fcd9e05..7c0c5d4ef 100644 --- a/lib/bb/cooker.py +++ b/lib/bb/cooker.py @@ -2017,6 +2017,22 @@ class Parser(multiprocessing.Process): self.context = bb.utils.get_context().copy() self.handlers = bb.event.get_class_handlers().copy() self.profile = profile + self.queue_signals = False + self.signal_received = [] + self.signal_threadlock = threading.Lock() + + def catch_sig(self, signum, frame): + if self.queue_signals: + self.signal_received.append(signum) + else: + self.handle_sig(signum, frame) + + def handle_sig(self, signum, frame): + if signum == signal.SIGTERM: + signal.signal(signal.SIGTERM, signal.SIG_DFL) + os.kill(os.getpid(), signal.SIGTERM) + elif signum == signal.SIGINT: + signal.default_int_handler(signum, frame) def run(self): @@ -2036,9 +2052,17 @@ class Parser(multiprocessing.Process): prof.dump_stats(logfile) def realrun(self): - signal.signal(signal.SIGTERM, signal.SIG_DFL) + # Signal handling here is hard. We must not terminate any process or thread holding the write + # lock for the event stream as it will not be released, ever, and things will hang. + # Python handles signals in the main thread/process but they can be raised from any thread and + # we want to defer processing of any SIGTERM/SIGINT signal until we're outside the critical section + # and don't hold the lock (see server/process.py). We therefore always catch the signals (so any + # new thread should also do so) and we defer handling but we handle with the local thread lock + # held (a threading lock, not a multiprocessing one) so that no other thread in the process + # can be in the critical section. + signal.signal(signal.SIGTERM, self.catch_sig) signal.signal(signal.SIGHUP, signal.SIG_DFL) - signal.signal(signal.SIGINT, signal.SIG_IGN) + signal.signal(signal.SIGINT, self.catch_sig) bb.utils.set_process_name(multiprocessing.current_process().name) multiprocessing.util.Finalize(None, bb.codeparser.parser_cache_save, exitpriority=1) multiprocessing.util.Finalize(None, bb.fetch.fetcher_parse_save, exitpriority=1) |