From 588d339f2bde8ab6547bc0c1c4e7b83310b1318f Mon Sep 17 00:00:00 2001 From: Bob Foerster Date: Fri, 26 Nov 2010 16:15:36 -0500 Subject: server: fix interrupt handling for process SIGINT is now blocked within the server context, thus allowing the UI to fully handle all user interaction. There is no longer a need to check for KeyboardInterrupt Exceptions anywhere within the server context. Signed-off-by: Bob Foerster Signed-off-by: Chris Larson --- lib/bb/cooker.py | 15 ++++++------ lib/bb/event.py | 3 ++- lib/bb/server/process.py | 64 +++++++++++++++++++++++++----------------------- 3 files changed, 44 insertions(+), 38 deletions(-) (limited to 'lib') diff --git a/lib/bb/cooker.py b/lib/bb/cooker.py index 62c8d2803..ea362e2e2 100644 --- a/lib/bb/cooker.py +++ b/lib/bb/cooker.py @@ -104,6 +104,8 @@ class BBCooker: self.command = bb.command.Command(self) self.state = state.initial + self.parser = None + def parseConfiguration(self): @@ -738,6 +740,10 @@ class BBCooker: if self.state == state.running: return + if self.state in (state.shutdown, state.stop): + self.parser.shutdown(clean=False) + sys.exit(1) + if self.state != state.parsing: self.parseConfiguration () @@ -883,10 +889,9 @@ class BBCooker: return self.appendlist[f] return [] - def shutdown(self): self.state = state.shutdown - + def stop(self): self.state = state.stop @@ -965,7 +970,7 @@ class CookerParser(object): sync = threading.Thread(target=self.bb_cache.sync) sync.start() - atexit.register(lambda: sync.join()) + multiprocessing.util.Finalize(None, sync.join, exitpriority=-100) def load_cached(self): for filename, appends in self.fromcache: @@ -978,14 +983,10 @@ class CookerParser(object): except StopIteration: self.shutdown() return False - except KeyboardInterrupt: - self.shutdown(clean=False) - raise except Exception as exc: self.shutdown(clean=False) bb.fatal('Error parsing %s: %s' % (exc.recipe, exc)) - self.current += 1 self.virtuals += len(result) if parsed: diff --git a/lib/bb/event.py b/lib/bb/event.py index 3f291ec27..647d02935 100644 --- a/lib/bb/event.py +++ b/lib/bb/event.py @@ -338,9 +338,10 @@ class CacheLoadProgress(Event): class CacheLoadCompleted(Event): """Cache loading is complete""" - def __init__(self, total): + def __init__(self, total, num_entries): Event.__init__(self) self.total = total + self.num_entries = num_entries class DepTreeGenerated(Event): diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py index 541c0c4d9..f3ad5da60 100644 --- a/lib/bb/server/process.py +++ b/lib/bb/server/process.py @@ -20,8 +20,9 @@ This module implements a multiprocessing.Process based server for bitbake. """ -import time import logging +import signal +import time import bb import bb.event from multiprocessing import Process, Event @@ -29,31 +30,21 @@ from bb.cooker import BBCooker logger = logging.getLogger('BitBake') - -class BitBakeServerCommands(): - def __init__(self, server, cooker): - self.cooker = cooker - self.server = server +class ServerCommunicator(): + def __init__(self, connection): + self.connection = connection def runCommand(self, command): - """ - Run a cooker command on the server - """ - self.server.command_channel.send(self.cooker.command.runCommand(command)) + # @todo try/except + self.connection.send(command) - def terminateServer(self): - """ - Trigger the server to quit - """ - self.server.stop() - #print "Server (cooker) exitting" - return - - def ping(self): - """ - Dummy method which can be used to check the server is still alive - """ - return True + while True: + # don't let the user ctrl-c while we're waiting for a response + try: + result = self.connection.recv() + return result + except KeyboardInterrupt: + pass class EventAdapter(): @@ -80,7 +71,6 @@ class ProcessServer(Process): self.configuration = configuration self.cooker = BBCooker(configuration, self.register_idle_function) self._idlefunctions = {} - self.commands = BitBakeServerCommands(self, self.cooker) self.event_handle = bb.event.register_UIHhandler(self) self.quit = False @@ -99,12 +89,22 @@ class ProcessServer(Process): # Ensure logging messages get sent to the UI as events logger.addHandler(bb.event.LogHandler()) + # Ignore SIGINT within the server, as all SIGINT handling is done by + # the UI and communicated to us + signal.signal(signal.SIGINT, signal.SIG_IGN) while self.keep_running.is_set(): - if self.command_channel.poll(): - command = self.command_channel.recv() - self.commands.runCommand(command) + try: + if self.command_channel.poll(): + command = self.command_channel.recv() + self.runCommand(command) + + self.idle_commands(.1) + except Exception, exc: + logger.exception('Running command %s', command) - self.idle_commands(.1) + self.event_queue.cancel_join_thread() + bb.event.unregister_UIHhandler(self.event_handle) + self.command_channel.close() return def idle_commands(self, delay): @@ -129,7 +129,11 @@ class ProcessServer(Process): if nextsleep is not None: time.sleep(nextsleep) + def runCommand(self, command): + """ + Run a cooker command on the server + """ + self.command_channel.send(self.cooker.command.runCommand(command)) + def stop(self): self.keep_running.clear() - bb.event.unregister_UIHhandler(self.event_handle) - self.command_channel.close() -- cgit 1.2.3-korg