diff --git a/client/CClient.cpp b/client/CClient.cpp index 4447d295..de4e7de0 100644 --- a/client/CClient.cpp +++ b/client/CClient.cpp @@ -6,11 +6,12 @@ #include "ISecondaryScreen.h" #include "ProtocolTypes.h" #include "CLock.h" +#include "CLog.h" #include "CThread.h" #include "CTimerThread.h" -#include "XSynergy.h" #include "TMethodJob.h" -#include "CLog.h" +#include "XSynergy.h" +#include "XThread.h" #include #include @@ -71,6 +72,7 @@ void CClient::run(const CNetworkAddress& serverAddress) log((CLOG_ERR "client error: %s", e.what())); // clean up + log((CLOG_NOTE "stopping client")); if (thread != NULL) { thread->cancel(); thread->wait(); @@ -78,10 +80,22 @@ void CClient::run(const CNetworkAddress& serverAddress) } closeSecondaryScreen(); } + catch (XThread&) { + // clean up + log((CLOG_NOTE "stopping client")); + if (thread != NULL) { + thread->cancel(); + thread->wait(); + delete thread; + } + closeSecondaryScreen(); + throw; + } catch (...) { log((CLOG_DEBUG "unknown client error")); // clean up + log((CLOG_NOTE "stopping client")); if (thread != NULL) { thread->cancel(); thread->wait(); diff --git a/client/client.cpp b/client/client.cpp index 1364d83d..4876c527 100644 --- a/client/client.cpp +++ b/client/client.cpp @@ -5,6 +5,7 @@ #include "CNetwork.h" #include "CNetworkAddress.h" #include "CThread.h" +#include "XThread.h" #include // @@ -42,20 +43,24 @@ void realMain(const CString& name, s_logMutex = &logMutex; CLog::setLock(&logLock); - // initialize network library - CNetwork::init(); - CClient* client = NULL; try { + // initialize network library + CNetwork::init(); + + // run client CNetworkAddress addr(hostname, port); client = new CClient(name); client->run(addr); + + // clean up delete client; CNetwork::cleanup(); CLog::setLock(NULL); s_logMutex = NULL; } catch (...) { + // clean up delete client; CNetwork::cleanup(); CLog::setLock(NULL); @@ -93,6 +98,10 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) MessageBox(NULL, msg.c_str(), "error", MB_OK | MB_ICONERROR); return 1; } + catch (XThread&) { + // terminated + return 1; + } } #else @@ -114,6 +123,10 @@ int main(int argc, char** argv) fprintf(stderr, "failed: %s\n", e.what()); return 1; } + catch (XThread&) { + // terminated + return 1; + } } #endif diff --git a/mt/CThread.h b/mt/CThread.h index b6ebe1e3..ae49838c 100644 --- a/mt/CThread.h +++ b/mt/CThread.h @@ -1,7 +1,7 @@ #ifndef CTHREAD_H #define CTHREAD_H -#include "common.h" +#include "BasicTypes.h" class IJob; class CThreadRep; diff --git a/mt/CThreadRep.cpp b/mt/CThreadRep.cpp index 8b48f6b8..4a0f99f4 100644 --- a/mt/CThreadRep.cpp +++ b/mt/CThreadRep.cpp @@ -40,6 +40,9 @@ static void threadDebug(int) CMutex* CThreadRep::s_mutex = NULL; CThreadRep* CThreadRep::s_head = NULL; +#if defined(CONFIG_PTHREADS) +pthread_t CThreadRep::s_signalThread; +#endif CThreadRep::CThreadRep() : m_prev(NULL), m_next(NULL), @@ -92,7 +95,14 @@ CThreadRep::CThreadRep(IJob* job, void* userData) : // start the thread. throw if it doesn't start. #if defined(CONFIG_PTHREADS) + // mask some signals in all threads except the main thread + sigset_t sigset, oldsigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigaddset(&sigset, SIGTERM); + pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset); int status = pthread_create(&m_thread, NULL, threadFunc, (void*)this); + pthread_sigmask(SIG_SETMASK, &oldsigset, NULL); if (status != 0) throw XThreadUnavailable(); #elif defined(CONFIG_PLATFORM_WIN32) @@ -164,7 +174,22 @@ void CThreadRep::initThreads() pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); sigemptyset(&sigset); sigaddset(&sigset, SIGPIPE); + sigaddset(&sigset, SIGINT); + sigaddset(&sigset, SIGTERM); pthread_sigmask(SIG_BLOCK, &sigset, NULL); + + // fire up the INT and TERM signal handler thread + int status = pthread_create(&s_signalThread, NULL, + &CThreadRep::threadSignalHandler, + getCurrentThreadRep()); + if (status != 0) { + // can't create thread to wait for signal so don't block + // the signals. + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigaddset(&sigset, SIGTERM); + pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); + } #endif } } @@ -338,8 +363,9 @@ void CThreadRep::cancel() void CThreadRep::testCancel() { { - // prevent further cancellation CLock lock(s_mutex); + + // done if not cancelled, not cancellable, or already cancelling if (!m_cancel || !m_cancellable || m_cancelling) return; @@ -393,18 +419,6 @@ void* CThreadRep::threadFunc(void* arg) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); - // set signal mask - sigset_t sigset; - sigemptyset(&sigset); - sigaddset(&sigset, SIGWAKEUP); -#ifndef NDEBUG - sigaddset(&sigset, SIGSEGV); -#endif - pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); - sigemptyset(&sigset); - sigaddset(&sigset, SIGPIPE); - pthread_sigmask(SIG_BLOCK, &sigset, NULL); - // run thread rep->doThreadFunc(); @@ -426,6 +440,27 @@ void CThreadRep::threadCancel(int) // do nothing } +void* CThreadRep::threadSignalHandler(void* vrep) +{ + CThreadRep* mainThreadRep = reinterpret_cast(vrep); + + // add signal to mask + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigaddset(&sigset, SIGTERM); + + // we exit the loop via thread cancellation in sigwait() + for (;;) { + // wait + int signal; + sigwait(&sigset, &signal); + + // if we get here then the signal was raised. cancel the thread. + mainThreadRep->cancel(); + } +} + #elif defined(CONFIG_PLATFORM_WIN32) void CThreadRep::init() diff --git a/mt/CThreadRep.h b/mt/CThreadRep.h index c0c7b9a0..7189752b 100644 --- a/mt/CThreadRep.h +++ b/mt/CThreadRep.h @@ -85,6 +85,7 @@ private: #if defined(CONFIG_PTHREADS) static void* threadFunc(void* arg); static void threadCancel(int); + static void* threadSignalHandler(void*); #elif defined(CONFIG_PLATFORM_WIN32) static unsigned int __stdcall threadFunc(void* arg); #endif @@ -107,11 +108,13 @@ private: void* m_result; bool m_cancellable; bool m_cancelling; + UInt32 m_signals; #if defined(CONFIG_PTHREADS) pthread_t m_thread; bool m_exit; bool m_cancel; + static pthread_t s_signalThread; #endif #if defined(CONFIG_PLATFORM_WIN32) diff --git a/server/CServer.cpp b/server/CServer.cpp index cc53826f..9b6686d9 100644 --- a/server/CServer.cpp +++ b/server/CServer.cpp @@ -7,18 +7,19 @@ #include "IPrimaryScreen.h" #include "ISocketFactory.h" #include "ProtocolTypes.h" -#include "XSynergy.h" #include "CNetworkAddress.h" #include "ISocket.h" #include "IListenSocket.h" -#include "XSocket.h" #include "CLock.h" +#include "CLog.h" #include "CThread.h" #include "CTimerThread.h" #include "CStopwatch.h" #include "CFunctionJob.h" #include "TMethodJob.h" -#include "CLog.h" +#include "XSocket.h" +#include "XSynergy.h" +#include "XThread.h" #include #include @@ -92,15 +93,26 @@ void CServer::run() log((CLOG_ERR "server error: %s", e.what())); // clean up + log((CLOG_NOTE "stopping server")); delete m_httpServer; m_httpServer = NULL; cleanupThreads(); closePrimaryScreen(); } + catch (XThread&) { + // clean up + log((CLOG_NOTE "stopping server")); + delete m_httpServer; + m_httpServer = NULL; + cleanupThreads(); + closePrimaryScreen(); + throw; + } catch (...) { log((CLOG_DEBUG "unknown server error")); // clean up + log((CLOG_NOTE "stopping server")); delete m_httpServer; m_httpServer = NULL; cleanupThreads(); diff --git a/server/server.cpp b/server/server.cpp index 56a15d0c..3cc4a081 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -4,6 +4,7 @@ #include "CMutex.h" #include "CNetwork.h" #include "CThread.h" +#include "XThread.h" #include "stdfstream.h" #include @@ -47,11 +48,12 @@ void realMain() s_logMutex = &logMutex; CLog::setLock(&logLock); - // initialize network library - CNetwork::init(); - CServer* server = NULL; try { + // initialize network library + CNetwork::init(); + + // load configuration CConfig config; { log((CLOG_DEBUG "opening configuration")); @@ -63,9 +65,12 @@ void realMain() log((CLOG_DEBUG "configuration read successfully")); } + // run server server = new CServer(); server->setConfig(config); server->run(); + + // clean up delete server; CNetwork::cleanup(); CLog::setLock(NULL); @@ -110,6 +115,10 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) MessageBox(NULL, msg.c_str(), "error", MB_OK | MB_ICONERROR); return 1; } + catch (XThread&) { + // terminated + return 1; + } } #else @@ -132,6 +141,10 @@ int main(int argc, char** argv) fprintf(stderr, "failed: %s\n", e.what()); return 1; } + catch (XThread&) { + // terminated + return 1; + } } #endif