summaryrefslogtreecommitdiff
path: root/cpp/src/Ice/Application.cpp
diff options
context:
space:
mode:
authorJoe George <joe@zeroc.com>2015-03-03 17:30:50 -0500
committerJoe George <joe@zeroc.com>2015-05-12 11:41:55 -0400
commitd35bb9f5c19e34aee31f83d445695a8186ef675e (patch)
treed5324eaf44f5f9776495537c51653f50a66a7237 /cpp/src/Ice/Application.cpp
downloadice-d35bb9f5c19e34aee31f83d445695a8186ef675e.tar.bz2
ice-d35bb9f5c19e34aee31f83d445695a8186ef675e.tar.xz
ice-d35bb9f5c19e34aee31f83d445695a8186ef675e.zip
Ice 3.4.2 Source Distributionv3.4.2
Diffstat (limited to 'cpp/src/Ice/Application.cpp')
-rw-r--r--cpp/src/Ice/Application.cpp740
1 files changed, 740 insertions, 0 deletions
diff --git a/cpp/src/Ice/Application.cpp b/cpp/src/Ice/Application.cpp
new file mode 100644
index 00000000000..8be66fa56e4
--- /dev/null
+++ b/cpp/src/Ice/Application.cpp
@@ -0,0 +1,740 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <Ice/Application.h>
+#include <Ice/LoggerI.h>
+#include <IceUtil/Mutex.h>
+#include <IceUtil/CtrlCHandler.h>
+#include <IceUtil/Cond.h>
+#include <IceUtil/ArgVector.h>
+#include <Ice/GC.h>
+#include <memory>
+
+using namespace std;
+using namespace Ice;
+using namespace IceUtil;
+using namespace IceUtilInternal;
+
+
+//
+// static initializations.
+//
+Mutex* IceInternal::Application::mutex = 0;
+
+bool IceInternal::Application::_callbackInProgress = false;
+bool IceInternal::Application::_destroyed = false;
+bool IceInternal::Application::_interrupted = false;
+
+string IceInternal::Application::_appName;
+CommunicatorPtr IceInternal::Application::_communicator;
+SignalPolicy IceInternal::Application::_signalPolicy = HandleSignals;
+Cond* IceInternal::Application::_condVar;
+Application* IceInternal::Application::_application;
+//
+// _mutex and _condVar are used to synchronize the main thread and
+// the CtrlCHandler thread
+//
+
+namespace
+{
+
+class Init
+{
+public:
+
+ Init()
+ {
+ IceInternal::Application::mutex = new IceUtil::Mutex;
+ IceInternal::Application::_condVar = new Cond();
+ }
+
+ ~Init()
+ {
+ delete IceInternal::Application::mutex;
+ IceInternal::Application::mutex = 0;
+ delete IceInternal::Application::_condVar;
+ IceInternal::Application::_condVar = 0;
+ }
+};
+
+Init init;
+
+
+
+//
+// Variables than can change while run() and communicator->destroy() are running!
+//
+bool _released = false;
+CtrlCHandlerCallback _previousCallback = 0;
+
+//
+// Variables that are immutable during run() and until communicator->destroy() has returned;
+// before and after run(), and once communicator->destroy() has returned, we assume that
+// only the main thread and CtrlCHandler threads are running.
+//
+CtrlCHandler* _ctrlCHandler = 0;
+bool _nohup = false;
+
+}
+
+#ifdef _WIN32
+const DWORD SIGHUP = CTRL_LOGOFF_EVENT;
+#else
+# include <csignal>
+#endif
+
+//
+// Compaq C++ defines signal() as a macro, causing problems with the _condVar->signal()
+// statement, which the compiler for some reason replaces by the macro.
+//
+#if defined (__digital__) && defined (__unix__)
+# undef signal
+#endif
+
+//
+// CtrlCHandler callbacks.
+//
+
+static void
+holdInterruptCallback(int signal)
+{
+ CtrlCHandlerCallback callback = 0;
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex);
+ while(!_released)
+ {
+ IceInternal::Application::_condVar->wait(lock);
+ }
+
+ if(IceInternal::Application::_destroyed)
+ {
+ //
+ // Being destroyed by main thread
+ //
+ return;
+ }
+ assert(_ctrlCHandler != 0);
+ callback = _ctrlCHandler->getCallback();
+ }
+
+ if(callback != 0)
+ {
+ callback(signal);
+ }
+}
+
+static void
+destroyOnInterruptCallback(int signal)
+{
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex);
+ if(IceInternal::Application::_destroyed)
+ {
+ //
+ // Being destroyed by main thread
+ //
+ return;
+ }
+ if(_nohup && signal == SIGHUP)
+ {
+ return;
+ }
+
+ assert(!IceInternal::Application::_callbackInProgress);
+ IceInternal::Application::_callbackInProgress = true;
+ IceInternal::Application::_interrupted = true;
+ IceInternal::Application::_destroyed = true;
+ }
+
+ try
+ {
+ assert(IceInternal::Application::_communicator != 0);
+ IceInternal::Application::_communicator->destroy();
+ }
+ catch(const std::exception& ex)
+ {
+ Error out(getProcessLogger());
+ out << "(while destroying in response to signal " << signal << "): " << ex;
+ }
+ catch(const std::string& msg)
+ {
+ Error out(getProcessLogger());
+ out << "(while destroying in response to signal " << signal << "): " << msg;
+ }
+ catch(const char* msg)
+ {
+ Error out(getProcessLogger());
+ out << "(while destroying in response to signal " << signal << "): " << msg;
+ }
+ catch(...)
+ {
+ Error out(getProcessLogger());
+ out << "(while destroying in response to signal " << signal << "): unknown exception";
+ }
+
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex);
+ IceInternal::Application::_callbackInProgress = false;
+ }
+ IceInternal::Application::_condVar->signal();
+}
+
+static void
+shutdownOnInterruptCallback(int signal)
+{
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex);
+ if(IceInternal::Application::_destroyed)
+ {
+ //
+ // Being destroyed by main thread
+ //
+ return;
+ }
+ if(_nohup && signal == SIGHUP)
+ {
+ return;
+ }
+
+ assert(!IceInternal::Application::_callbackInProgress);
+ IceInternal::Application::_callbackInProgress = true;
+ IceInternal::Application::_interrupted = true;
+ }
+
+ try
+ {
+ assert(IceInternal::Application::_communicator != 0);
+ IceInternal::Application::_communicator->shutdown();
+ }
+ catch(const std::exception& ex)
+ {
+ Error out(getProcessLogger());
+ out << "(while shutting down in response to signal " << signal << "): std::exception: " << ex;
+ }
+ catch(const std::string& msg)
+ {
+ Error out(getProcessLogger());
+ out << "(while shutting down in response to signal " << signal << "): " << msg;
+ }
+ catch(const char* msg)
+ {
+ Error out(getProcessLogger());
+ out << "(while shutting down in response to signal " << signal << "): " << msg;
+ }
+ catch(...)
+ {
+ Error out(getProcessLogger());
+ out << "(while shutting down in response to signal " << signal << "): unknown exception";
+ }
+
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex);
+ IceInternal::Application::_callbackInProgress = false;
+ }
+ IceInternal::Application::_condVar->signal();
+}
+
+static void
+callbackOnInterruptCallback(int signal)
+{
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex);
+ if(IceInternal::Application::_destroyed)
+ {
+ //
+ // Being destroyed by main thread
+ //
+ return;
+ }
+ // For SIGHUP the user callback is always called. It can
+ // decide what to do.
+ assert(!IceInternal::Application::_callbackInProgress);
+ IceInternal::Application::_callbackInProgress = true;
+ IceInternal::Application::_interrupted = true;
+ }
+
+ try
+ {
+ assert(IceInternal::Application::_application != 0);
+ IceInternal::Application::_application->interruptCallback(signal);
+ }
+ catch(const std::exception& ex)
+ {
+ Error out(getProcessLogger());
+ out << "(while interrupting in response to signal " << signal << "): std::exception: " << ex;
+ }
+ catch(const std::string& msg)
+ {
+ Error out(getProcessLogger());
+ out << "(while interrupting in response to signal " << signal << "): " << msg;
+ }
+ catch(const char* msg)
+ {
+ Error out(getProcessLogger());
+ out << "(while interrupting in response to signal " << signal << "): " << msg;
+ }
+ catch(...)
+ {
+ Error out(getProcessLogger());
+ out << "(while interrupting in response to signal " << signal << "): unknown exception";
+ }
+
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex);
+ IceInternal::Application::_callbackInProgress = false;
+ }
+ IceInternal::Application::_condVar->signal();
+}
+
+Ice::Application::Application(SignalPolicy signalPolicy)
+{
+ IceInternal::Application::_signalPolicy = signalPolicy;
+}
+
+Ice::Application::~Application()
+{
+}
+
+int
+Ice::Application::main(int argc, char* argv[], const char* configFile)
+{
+ //
+ // We don't call the main below to avoid a deprecated warning
+ //
+
+ IceInternal::Application::_appName = "";
+ if(argc > 0)
+ {
+ IceInternal::Application::_appName = argv[0];
+ }
+
+ if(argc > 0 && argv[0] && LoggerIPtr::dynamicCast(getProcessLogger()))
+ {
+ setProcessLogger(new LoggerI(argv[0], ""));
+ }
+
+ InitializationData initData;
+ if(configFile)
+ {
+ try
+ {
+ initData.properties = createProperties();
+ initData.properties->load(configFile);
+ }
+ catch(const std::exception& ex)
+ {
+ Error out(getProcessLogger());
+ out << ex;
+ return EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ Error out(getProcessLogger());
+ out << "unknown exception";
+ return EXIT_FAILURE;
+ }
+ }
+ return main(argc, argv, initData);
+}
+
+#ifdef _WIN32
+
+int
+Ice::Application::main(int argc, wchar_t* argv[], const char* config)
+{
+ return main(argsToStringSeq(argc, argv), config);
+}
+
+int
+Ice::Application::main(int argc, wchar_t* argv[], const Ice::InitializationData& initData)
+{
+ //
+ // On Windows the given wchar_t* strings are UTF16 and therefore
+ // needs to be converted to native narow string encoding.
+ //
+ return main(argsToStringSeq(argc, argv, initData.stringConverter), initData);
+}
+
+#endif
+
+int
+Ice::Application::main(int argc, char* argv[], const InitializationData& initializationData)
+{
+ if(argc > 0 && argv[0] && LoggerIPtr::dynamicCast(getProcessLogger()))
+ {
+ setProcessLogger(new LoggerI(argv[0], ""));
+ }
+
+ if(IceInternal::Application::_communicator != 0)
+ {
+ Error out(getProcessLogger());
+ out << "only one instance of the Application class can be used";
+ return EXIT_FAILURE;
+ }
+ int status;
+
+ //
+ // We parse the properties here to extract Ice.ProgramName.
+ //
+ InitializationData initData = initializationData;
+ initData.properties = createProperties(argc, argv, initData.properties, initData.stringConverter);
+
+ IceInternal::Application::_appName = initData.properties->getPropertyWithDefault("Ice.ProgramName",
+ IceInternal::Application::_appName);
+
+ //
+ // Used by destroyOnInterruptCallback and shutdownOnInterruptCallback.
+ //
+ _nohup = initData.properties->getPropertyAsInt("Ice.Nohup") > 0;
+
+ IceInternal::Application::_application = this;
+
+ if(IceInternal::Application::_signalPolicy == HandleSignals)
+ {
+ try
+ {
+ //
+ // The ctrlCHandler must be created before starting any thread, in particular
+ // before initializing the communicator.
+ //
+ CtrlCHandler ctrCHandler;
+ _ctrlCHandler = &ctrCHandler;
+
+ status = doMain(argc, argv, initData);
+
+ //
+ // Set _ctrlCHandler to 0 only once communicator->destroy() has completed.
+ //
+ _ctrlCHandler = 0;
+ }
+ catch(const CtrlCHandlerException&)
+ {
+ Error out(getProcessLogger());
+ out << "only one instance of the CtrlCHandler class can be used";
+ status = EXIT_FAILURE;
+ }
+ }
+ else
+ {
+ status = doMain(argc, argv, initData);
+ }
+
+ return status;
+}
+
+int
+Ice::Application::main(int argc, char* const argv[], const char* configFile)
+{
+ ArgVector av(argc, argv);
+ return main(av.argc, av.argv, configFile);
+}
+
+int
+Ice::Application::main(int argc, char* const argv[], const Ice::InitializationData& initData)
+{
+ ArgVector av(argc, argv);
+ return main(av.argc, av.argv, initData);
+}
+
+int
+Ice::Application::main(const StringSeq& args, const char* configFile)
+{
+ ArgVector av(args);
+ return main(av.argc, av.argv, configFile);
+}
+
+int
+Ice::Application::main(const StringSeq& args, const InitializationData& initData)
+{
+ ArgVector av(args);
+ return main(av.argc, av.argv, initData);
+}
+
+void
+Ice::Application::interruptCallback(int)
+{
+}
+
+const char*
+Ice::Application::appName()
+{
+ return IceInternal::Application::_appName.c_str();
+}
+
+CommunicatorPtr
+Ice::Application::communicator()
+{
+ return IceInternal::Application::_communicator;
+}
+
+void
+Ice::Application::destroyOnInterrupt()
+{
+ if(IceInternal::Application::_signalPolicy == HandleSignals)
+ {
+ if(_ctrlCHandler != 0)
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex); // we serialize all the interrupt-setting
+ if(_ctrlCHandler->getCallback() == holdInterruptCallback)
+ {
+ _released = true;
+ IceInternal::Application::_condVar->signal();
+ }
+ _ctrlCHandler->setCallback(destroyOnInterruptCallback);
+ }
+ }
+ else
+ {
+ Warning out(getProcessLogger());
+ out << "interrupt method called on Application configured to not handle interrupts.";
+ }
+}
+
+void
+Ice::Application::shutdownOnInterrupt()
+{
+ if(IceInternal::Application::_signalPolicy == HandleSignals)
+ {
+ if(_ctrlCHandler != 0)
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex); // we serialize all the interrupt-setting
+ if(_ctrlCHandler->getCallback() == holdInterruptCallback)
+ {
+ _released = true;
+ IceInternal::Application::_condVar->signal();
+ }
+ _ctrlCHandler->setCallback(shutdownOnInterruptCallback);
+ }
+ }
+ else
+ {
+ Warning out(getProcessLogger());
+ out << "interrupt method called on Application configured to not handle interrupts.";
+ }
+}
+
+void
+Ice::Application::ignoreInterrupt()
+{
+ if(IceInternal::Application::_signalPolicy == HandleSignals)
+ {
+ if(_ctrlCHandler != 0)
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex); // we serialize all the interrupt-setting
+ if(_ctrlCHandler->getCallback() == holdInterruptCallback)
+ {
+ _released = true;
+ IceInternal::Application::_condVar->signal();
+ }
+ _ctrlCHandler->setCallback(0);
+ }
+ }
+ else
+ {
+ Warning out(getProcessLogger());
+ out << "interrupt method called on Application configured to not handle interrupts.";
+ }
+}
+
+void
+Ice::Application::callbackOnInterrupt()
+{
+ if(IceInternal::Application::_signalPolicy == HandleSignals)
+ {
+ if(_ctrlCHandler != 0)
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex); // we serialize all the interrupt-setting
+ if(_ctrlCHandler->getCallback() == holdInterruptCallback)
+ {
+ _released = true;
+ IceInternal::Application::_condVar->signal();
+ }
+ _ctrlCHandler->setCallback(callbackOnInterruptCallback);
+ }
+ }
+ else
+ {
+ Warning out(getProcessLogger());
+ out << "interrupt method called on Application configured to not handle interrupts.";
+ }
+}
+
+void
+Ice::Application::holdInterrupt()
+{
+ if(IceInternal::Application::_signalPolicy == HandleSignals)
+ {
+ if(_ctrlCHandler != 0)
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex); // we serialize all the interrupt-setting
+ if(_ctrlCHandler->getCallback() != holdInterruptCallback)
+ {
+ _previousCallback = _ctrlCHandler->getCallback();
+ _released = false;
+ _ctrlCHandler->setCallback(holdInterruptCallback);
+ }
+ // else, we were already holding signals
+ }
+ }
+ else
+ {
+ Warning out(getProcessLogger());
+ out << "interrupt method called on Application configured to not handle interrupts.";
+ }
+}
+
+void
+Ice::Application::releaseInterrupt()
+{
+ if(IceInternal::Application::_signalPolicy == HandleSignals)
+ {
+ if(_ctrlCHandler != 0)
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex); // we serialize all the interrupt-setting
+ if(_ctrlCHandler->getCallback() == 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.
+ //
+
+ _released = true;
+ _ctrlCHandler->setCallback(_previousCallback);
+ IceInternal::Application::_condVar->signal();
+ }
+ // Else nothing to release.
+ }
+ }
+ else
+ {
+ Warning out(getProcessLogger());
+ out << "interrupt method called on Application configured to not handle interrupts.";
+ }
+}
+
+bool
+Ice::Application::interrupted()
+{
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex);
+ return IceInternal::Application::_interrupted;
+}
+
+int
+Ice::Application::doMain(int argc, char* argv[], const InitializationData& initData)
+{
+ int status;
+
+ try
+ {
+ IceInternal::Application::_interrupted = false;
+
+ //
+ // If the process logger is the default logger, we now replace it with a
+ // a logger which is using the program name for the prefix.
+ //
+ if(initData.properties->getProperty("Ice.ProgramName") != "" && LoggerIPtr::dynamicCast(getProcessLogger()))
+ {
+ setProcessLogger(new LoggerI(initData.properties->getProperty("Ice.ProgramName"), ""));
+ }
+
+ IceInternal::Application::_communicator = initialize(argc, argv, initData);
+ IceInternal::Application::_destroyed = false;
+
+ //
+ // The default is to destroy when a signal is received.
+ //
+ if(IceInternal::Application::_signalPolicy == HandleSignals)
+ {
+ destroyOnInterrupt();
+ }
+
+ status = run(argc, argv);
+ }
+ catch(const std::exception& ex)
+ {
+ Error out(getProcessLogger());
+ out << ex;
+ status = EXIT_FAILURE;
+ }
+ catch(const std::string& msg)
+ {
+ Error out(getProcessLogger());
+ out << msg;
+ status = EXIT_FAILURE;
+ }
+ catch(const char* msg)
+ {
+ Error out(getProcessLogger());
+ out << msg;
+ status = EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ Error out(getProcessLogger());
+ out << "unknown exception";
+ status = EXIT_FAILURE;
+ }
+
+ //
+ // Don't want any new interrupt and at this point (post-run),
+ // it would not make sense to release a held signal to run
+ // shutdown or destroy.
+ //
+ if(IceInternal::Application::_signalPolicy == HandleSignals)
+ {
+ ignoreInterrupt();
+ }
+
+ {
+ IceUtil::Mutex::Lock lock(*IceInternal::Application::mutex);
+ while(IceInternal::Application::_callbackInProgress)
+ {
+ IceInternal::Application::_condVar->wait(lock);
+ }
+ if(IceInternal::Application::_destroyed)
+ {
+ IceInternal::Application::_communicator = 0;
+ }
+ else
+ {
+ IceInternal::Application::_destroyed = true;
+ //
+ // And _communicator != 0, meaning will be destroyed
+ // next, _destroyed = true also ensures that any
+ // remaining callback won't do anything
+ //
+ }
+ IceInternal::Application::_application = 0;
+ }
+
+ if(IceInternal::Application::_communicator != 0)
+ {
+ try
+ {
+ IceInternal::Application::_communicator->destroy();
+ }
+ catch(const std::exception& ex)
+ {
+ Error out(getProcessLogger());
+ out << ex;
+ status = EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ Error out(getProcessLogger());
+ out << "unknown exception";
+ status = EXIT_FAILURE;
+ }
+ IceInternal::Application::_communicator = 0;
+ }
+
+ return status;
+}