diff options
author | Bernard Normier <bernard@zeroc.com> | 2003-04-18 21:44:09 +0000 |
---|---|---|
committer | Bernard Normier <bernard@zeroc.com> | 2003-04-18 21:44:09 +0000 |
commit | ab818e033a7c29898da7778a75bd69a2bcf530c5 (patch) | |
tree | 9f15cdc381f1c3cdbdd327120c43060d55b9ee16 /cpp/src/IceUtil/CtrlCHandler.cpp | |
parent | bug fix for service shutdown (diff) | |
download | ice-ab818e033a7c29898da7778a75bd69a2bcf530c5.tar.bz2 ice-ab818e033a7c29898da7778a75bd69a2bcf530c5.tar.xz ice-ab818e033a7c29898da7778a75bd69a2bcf530c5.zip |
StaticMutex, CtrlCHandler and Applicaton signal handling update
Diffstat (limited to 'cpp/src/IceUtil/CtrlCHandler.cpp')
-rw-r--r-- | cpp/src/IceUtil/CtrlCHandler.cpp | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/cpp/src/IceUtil/CtrlCHandler.cpp b/cpp/src/IceUtil/CtrlCHandler.cpp new file mode 100644 index 00000000000..9c7c53220dc --- /dev/null +++ b/cpp/src/IceUtil/CtrlCHandler.cpp @@ -0,0 +1,208 @@ +// ********************************************************************** +// +// Copyright (c) 2003 +// ZeroC, Inc. +// Billerica, MA, USA +// +// All Rights Reserved. +// +// Ice is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 2 as published by +// the Free Software Foundation. +// +// ********************************************************************** + +#include <IceUtil/CtrlCHandler.h> +#include <IceUtil/StaticMutex.h> + +#ifndef _WIN32 +# ifdef __sun +# define _POSIX_PTHREAD_SEMANTICS +# endif +# include <signal.h> +#endif + +using namespace std; +using namespace IceUtil; + +static CtrlCHandlerCallback _callback = 0; +static const CtrlCHandler* _handler = 0; + +CtrlCHandlerException::CtrlCHandlerException(const char* file, int line) : + Exception(file, line) +{ +} + +string +CtrlCHandlerException::ice_name() const +{ + return "IceUtil::CtrlCHandlerException"; +} + +Exception* +CtrlCHandlerException::ice_clone() const +{ + return new CtrlCHandlerException(*this); +} + +void +CtrlCHandlerException::ice_throw() const +{ + throw *this; +} + +void +CtrlCHandler::setCallback(CtrlCHandlerCallback callback) +{ + StaticMutex::Lock lock(globalMutex); + _callback = callback; +} + +CtrlCHandlerCallback +CtrlCHandler::getCallback() const +{ + StaticMutex::Lock lock(globalMutex); + return _callback; +} + +#ifdef _WIN32 + +static BOOL WINAPI handlerRoutine(DWORD dwCtrlType) +{ + CtrlCHandlerCallback callback = _handler->getCallback(); + if(callback != 0) + { + try + { + callback(dwCtrlType); + } + catch(...) + { + assert(0); + } + } + return TRUE; +} + + +CtrlCHandler::CtrlCHandler(CtrlCHandlerCallback callback) +{ + StaticMutex::Lock lock(globalMutex); + if(_handler != 0) + { + throw CtrlCHandlerException(__FILE__, __LINE__); + } + else + { + _callback = callback; + _handler = this; + lock.release(); + SetConsoleCtrlHandler(handlerRoutine, TRUE); + } +} + +CtrlCHandler::~CtrlCHandler() +{ + SetConsoleCtrlHandler(handlerRoutine, FALSE); + { + StaticMutex::Lock lock(globalMutex); + _handler = 0; + } +} + +#else + +extern "C" +{ + +static void* +sigwaitThread(void*) +{ + sigset_t ctrlCLikeSignals; + sigemptyset(&ctrlCLikeSignals); + sigaddset(&ctrlCLikeSignals, SIGHUP); + sigaddset(&ctrlCLikeSignals, SIGINT); + sigaddset(&ctrlCLikeSignals, SIGTERM); + + // Run until I'm cancelled (in sigwait()) + // + for(;;) + { + int signal = 0; + int rc = sigwait(&ctrlCLikeSignals, &signal); + assert(rc == 0); + + rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); + assert(rc == 0); + + CtrlCHandlerCallback callback = _handler->getCallback(); + + if(callback != 0) + { + try + { + callback(signal); + } + catch(...) + { + assert(0); + } + } + + rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); + assert(rc == 0); + } + return 0; +} +} + +static pthread_t _tid; + +CtrlCHandler::CtrlCHandler(CtrlCHandlerCallback callback) +{ + StaticMutex::Lock lock(globalMutex); + if(_handler != 0) + { + throw CtrlCHandlerException(__FILE__, __LINE__); + } + else + { + _callback = callback; + _handler = this; + lock.release(); + + // We block these CTRL+C like signals in the main thread, + // and by default all other threads will inherit this signal + // disposition. + + sigset_t ctrlCLikeSignals; + sigemptyset(&ctrlCLikeSignals); + sigaddset(&ctrlCLikeSignals, SIGHUP); + sigaddset(&ctrlCLikeSignals, SIGINT); + sigaddset(&ctrlCLikeSignals, SIGTERM); + int rc = pthread_sigmask(SIG_BLOCK, &ctrlCLikeSignals, 0); + assert(rc == 0); + + // Joinable thread + rc = pthread_create(&_tid, 0, sigwaitThread, 0); + assert(rc == 0); + } +} + +CtrlCHandler::~CtrlCHandler() +{ + int rc = pthread_cancel(_tid); + assert(rc == 0); + void* status = 0; + rc = pthread_join(_tid, &status); + assert(rc == 0); + assert(status == PTHREAD_CANCELED); + + { + StaticMutex::Lock lock(globalMutex); + _handler = 0; + } +} + +#endif + |