added SIGINT and SIGTERM handling to unix client and server.
either signal causes the main thread to be cancelled. added necessary code to make main thread cancellation clean up nicely.
This commit is contained in:
parent
1da9be88c9
commit
1d3807cb0e
|
@ -6,11 +6,12 @@
|
||||||
#include "ISecondaryScreen.h"
|
#include "ISecondaryScreen.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
|
#include "CLog.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "CTimerThread.h"
|
#include "CTimerThread.h"
|
||||||
#include "XSynergy.h"
|
|
||||||
#include "TMethodJob.h"
|
#include "TMethodJob.h"
|
||||||
#include "CLog.h"
|
#include "XSynergy.h"
|
||||||
|
#include "XThread.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -71,6 +72,7 @@ void CClient::run(const CNetworkAddress& serverAddress)
|
||||||
log((CLOG_ERR "client error: %s", e.what()));
|
log((CLOG_ERR "client error: %s", e.what()));
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
|
log((CLOG_NOTE "stopping client"));
|
||||||
if (thread != NULL) {
|
if (thread != NULL) {
|
||||||
thread->cancel();
|
thread->cancel();
|
||||||
thread->wait();
|
thread->wait();
|
||||||
|
@ -78,10 +80,22 @@ void CClient::run(const CNetworkAddress& serverAddress)
|
||||||
}
|
}
|
||||||
closeSecondaryScreen();
|
closeSecondaryScreen();
|
||||||
}
|
}
|
||||||
|
catch (XThread&) {
|
||||||
|
// clean up
|
||||||
|
log((CLOG_NOTE "stopping client"));
|
||||||
|
if (thread != NULL) {
|
||||||
|
thread->cancel();
|
||||||
|
thread->wait();
|
||||||
|
delete thread;
|
||||||
|
}
|
||||||
|
closeSecondaryScreen();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
log((CLOG_DEBUG "unknown client error"));
|
log((CLOG_DEBUG "unknown client error"));
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
|
log((CLOG_NOTE "stopping client"));
|
||||||
if (thread != NULL) {
|
if (thread != NULL) {
|
||||||
thread->cancel();
|
thread->cancel();
|
||||||
thread->wait();
|
thread->wait();
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "CNetwork.h"
|
#include "CNetwork.h"
|
||||||
#include "CNetworkAddress.h"
|
#include "CNetworkAddress.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
|
#include "XThread.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -42,20 +43,24 @@ void realMain(const CString& name,
|
||||||
s_logMutex = &logMutex;
|
s_logMutex = &logMutex;
|
||||||
CLog::setLock(&logLock);
|
CLog::setLock(&logLock);
|
||||||
|
|
||||||
// initialize network library
|
|
||||||
CNetwork::init();
|
|
||||||
|
|
||||||
CClient* client = NULL;
|
CClient* client = NULL;
|
||||||
try {
|
try {
|
||||||
|
// initialize network library
|
||||||
|
CNetwork::init();
|
||||||
|
|
||||||
|
// run client
|
||||||
CNetworkAddress addr(hostname, port);
|
CNetworkAddress addr(hostname, port);
|
||||||
client = new CClient(name);
|
client = new CClient(name);
|
||||||
client->run(addr);
|
client->run(addr);
|
||||||
|
|
||||||
|
// clean up
|
||||||
delete client;
|
delete client;
|
||||||
CNetwork::cleanup();
|
CNetwork::cleanup();
|
||||||
CLog::setLock(NULL);
|
CLog::setLock(NULL);
|
||||||
s_logMutex = NULL;
|
s_logMutex = NULL;
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
// clean up
|
||||||
delete client;
|
delete client;
|
||||||
CNetwork::cleanup();
|
CNetwork::cleanup();
|
||||||
CLog::setLock(NULL);
|
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);
|
MessageBox(NULL, msg.c_str(), "error", MB_OK | MB_ICONERROR);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
catch (XThread&) {
|
||||||
|
// terminated
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -114,6 +123,10 @@ int main(int argc, char** argv)
|
||||||
fprintf(stderr, "failed: %s\n", e.what());
|
fprintf(stderr, "failed: %s\n", e.what());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
catch (XThread&) {
|
||||||
|
// terminated
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef CTHREAD_H
|
#ifndef CTHREAD_H
|
||||||
#define CTHREAD_H
|
#define CTHREAD_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "BasicTypes.h"
|
||||||
|
|
||||||
class IJob;
|
class IJob;
|
||||||
class CThreadRep;
|
class CThreadRep;
|
||||||
|
|
|
@ -40,6 +40,9 @@ static void threadDebug(int)
|
||||||
|
|
||||||
CMutex* CThreadRep::s_mutex = NULL;
|
CMutex* CThreadRep::s_mutex = NULL;
|
||||||
CThreadRep* CThreadRep::s_head = NULL;
|
CThreadRep* CThreadRep::s_head = NULL;
|
||||||
|
#if defined(CONFIG_PTHREADS)
|
||||||
|
pthread_t CThreadRep::s_signalThread;
|
||||||
|
#endif
|
||||||
|
|
||||||
CThreadRep::CThreadRep() : m_prev(NULL),
|
CThreadRep::CThreadRep() : m_prev(NULL),
|
||||||
m_next(NULL),
|
m_next(NULL),
|
||||||
|
@ -92,7 +95,14 @@ CThreadRep::CThreadRep(IJob* job, void* userData) :
|
||||||
|
|
||||||
// start the thread. throw if it doesn't start.
|
// start the thread. throw if it doesn't start.
|
||||||
#if defined(CONFIG_PTHREADS)
|
#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);
|
int status = pthread_create(&m_thread, NULL, threadFunc, (void*)this);
|
||||||
|
pthread_sigmask(SIG_SETMASK, &oldsigset, NULL);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
throw XThreadUnavailable();
|
throw XThreadUnavailable();
|
||||||
#elif defined(CONFIG_PLATFORM_WIN32)
|
#elif defined(CONFIG_PLATFORM_WIN32)
|
||||||
|
@ -164,7 +174,22 @@ void CThreadRep::initThreads()
|
||||||
pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
|
pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
|
||||||
sigemptyset(&sigset);
|
sigemptyset(&sigset);
|
||||||
sigaddset(&sigset, SIGPIPE);
|
sigaddset(&sigset, SIGPIPE);
|
||||||
|
sigaddset(&sigset, SIGINT);
|
||||||
|
sigaddset(&sigset, SIGTERM);
|
||||||
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,8 +363,9 @@ void CThreadRep::cancel()
|
||||||
void CThreadRep::testCancel()
|
void CThreadRep::testCancel()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
// prevent further cancellation
|
|
||||||
CLock lock(s_mutex);
|
CLock lock(s_mutex);
|
||||||
|
|
||||||
|
// done if not cancelled, not cancellable, or already cancelling
|
||||||
if (!m_cancel || !m_cancellable || m_cancelling)
|
if (!m_cancel || !m_cancellable || m_cancelling)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -393,18 +419,6 @@ void* CThreadRep::threadFunc(void* arg)
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 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
|
// run thread
|
||||||
rep->doThreadFunc();
|
rep->doThreadFunc();
|
||||||
|
|
||||||
|
@ -426,6 +440,27 @@ void CThreadRep::threadCancel(int)
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* CThreadRep::threadSignalHandler(void* vrep)
|
||||||
|
{
|
||||||
|
CThreadRep* mainThreadRep = reinterpret_cast<CThreadRep*>(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)
|
#elif defined(CONFIG_PLATFORM_WIN32)
|
||||||
|
|
||||||
void CThreadRep::init()
|
void CThreadRep::init()
|
||||||
|
|
|
@ -85,6 +85,7 @@ private:
|
||||||
#if defined(CONFIG_PTHREADS)
|
#if defined(CONFIG_PTHREADS)
|
||||||
static void* threadFunc(void* arg);
|
static void* threadFunc(void* arg);
|
||||||
static void threadCancel(int);
|
static void threadCancel(int);
|
||||||
|
static void* threadSignalHandler(void*);
|
||||||
#elif defined(CONFIG_PLATFORM_WIN32)
|
#elif defined(CONFIG_PLATFORM_WIN32)
|
||||||
static unsigned int __stdcall threadFunc(void* arg);
|
static unsigned int __stdcall threadFunc(void* arg);
|
||||||
#endif
|
#endif
|
||||||
|
@ -107,11 +108,13 @@ private:
|
||||||
void* m_result;
|
void* m_result;
|
||||||
bool m_cancellable;
|
bool m_cancellable;
|
||||||
bool m_cancelling;
|
bool m_cancelling;
|
||||||
|
UInt32 m_signals;
|
||||||
|
|
||||||
#if defined(CONFIG_PTHREADS)
|
#if defined(CONFIG_PTHREADS)
|
||||||
pthread_t m_thread;
|
pthread_t m_thread;
|
||||||
bool m_exit;
|
bool m_exit;
|
||||||
bool m_cancel;
|
bool m_cancel;
|
||||||
|
static pthread_t s_signalThread;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_PLATFORM_WIN32)
|
#if defined(CONFIG_PLATFORM_WIN32)
|
||||||
|
|
|
@ -7,18 +7,19 @@
|
||||||
#include "IPrimaryScreen.h"
|
#include "IPrimaryScreen.h"
|
||||||
#include "ISocketFactory.h"
|
#include "ISocketFactory.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "XSynergy.h"
|
|
||||||
#include "CNetworkAddress.h"
|
#include "CNetworkAddress.h"
|
||||||
#include "ISocket.h"
|
#include "ISocket.h"
|
||||||
#include "IListenSocket.h"
|
#include "IListenSocket.h"
|
||||||
#include "XSocket.h"
|
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
|
#include "CLog.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "CTimerThread.h"
|
#include "CTimerThread.h"
|
||||||
#include "CStopwatch.h"
|
#include "CStopwatch.h"
|
||||||
#include "CFunctionJob.h"
|
#include "CFunctionJob.h"
|
||||||
#include "TMethodJob.h"
|
#include "TMethodJob.h"
|
||||||
#include "CLog.h"
|
#include "XSocket.h"
|
||||||
|
#include "XSynergy.h"
|
||||||
|
#include "XThread.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -92,15 +93,26 @@ void CServer::run()
|
||||||
log((CLOG_ERR "server error: %s", e.what()));
|
log((CLOG_ERR "server error: %s", e.what()));
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
|
log((CLOG_NOTE "stopping server"));
|
||||||
delete m_httpServer;
|
delete m_httpServer;
|
||||||
m_httpServer = NULL;
|
m_httpServer = NULL;
|
||||||
cleanupThreads();
|
cleanupThreads();
|
||||||
closePrimaryScreen();
|
closePrimaryScreen();
|
||||||
}
|
}
|
||||||
|
catch (XThread&) {
|
||||||
|
// clean up
|
||||||
|
log((CLOG_NOTE "stopping server"));
|
||||||
|
delete m_httpServer;
|
||||||
|
m_httpServer = NULL;
|
||||||
|
cleanupThreads();
|
||||||
|
closePrimaryScreen();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
log((CLOG_DEBUG "unknown server error"));
|
log((CLOG_DEBUG "unknown server error"));
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
|
log((CLOG_NOTE "stopping server"));
|
||||||
delete m_httpServer;
|
delete m_httpServer;
|
||||||
m_httpServer = NULL;
|
m_httpServer = NULL;
|
||||||
cleanupThreads();
|
cleanupThreads();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "CNetwork.h"
|
#include "CNetwork.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
|
#include "XThread.h"
|
||||||
#include "stdfstream.h"
|
#include "stdfstream.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
@ -47,11 +48,12 @@ void realMain()
|
||||||
s_logMutex = &logMutex;
|
s_logMutex = &logMutex;
|
||||||
CLog::setLock(&logLock);
|
CLog::setLock(&logLock);
|
||||||
|
|
||||||
// initialize network library
|
|
||||||
CNetwork::init();
|
|
||||||
|
|
||||||
CServer* server = NULL;
|
CServer* server = NULL;
|
||||||
try {
|
try {
|
||||||
|
// initialize network library
|
||||||
|
CNetwork::init();
|
||||||
|
|
||||||
|
// load configuration
|
||||||
CConfig config;
|
CConfig config;
|
||||||
{
|
{
|
||||||
log((CLOG_DEBUG "opening configuration"));
|
log((CLOG_DEBUG "opening configuration"));
|
||||||
|
@ -63,9 +65,12 @@ void realMain()
|
||||||
log((CLOG_DEBUG "configuration read successfully"));
|
log((CLOG_DEBUG "configuration read successfully"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run server
|
||||||
server = new CServer();
|
server = new CServer();
|
||||||
server->setConfig(config);
|
server->setConfig(config);
|
||||||
server->run();
|
server->run();
|
||||||
|
|
||||||
|
// clean up
|
||||||
delete server;
|
delete server;
|
||||||
CNetwork::cleanup();
|
CNetwork::cleanup();
|
||||||
CLog::setLock(NULL);
|
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);
|
MessageBox(NULL, msg.c_str(), "error", MB_OK | MB_ICONERROR);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
catch (XThread&) {
|
||||||
|
// terminated
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -132,6 +141,10 @@ int main(int argc, char** argv)
|
||||||
fprintf(stderr, "failed: %s\n", e.what());
|
fprintf(stderr, "failed: %s\n", e.what());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
catch (XThread&) {
|
||||||
|
// terminated
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue