Generalized signal handling. Now handling SIGHUP in addition
to SIGINT and SIGTERM. Setup SIGHUP to reload the server's configuration.
This commit is contained in:
parent
9f7e909361
commit
82dffeb498
|
@ -358,6 +358,13 @@ static
|
||||||
int
|
int
|
||||||
mainLoop()
|
mainLoop()
|
||||||
{
|
{
|
||||||
|
// create socket multiplexer. this must happen after daemonization
|
||||||
|
// on unix because threads evaporate across a fork().
|
||||||
|
CSocketMultiplexer multiplexer;
|
||||||
|
|
||||||
|
// create the event queue
|
||||||
|
CEventQueue eventQueue;
|
||||||
|
|
||||||
// start the client. if this return false then we've failed and
|
// start the client. if this return false then we've failed and
|
||||||
// we shouldn't retry.
|
// we shouldn't retry.
|
||||||
LOG((CLOG_DEBUG1 "starting client"));
|
LOG((CLOG_DEBUG1 "starting client"));
|
||||||
|
@ -416,8 +423,6 @@ int
|
||||||
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
||||||
{
|
{
|
||||||
// general initialization
|
// general initialization
|
||||||
CSocketMultiplexer multiplexer;
|
|
||||||
CEventQueue eventQueue;
|
|
||||||
ARG->m_serverAddress = new CNetworkAddress;
|
ARG->m_serverAddress = new CNetworkAddress;
|
||||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
|
|
||||||
typedef int (*StartupFunc)(int, char**);
|
typedef int (*StartupFunc)(int, char**);
|
||||||
static void parse(int argc, const char* const* argv);
|
static void parse(int argc, const char* const* argv);
|
||||||
|
static bool loadConfig(const CString& pathname);
|
||||||
static void loadConfig();
|
static void loadConfig();
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -83,7 +84,7 @@ public:
|
||||||
m_backend(false),
|
m_backend(false),
|
||||||
m_restartable(true),
|
m_restartable(true),
|
||||||
m_daemon(true),
|
m_daemon(true),
|
||||||
m_configFile(NULL),
|
m_configFile(),
|
||||||
m_logFilter(NULL)
|
m_logFilter(NULL)
|
||||||
{ s_instance = this; }
|
{ s_instance = this; }
|
||||||
~CArgs() { s_instance = NULL; }
|
~CArgs() { s_instance = NULL; }
|
||||||
|
@ -94,7 +95,7 @@ public:
|
||||||
bool m_backend;
|
bool m_backend;
|
||||||
bool m_restartable;
|
bool m_restartable;
|
||||||
bool m_daemon;
|
bool m_daemon;
|
||||||
const char* m_configFile;
|
CString m_configFile;
|
||||||
const char* m_logFilter;
|
const char* m_logFilter;
|
||||||
CString m_name;
|
CString m_name;
|
||||||
CNetworkAddress* m_synergyAddress;
|
CNetworkAddress* m_synergyAddress;
|
||||||
|
@ -136,11 +137,12 @@ createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
|
||||||
// platform independent main
|
// platform independent main
|
||||||
//
|
//
|
||||||
|
|
||||||
static CServer* s_server = NULL;
|
static CServer* s_server = NULL;
|
||||||
static CScreen* s_serverScreen = NULL;
|
static CScreen* s_serverScreen = NULL;
|
||||||
static CPrimaryClient* s_primaryClient = NULL;
|
static CPrimaryClient* s_primaryClient = NULL;
|
||||||
static CClientListener* s_listener = NULL;
|
static CClientListener* s_listener = NULL;
|
||||||
static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
|
static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
|
||||||
|
static CEvent::Type s_reloadConfigEvent = CEvent::kUnknown;
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
|
@ -389,10 +391,38 @@ stopServer()
|
||||||
s_serverScreen = NULL;
|
s_serverScreen = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
reloadSignalHandler(CArch::ESignal, void*)
|
||||||
|
{
|
||||||
|
EVENTQUEUE->addEvent(CEvent(s_reloadConfigEvent,
|
||||||
|
IEventQueue::getSystemTarget()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
reloadConfig(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_DEBUG "reload configuration"));
|
||||||
|
if (loadConfig(ARG->m_configFile)) {
|
||||||
|
if (s_server != NULL) {
|
||||||
|
s_server->setConfig(*ARG->m_config);
|
||||||
|
}
|
||||||
|
LOG((CLOG_NOTE "reloaded configuration"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
mainLoop()
|
mainLoop()
|
||||||
{
|
{
|
||||||
|
// create socket multiplexer. this must happen after daemonization
|
||||||
|
// on unix because threads evaporate across a fork().
|
||||||
|
CSocketMultiplexer multiplexer;
|
||||||
|
|
||||||
|
// create the event queue
|
||||||
|
CEventQueue eventQueue;
|
||||||
|
|
||||||
// if configuration has no screens then add this system
|
// if configuration has no screens then add this system
|
||||||
// as the default
|
// as the default
|
||||||
if (ARG->m_config->begin() == ARG->m_config->end()) {
|
if (ARG->m_config->begin() == ARG->m_config->end()) {
|
||||||
|
@ -423,6 +453,13 @@ mainLoop()
|
||||||
return kExitFailed;
|
return kExitFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle hangup signal by reloading the server's configuration
|
||||||
|
CEvent::registerTypeOnce(s_reloadConfigEvent, "reloadConfig");
|
||||||
|
ARCH->setSignalHandler(CArch::kHANGUP, &reloadSignalHandler, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(s_reloadConfigEvent,
|
||||||
|
IEventQueue::getSystemTarget(),
|
||||||
|
new CFunctionEventJob(&reloadConfig));
|
||||||
|
|
||||||
// run event loop. if startServer() failed we're supposed to retry
|
// run event loop. if startServer() failed we're supposed to retry
|
||||||
// later. the timer installed by startServer() will take care of
|
// later. the timer installed by startServer() will take care of
|
||||||
// that.
|
// that.
|
||||||
|
@ -438,6 +475,8 @@ mainLoop()
|
||||||
|
|
||||||
// close down
|
// close down
|
||||||
LOG((CLOG_DEBUG1 "stopping server"));
|
LOG((CLOG_DEBUG1 "stopping server"));
|
||||||
|
EVENTQUEUE->removeHandler(s_reloadConfigEvent,
|
||||||
|
IEventQueue::getSystemTarget());
|
||||||
stopServer();
|
stopServer();
|
||||||
updateStatus();
|
updateStatus();
|
||||||
LOG((CLOG_NOTE "stopped server"));
|
LOG((CLOG_NOTE "stopped server"));
|
||||||
|
@ -477,8 +516,6 @@ int
|
||||||
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
||||||
{
|
{
|
||||||
// general initialization
|
// general initialization
|
||||||
CSocketMultiplexer multiplexer;
|
|
||||||
CEventQueue eventQueue;
|
|
||||||
ARG->m_synergyAddress = new CNetworkAddress;
|
ARG->m_synergyAddress = new CNetworkAddress;
|
||||||
ARG->m_config = new CConfig;
|
ARG->m_config = new CConfig;
|
||||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
@ -759,14 +796,12 @@ parse(int argc, const char* const* argv)
|
||||||
|
|
||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
loadConfig(const char* pathname)
|
loadConfig(const CString& pathname)
|
||||||
{
|
{
|
||||||
assert(pathname != NULL);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// load configuration
|
// load configuration
|
||||||
LOG((CLOG_DEBUG "opening configuration \"%s\"", pathname));
|
LOG((CLOG_DEBUG "opening configuration \"%s\"", pathname.c_str()));
|
||||||
std::ifstream configStream(pathname);
|
std::ifstream configStream(pathname.c_str());
|
||||||
if (!configStream) {
|
if (!configStream) {
|
||||||
throw XConfigRead("cannot open file");
|
throw XConfigRead("cannot open file");
|
||||||
}
|
}
|
||||||
|
@ -776,7 +811,7 @@ loadConfig(const char* pathname)
|
||||||
}
|
}
|
||||||
catch (XConfigRead& e) {
|
catch (XConfigRead& e) {
|
||||||
LOG((CLOG_DEBUG "cannot read configuration \"%s\": %s",
|
LOG((CLOG_DEBUG "cannot read configuration \"%s\": %s",
|
||||||
pathname, e.what()));
|
pathname.c_str(), e.what()));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -788,7 +823,7 @@ loadConfig()
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
|
|
||||||
// load the config file, if specified
|
// load the config file, if specified
|
||||||
if (ARG->m_configFile != NULL) {
|
if (!ARG->m_configFile.empty()) {
|
||||||
loaded = loadConfig(ARG->m_configFile);
|
loaded = loadConfig(ARG->m_configFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,14 +836,20 @@ loadConfig()
|
||||||
path = ARCH->concatPath(path, USR_CONFIG_NAME);
|
path = ARCH->concatPath(path, USR_CONFIG_NAME);
|
||||||
|
|
||||||
// now try loading the user's configuration
|
// now try loading the user's configuration
|
||||||
loaded = loadConfig(path.c_str());
|
if (loadConfig(path)) {
|
||||||
|
loaded = true;
|
||||||
|
ARG->m_configFile = path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
// try the system-wide config file
|
// try the system-wide config file
|
||||||
path = ARCH->getSystemDirectory();
|
path = ARCH->getSystemDirectory();
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
path = ARCH->concatPath(path, SYS_CONFIG_NAME);
|
path = ARCH->concatPath(path, SYS_CONFIG_NAME);
|
||||||
loaded = loadConfig(path.c_str());
|
if (loadConfig(path)) {
|
||||||
|
loaded = true;
|
||||||
|
ARG->m_configFile = path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,15 +376,15 @@ CArch::getIDOfThread(CArchThread thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArch::setInterruptHandler(InterruptFunc func, void* userData)
|
CArch::setSignalHandler(ESignal signal, SignalFunc func, void* userData)
|
||||||
{
|
{
|
||||||
m_mt->setInterruptHandler(func, userData);
|
m_mt->setSignalHandler(signal, func, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArch::interrupt()
|
CArch::raiseSignal(ESignal signal)
|
||||||
{
|
{
|
||||||
m_mt->interrupt();
|
m_mt->raiseSignal(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
CArchSocket
|
CArchSocket
|
||||||
|
|
|
@ -120,8 +120,8 @@ public:
|
||||||
virtual bool isExitedThread(CArchThread);
|
virtual bool isExitedThread(CArchThread);
|
||||||
virtual void* getResultOfThread(CArchThread);
|
virtual void* getResultOfThread(CArchThread);
|
||||||
virtual ThreadID getIDOfThread(CArchThread);
|
virtual ThreadID getIDOfThread(CArchThread);
|
||||||
virtual void setInterruptHandler(InterruptFunc, void*);
|
virtual void setSignalHandler(ESignal, SignalFunc, void*);
|
||||||
virtual void interrupt();
|
virtual void raiseSignal(ESignal);
|
||||||
|
|
||||||
// IArchNetwork overrides
|
// IArchNetwork overrides
|
||||||
virtual CArchSocket newSocket(EAddressFamily, ESocketType);
|
virtual CArchSocket newSocket(EAddressFamily, ESocketType);
|
||||||
|
|
|
@ -108,9 +108,20 @@ CArchConsoleWindows::getNewlineForConsole()
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
CArchConsoleWindows::signalHandler(DWORD)
|
CArchConsoleWindows::signalHandler(DWORD ctrlType)
|
||||||
{
|
{
|
||||||
// terminate app and skip remaining handlers
|
// terminate app and skip remaining handlers
|
||||||
ARCH->interrupt();
|
switch (ctrlType) {
|
||||||
return TRUE;
|
case CTRL_C_EVENT:
|
||||||
|
ARCH->raiseSignal(CArch::kINTERRUPT);
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case CTRL_BREAK_EVENT:
|
||||||
|
ARCH->raiseSignal(CArch::kTERMINATE);
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ARCH->raiseSignal(CArch::kINTERRUPT);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,16 @@
|
||||||
# define HAVE_POSIX_SIGWAIT 1
|
# define HAVE_POSIX_SIGWAIT 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
setSignalSet(sigset_t* sigset)
|
||||||
|
{
|
||||||
|
sigemptyset(sigset);
|
||||||
|
sigaddset(sigset, SIGHUP);
|
||||||
|
sigaddset(sigset, SIGINT);
|
||||||
|
sigaddset(sigset, SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// CArchThreadImpl
|
// CArchThreadImpl
|
||||||
//
|
//
|
||||||
|
@ -83,14 +93,18 @@ CArchMultithreadPosix* CArchMultithreadPosix::s_instance = NULL;
|
||||||
|
|
||||||
CArchMultithreadPosix::CArchMultithreadPosix() :
|
CArchMultithreadPosix::CArchMultithreadPosix() :
|
||||||
m_newThreadCalled(false),
|
m_newThreadCalled(false),
|
||||||
m_nextID(0),
|
m_nextID(0)
|
||||||
m_signalFunc(NULL),
|
|
||||||
m_signalUserData(NULL)
|
|
||||||
{
|
{
|
||||||
assert(s_instance == NULL);
|
assert(s_instance == NULL);
|
||||||
|
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
|
|
||||||
|
// no signal handlers
|
||||||
|
for (size_t i = 0; i < kNUM_SIGNALS; ++i) {
|
||||||
|
m_signalFunc[i] = NULL;
|
||||||
|
m_signalUserData[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// create mutex for thread list
|
// create mutex for thread list
|
||||||
m_threadMutex = newMutex();
|
m_threadMutex = newMutex();
|
||||||
|
|
||||||
|
@ -353,13 +367,6 @@ CArchMultithreadPosix::newThread(ThreadFunc func, void* data)
|
||||||
thread->m_func = func;
|
thread->m_func = func;
|
||||||
thread->m_userData = data;
|
thread->m_userData = data;
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// create the thread. pthread_create() on RedHat 7.2 smp fails
|
// create the thread. pthread_create() on RedHat 7.2 smp fails
|
||||||
// if passed a NULL attr so use a default attr.
|
// if passed a NULL attr so use a default attr.
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
|
@ -370,9 +377,6 @@ CArchMultithreadPosix::newThread(ThreadFunc func, void* data)
|
||||||
pthread_attr_destroy(&attr);
|
pthread_attr_destroy(&attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore signals
|
|
||||||
pthread_sigmask(SIG_SETMASK, &oldsigset, NULL);
|
|
||||||
|
|
||||||
// check if thread was started
|
// check if thread was started
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
// failed to start thread so clean up
|
// failed to start thread so clean up
|
||||||
|
@ -560,23 +564,24 @@ CArchMultithreadPosix::getIDOfThread(CArchThread thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchMultithreadPosix::setInterruptHandler(InterruptFunc func, void* userData)
|
CArchMultithreadPosix::setSignalHandler(
|
||||||
|
ESignal signal, SignalFunc func, void* userData)
|
||||||
{
|
{
|
||||||
lockMutex(m_threadMutex);
|
lockMutex(m_threadMutex);
|
||||||
m_signalFunc = func;
|
m_signalFunc[signal] = func;
|
||||||
m_signalUserData = userData;
|
m_signalUserData[signal] = userData;
|
||||||
unlockMutex(m_threadMutex);
|
unlockMutex(m_threadMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchMultithreadPosix::interrupt()
|
CArchMultithreadPosix::raiseSignal(ESignal signal)
|
||||||
{
|
{
|
||||||
lockMutex(m_threadMutex);
|
lockMutex(m_threadMutex);
|
||||||
if (m_signalFunc != NULL) {
|
if (m_signalFunc[signal] != NULL) {
|
||||||
m_signalFunc(m_signalUserData);
|
m_signalFunc[signal](signal, m_signalUserData[signal]);
|
||||||
unblockThread(m_mainThread);
|
unblockThread(m_mainThread);
|
||||||
}
|
}
|
||||||
else {
|
else if (signal == kINTERRUPT || signal == kTERMINATE) {
|
||||||
ARCH->cancelThread(m_mainThread);
|
ARCH->cancelThread(m_mainThread);
|
||||||
}
|
}
|
||||||
unlockMutex(m_threadMutex);
|
unlockMutex(m_threadMutex);
|
||||||
|
@ -587,11 +592,9 @@ CArchMultithreadPosix::startSignalHandler()
|
||||||
{
|
{
|
||||||
// set signal mask. the main thread blocks these signals and
|
// set signal mask. the main thread blocks these signals and
|
||||||
// the signal handler thread will listen for them.
|
// the signal handler thread will listen for them.
|
||||||
sigset_t sigset;
|
sigset_t sigset, oldsigset;
|
||||||
sigemptyset(&sigset);
|
setSignalSet(&sigset);
|
||||||
sigaddset(&sigset, SIGINT);
|
pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset);
|
||||||
sigaddset(&sigset, SIGTERM);
|
|
||||||
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
|
|
||||||
|
|
||||||
// fire up the INT and TERM signal handler thread. we could
|
// fire up the INT and TERM signal handler thread. we could
|
||||||
// instead arrange to catch and handle these signals but
|
// instead arrange to catch and handle these signals but
|
||||||
|
@ -608,10 +611,7 @@ CArchMultithreadPosix::startSignalHandler()
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
// can't create thread to wait for signal so don't block
|
// can't create thread to wait for signal so don't block
|
||||||
// the signals.
|
// the signals.
|
||||||
sigemptyset(&sigset);
|
pthread_sigmask(SIG_UNBLOCK, &oldsigset, NULL);
|
||||||
sigaddset(&sigset, SIGINT);
|
|
||||||
sigaddset(&sigset, SIGTERM);
|
|
||||||
pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -766,9 +766,7 @@ CArchMultithreadPosix::threadSignalHandler(void*)
|
||||||
|
|
||||||
// add signal to mask
|
// add signal to mask
|
||||||
sigset_t sigset;
|
sigset_t sigset;
|
||||||
sigemptyset(&sigset);
|
setSignalSet(&sigset);
|
||||||
sigaddset(&sigset, SIGINT);
|
|
||||||
sigaddset(&sigset, SIGTERM);
|
|
||||||
|
|
||||||
// also wait on SIGABRT. on linux (others?) this thread (process)
|
// also wait on SIGABRT. on linux (others?) this thread (process)
|
||||||
// will persist after all the other threads evaporate due to an
|
// will persist after all the other threads evaporate due to an
|
||||||
|
@ -791,6 +789,22 @@ CArchMultithreadPosix::threadSignalHandler(void*)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// if we get here then the signal was raised
|
// if we get here then the signal was raised
|
||||||
ARCH->interrupt();
|
switch (signal) {
|
||||||
|
case SIGINT:
|
||||||
|
ARCH->raiseSignal(kINTERRUPT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIGTERM:
|
||||||
|
ARCH->raiseSignal(kTERMINATE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIGHUP:
|
||||||
|
ARCH->raiseSignal(kHANGUP);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// ignore
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,8 +72,8 @@ public:
|
||||||
virtual bool isExitedThread(CArchThread);
|
virtual bool isExitedThread(CArchThread);
|
||||||
virtual void* getResultOfThread(CArchThread);
|
virtual void* getResultOfThread(CArchThread);
|
||||||
virtual ThreadID getIDOfThread(CArchThread);
|
virtual ThreadID getIDOfThread(CArchThread);
|
||||||
virtual void setInterruptHandler(InterruptFunc, void*);
|
virtual void setSignalHandler(ESignal, SignalFunc, void*);
|
||||||
virtual void interrupt();
|
virtual void raiseSignal(ESignal);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startSignalHandler();
|
void startSignalHandler();
|
||||||
|
@ -104,8 +104,8 @@ private:
|
||||||
ThreadID m_nextID;
|
ThreadID m_nextID;
|
||||||
|
|
||||||
pthread_t m_signalThread;
|
pthread_t m_signalThread;
|
||||||
InterruptFunc m_signalFunc;
|
SignalFunc m_signalFunc[kNUM_SIGNALS];
|
||||||
void* m_signalUserData;
|
void* m_signalUserData[kNUM_SIGNALS];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -80,13 +80,17 @@ CArchThreadImpl::~CArchThreadImpl()
|
||||||
|
|
||||||
CArchMultithreadWindows* CArchMultithreadWindows::s_instance = NULL;
|
CArchMultithreadWindows* CArchMultithreadWindows::s_instance = NULL;
|
||||||
|
|
||||||
CArchMultithreadWindows::CArchMultithreadWindows() :
|
CArchMultithreadWindows::CArchMultithreadWindows()
|
||||||
m_signalFunc(NULL),
|
|
||||||
m_signalUserData(NULL)
|
|
||||||
{
|
{
|
||||||
assert(s_instance == NULL);
|
assert(s_instance == NULL);
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
|
|
||||||
|
// no signal handlers
|
||||||
|
for (size_t i = 0; i < kNUM_SIGNALS; ++i) {
|
||||||
|
m_signalFunc[i] = NULL;
|
||||||
|
m_signalUserData[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// create mutex for thread list
|
// create mutex for thread list
|
||||||
m_threadMutex = newMutex();
|
m_threadMutex = newMutex();
|
||||||
|
|
||||||
|
@ -529,23 +533,24 @@ CArchMultithreadWindows::getIDOfThread(CArchThread thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchMultithreadWindows::setInterruptHandler(InterruptFunc func, void* userData)
|
CArchMultithreadWindows::setSignalHandler(
|
||||||
|
ESignal signal, SignalFunc func, void* userData)
|
||||||
{
|
{
|
||||||
lockMutex(m_threadMutex);
|
lockMutex(m_threadMutex);
|
||||||
m_signalFunc = func;
|
m_signalFunc[signal] = func;
|
||||||
m_signalUserData = userData;
|
m_signalUserData[signal] = userData;
|
||||||
unlockMutex(m_threadMutex);
|
unlockMutex(m_threadMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchMultithreadWindows::interrupt()
|
CArchMultithreadWindows::raiseSignal(ESignal signal)
|
||||||
{
|
{
|
||||||
lockMutex(m_threadMutex);
|
lockMutex(m_threadMutex);
|
||||||
if (m_signalFunc != NULL) {
|
if (m_signalFunc[signal] != NULL) {
|
||||||
m_signalFunc(m_signalUserData);
|
m_signalFunc[signal](signal, m_signalUserData[signal]);
|
||||||
ARCH->unblockPollSocket(m_mainThread);
|
ARCH->unblockPollSocket(m_mainThread);
|
||||||
}
|
}
|
||||||
else {
|
else if (signal == kINTERRUPT || signal == kTERMINATE) {
|
||||||
ARCH->cancelThread(m_mainThread);
|
ARCH->cancelThread(m_mainThread);
|
||||||
}
|
}
|
||||||
unlockMutex(m_threadMutex);
|
unlockMutex(m_threadMutex);
|
||||||
|
|
|
@ -81,8 +81,8 @@ public:
|
||||||
virtual bool isExitedThread(CArchThread);
|
virtual bool isExitedThread(CArchThread);
|
||||||
virtual void* getResultOfThread(CArchThread);
|
virtual void* getResultOfThread(CArchThread);
|
||||||
virtual ThreadID getIDOfThread(CArchThread);
|
virtual ThreadID getIDOfThread(CArchThread);
|
||||||
virtual void setInterruptHandler(InterruptFunc, void*);
|
virtual void setSignalHandler(ESignal, SignalFunc, void*);
|
||||||
virtual void interrupt();
|
virtual void raiseSignal(ESignal);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CArchThreadImpl* find(DWORD id);
|
CArchThreadImpl* find(DWORD id);
|
||||||
|
@ -107,8 +107,8 @@ private:
|
||||||
CThreadList m_threadList;
|
CThreadList m_threadList;
|
||||||
CArchThread m_mainThread;
|
CArchThread m_mainThread;
|
||||||
|
|
||||||
InterruptFunc m_signalFunc;
|
SignalFunc m_signalFunc[kNUM_SIGNALS];
|
||||||
void* m_signalUserData;
|
void* m_signalUserData[kNUM_SIGNALS];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -71,6 +71,19 @@ public:
|
||||||
typedef void* (*ThreadFunc)(void*);
|
typedef void* (*ThreadFunc)(void*);
|
||||||
//! Type of thread identifier
|
//! Type of thread identifier
|
||||||
typedef unsigned int ThreadID;
|
typedef unsigned int ThreadID;
|
||||||
|
//! Types of signals
|
||||||
|
/*!
|
||||||
|
Not all platforms support all signals. Unsupported signals are
|
||||||
|
ignored.
|
||||||
|
*/
|
||||||
|
enum ESignal {
|
||||||
|
kINTERRUPT, //!< Interrupt (e.g. Ctrl+C)
|
||||||
|
kTERMINATE, //!< Terminate (e.g. Ctrl+Break)
|
||||||
|
kHANGUP, //!< Hangup (SIGHUP)
|
||||||
|
kNUM_SIGNALS
|
||||||
|
};
|
||||||
|
//! Type of signal handler function
|
||||||
|
typedef void (*SignalFunc)(ESignal, void* userData);
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
@ -242,12 +255,16 @@ public:
|
||||||
Sets the function to call on receipt of an external interrupt.
|
Sets the function to call on receipt of an external interrupt.
|
||||||
By default and when \p func is NULL, the main thread is cancelled.
|
By default and when \p func is NULL, the main thread is cancelled.
|
||||||
*/
|
*/
|
||||||
typedef void (*InterruptFunc)(void*);
|
virtual void setSignalHandler(ESignal, SignalFunc func,
|
||||||
virtual void setInterruptHandler(InterruptFunc func,
|
|
||||||
void* userData) = 0;
|
void* userData) = 0;
|
||||||
|
|
||||||
//! Invoke the interrupt handler
|
//! Invoke the signal handler
|
||||||
virtual void interrupt() = 0;
|
/*!
|
||||||
|
Invokes the signal handler for \p signal, if any. If no handler
|
||||||
|
cancels the main thread for \c kINTERRUPT and \c kTERMINATE and
|
||||||
|
ignores the call otherwise.
|
||||||
|
*/
|
||||||
|
virtual void raiseSignal(ESignal signal) = 0;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
;/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2004 Chris Schoeneman
|
* Copyright (C) 2004 Chris Schoeneman
|
||||||
*
|
*
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
// interrupt handler. this just adds a quit event to the queue.
|
// interrupt handler. this just adds a quit event to the queue.
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
interrupt(void*)
|
interrupt(CArch::ESignal, void*)
|
||||||
{
|
{
|
||||||
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
}
|
}
|
||||||
|
@ -37,14 +37,16 @@ CEventQueue::CEventQueue() :
|
||||||
{
|
{
|
||||||
setInstance(this);
|
setInstance(this);
|
||||||
m_mutex = ARCH->newMutex();
|
m_mutex = ARCH->newMutex();
|
||||||
ARCH->setInterruptHandler(&interrupt, NULL);
|
ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, NULL);
|
||||||
|
ARCH->setSignalHandler(CArch::kTERMINATE, &interrupt, NULL);
|
||||||
m_buffer = new CSimpleEventQueueBuffer;
|
m_buffer = new CSimpleEventQueueBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
CEventQueue::~CEventQueue()
|
CEventQueue::~CEventQueue()
|
||||||
{
|
{
|
||||||
delete m_buffer;
|
delete m_buffer;
|
||||||
ARCH->setInterruptHandler(NULL, NULL);
|
ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
|
||||||
|
ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
|
||||||
ARCH->closeMutex(m_mutex);
|
ARCH->closeMutex(m_mutex);
|
||||||
setInstance(NULL);
|
setInstance(NULL);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue