diff options
author | Mark Spruiell <mes@zeroc.com> | 2004-09-16 19:33:42 +0000 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2004-09-16 19:33:42 +0000 |
commit | cc74b8d3017a3bfc302e84f006d50ac72c86409b (patch) | |
tree | 00a06d58ca12d7357f32829faec3ab0ec274a2eb /py/python/Ice.py | |
parent | *** empty log message *** (diff) | |
download | ice-cc74b8d3017a3bfc302e84f006d50ac72c86409b.tar.bz2 ice-cc74b8d3017a3bfc302e84f006d50ac72c86409b.tar.xz ice-cc74b8d3017a3bfc302e84f006d50ac72c86409b.zip |
adding signal support to Ice.Application
Diffstat (limited to 'py/python/Ice.py')
-rw-r--r-- | py/python/Ice.py | 158 |
1 files changed, 146 insertions, 12 deletions
diff --git a/py/python/Ice.py b/py/python/Ice.py index 9a36f3326fd..213728682e7 100644 --- a/py/python/Ice.py +++ b/py/python/Ice.py @@ -352,14 +352,17 @@ def getDefaultProperties(args=[]): return PropertiesI(properties) # +# The variables below need to be global in order to properly reference a +# static method of Application. +# +_ctrlCHandler = None +_previousCallback = None + +# # Application class. # +import threading, signal class Application(object): - def __init__(self): - pass - - def __del__(self): - pass def main(self, args, configFile=None): if Application._communicator: @@ -369,6 +372,14 @@ class Application(object): Application._interrupted = False Application._appName = args[0] + # + # Install our handler for the signals we are interested in. We assume main() + # is called from the main thread. + # + signal.signal(signal.SIGHUP, Application.signalHandler) + signal.signal(signal.SIGINT, Application.signalHandler) + signal.signal(signal.SIGTERM, Application.signalHandler) + status = 0 try: @@ -380,11 +391,27 @@ class Application(object): Application._communicator = initialize(args) # + # Used by destroyOnInterruptCallback and shutdownOnInterruptCallback. + # + Application._nohup = Application._communicator.getProperties().getPropertyAsInt("Ice.Nohup") > 0 + + # # The default is to destroy when a signal is received. # Application.destroyOnInterrupt() - status = self.run(args) + # + # Don't call run() from the main thread. Instead, start a new thread and + # let it invoke run(). Because Python only delivers signals to the main + # thread, we have to make sure the main thread isn't busy (which it would + # be if the run() method invoked a blocking C function such as + # waitForShutdown()). + # + t = Application.RunThread(self, args) + t.start() + while t.isAlive(): + t.join(1) + status = t.status except Exception, ex: print Application._appName + ": " + str(ex) status = 1 @@ -420,33 +447,140 @@ class Application(object): communicator = staticmethod(communicator) def destroyOnInterrupt(): - pass + global _ctrlCHandler + Application._condVar.acquire() + if _ctrlCHandler == Application.holdInterruptCallback: + Application._released = True + _ctrlCHandler = Application.destroyOnInterruptCallback + Application._condVar.notify() + else: + _ctrlCHandler = Application.destroyOnInterruptCallback + Application._condVar.release() destroyOnInterrupt = staticmethod(destroyOnInterrupt) def shutdownOnInterrupt(): - pass + global _ctrlCHandler + Application._condVar.acquire() + if _ctrlCHandler == Application.holdInterruptCallback: + Application._released = True + _ctrlCHandler = Application.shutdownOnInterruptCallback + Application._condVar.notify() + else: + _ctrlCHandler = Application.shutdownOnInterruptCallback + Application._condVar.release() shutdownOnInterrupt = staticmethod(shutdownOnInterrupt) def ignoreInterrupt(): - pass + global _ctrlCHandler + Application._condVar.acquire() + if _ctrlCHandler == Application.holdInterruptCallback: + Application._released = True + _ctrlCHandler = None + Application._condVar.notify() + else: + _ctrlCHandler = None + Application._condVar.release() ignoreInterrupt = staticmethod(ignoreInterrupt) def holdInterrupt(): - pass + global _ctrlCHandler, _previousCallback + Application._condVar.acquire() + if _ctrlCHandler != Application.holdInterruptCallback: + _previousCallback = _ctrlCHandler + Application._released = False + _ctrlCHandler = Application.holdInterruptCallback + # else, we were already holding signals + Application._condVar.release() holdInterrupt = staticmethod(holdInterrupt) def releaseInterrupt(): - pass + global _ctrlCHandler, _previousCallback + Application._condVar.acquire() + if _ctrlCHandler == Application.holdInterruptCallback: + # + # Note that it's very possible no signal is held; + # in this case the callback is just replaced and + # setting _released to true and signalling _condVar + # do no harm. + # + Application._released = True + _ctrlCHandler = _previousCallback + Application._condVar.notify() + # Else nothing to release. + Application._condVar.release() releaseInterrupt = staticmethod(releaseInterrupt) def interrupted(): - pass + Application._condVar.acquire() + result = Application._interrupted + Application._condVar.release() + return result interrupted = staticmethod(interrupted) + def signalHandler(sig, frame): + global _ctrlCHandler + if _ctrlCHandler: + _ctrlCHandler(sig) + signalHandler = staticmethod(signalHandler) + + def holdInterruptCallback(sig): + global _ctrlCHandler + Application._condVar.acquire() + while not Application._released: + Application._condVar.wait(1) + Application._condVar.release() + + # + # Use the current callback to process this (old) signal. + # + if _ctrlCHandler: + _ctrlCHandler(sig) + holdInterruptCallback = staticmethod(holdInterruptCallback) + + def destroyOnInterruptCallback(sig): + if Application._nohup and sig == signal.SIGHUP: + return + + Application._condVar.acquire() + Application._interrupted = True + Application._condVar.release() + + try: + Application._communicator.destroy() + except exceptions.Exception, ex: + print Application._appName + " (while destroying in response to signal " + str(sig) + "): " + str(ex) + destroyOnInterruptCallback = staticmethod(destroyOnInterruptCallback) + + def shutdownOnInterruptCallback(sig): + if Application._nohup and sig == signal.SIGHUP: + return + + Application._condVar.acquire() + Application._interrupted = True + Application._condVar.release() + + try: + Application._communicator.shutdown() + except exceptions.Exception, ex: + print Application._appName + " (while shutting down in response to signal " + str(sig) + "): " + str(ex) + shutdownOnInterruptCallback = staticmethod(shutdownOnInterruptCallback) + + class RunThread(threading.Thread): + def __init__(self, app, args): + threading.Thread.__init__(self) + self.app = app + self.args = args + self.status = 0 + + def run(self): + self.status = self.app.run(self.args) + _appName = None _communicator = None _interrupted = False _released = False + _mutex = threading.Lock() + _condVar = threading.Condition() # # Define Ice::Object and Ice::ObjectPrx. |