1 // **********************************************************************
3 // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
8 // **********************************************************************
11 # define _POSIX_PTHREAD_SEMANTICS
14 #include <IceUtil/CtrlCHandler.h>
15 #include <IceUtil/MutexPtrLock.h>
16 #include <IceUtil/Mutex.h>
23 using namespace IceUtil
;
28 CtrlCHandlerCallback _callback
= 0;
29 const CtrlCHandler
* _handler
= 0;
31 IceUtil::Mutex
* globalMutex
= 0;
39 globalMutex
= new IceUtil::Mutex
;
53 CtrlCHandlerException::CtrlCHandlerException(const char* file
, int line
) :
58 static const char* ctrlCHandlerName
= "IceUtil::CtrlCHandlerException";
61 CtrlCHandlerException::ice_name() const
63 return ctrlCHandlerName
;
67 CtrlCHandlerException::ice_clone() const
69 return new CtrlCHandlerException(*this);
73 CtrlCHandlerException::ice_throw() const
79 CtrlCHandler::setCallback(CtrlCHandlerCallback callback
)
81 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(globalMutex
);
86 CtrlCHandler::getCallback() const
88 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(globalMutex
);
94 static BOOL WINAPI
handlerRoutine(DWORD dwCtrlType
)
96 CtrlCHandlerCallback callback
= _handler
->getCallback();
105 CtrlCHandler::CtrlCHandler(CtrlCHandlerCallback callback
)
107 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(globalMutex
);
108 bool handler
= _handler
!= 0;
112 throw CtrlCHandlerException(__FILE__
, __LINE__
);
116 _callback
= callback
;
120 SetConsoleCtrlHandler(handlerRoutine
, TRUE
);
124 CtrlCHandler::~CtrlCHandler()
126 SetConsoleCtrlHandler(handlerRoutine
, FALSE
);
128 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(globalMutex
);
141 sigset_t ctrlCLikeSignals
;
142 sigemptyset(&ctrlCLikeSignals
);
143 sigaddset(&ctrlCLikeSignals
, SIGHUP
);
144 sigaddset(&ctrlCLikeSignals
, SIGINT
);
145 sigaddset(&ctrlCLikeSignals
, SIGTERM
);
148 // Run until I'm cancelled (in sigwait())
153 int rc
= sigwait(&ctrlCLikeSignals
, &signal
);
154 #if defined(__APPLE__)
156 // WORKAROUND: sigwait is not a cancelation point on MacOS X. To cancel this thread, the
157 // destructor cancels the thread and send a signal to the thread to unblock sigwait, then
158 // we explicitly test for cancellation.
160 pthread_testcancel();
163 // Some sigwait() implementations incorrectly return EINTR
164 // when interrupted by an unblocked caught signal
172 rc
= pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, 0);
175 CtrlCHandlerCallback callback
= _handler
->getCallback();
182 rc
= pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, 0);
197 CtrlCHandler::CtrlCHandler(CtrlCHandlerCallback callback
)
199 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(globalMutex
);
200 bool handler
= _handler
!= 0;
204 throw CtrlCHandlerException(__FILE__
, __LINE__
);
208 _callback
= callback
;
213 // We block these CTRL+C like signals in the main thread,
214 // and by default all other threads will inherit this signal
217 sigset_t ctrlCLikeSignals
;
218 sigemptyset(&ctrlCLikeSignals
);
219 sigaddset(&ctrlCLikeSignals
, SIGHUP
);
220 sigaddset(&ctrlCLikeSignals
, SIGINT
);
221 sigaddset(&ctrlCLikeSignals
, SIGTERM
);
222 int rc
= pthread_sigmask(SIG_BLOCK
, &ctrlCLikeSignals
, 0);
226 rc
= pthread_create(&_tid
, 0, sigwaitThread
, 0);
231 CtrlCHandler::~CtrlCHandler()
233 int rc
= pthread_cancel(_tid
);
235 #if defined(__APPLE__)
237 // WORKAROUND: sigwait isn't a cancellation point on MacOS X, see
238 // comment in sigwaitThread
240 rc
= pthread_kill(_tid
, SIGTERM
);
241 //assert(rc == 0); For some reaosns, this assert is sometime triggered
244 rc
= pthread_join(_tid
, &status
);
246 #if !defined(__APPLE__)
247 assert(status
== PTHREAD_CANCELED
);
250 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(globalMutex
);