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
|
||||
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
|
||||
// we shouldn't retry.
|
||||
LOG((CLOG_DEBUG1 "starting client"));
|
||||
|
@ -416,8 +423,6 @@ int
|
|||
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
||||
{
|
||||
// general initialization
|
||||
CSocketMultiplexer multiplexer;
|
||||
CEventQueue eventQueue;
|
||||
ARG->m_serverAddress = new CNetworkAddress;
|
||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
|
||||
typedef int (*StartupFunc)(int, char**);
|
||||
static void parse(int argc, const char* const* argv);
|
||||
static bool loadConfig(const CString& pathname);
|
||||
static void loadConfig();
|
||||
|
||||
//
|
||||
|
@ -83,7 +84,7 @@ public:
|
|||
m_backend(false),
|
||||
m_restartable(true),
|
||||
m_daemon(true),
|
||||
m_configFile(NULL),
|
||||
m_configFile(),
|
||||
m_logFilter(NULL)
|
||||
{ s_instance = this; }
|
||||
~CArgs() { s_instance = NULL; }
|
||||
|
@ -94,7 +95,7 @@ public:
|
|||
bool m_backend;
|
||||
bool m_restartable;
|
||||
bool m_daemon;
|
||||
const char* m_configFile;
|
||||
CString m_configFile;
|
||||
const char* m_logFilter;
|
||||
CString m_name;
|
||||
CNetworkAddress* m_synergyAddress;
|
||||
|
@ -141,6 +142,7 @@ static CScreen* s_serverScreen = NULL;
|
|||
static CPrimaryClient* s_primaryClient = NULL;
|
||||
static CClientListener* s_listener = NULL;
|
||||
static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
|
||||
static CEvent::Type s_reloadConfigEvent = CEvent::kUnknown;
|
||||
|
||||
static
|
||||
void
|
||||
|
@ -389,10 +391,38 @@ stopServer()
|
|||
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
|
||||
int
|
||||
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
|
||||
// as the default
|
||||
if (ARG->m_config->begin() == ARG->m_config->end()) {
|
||||
|
@ -423,6 +453,13 @@ mainLoop()
|
|||
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
|
||||
// later. the timer installed by startServer() will take care of
|
||||
// that.
|
||||
|
@ -438,6 +475,8 @@ mainLoop()
|
|||
|
||||
// close down
|
||||
LOG((CLOG_DEBUG1 "stopping server"));
|
||||
EVENTQUEUE->removeHandler(s_reloadConfigEvent,
|
||||
IEventQueue::getSystemTarget());
|
||||
stopServer();
|
||||
updateStatus();
|
||||
LOG((CLOG_NOTE "stopped server"));
|
||||
|
@ -477,8 +516,6 @@ int
|
|||
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
||||
{
|
||||
// general initialization
|
||||
CSocketMultiplexer multiplexer;
|
||||
CEventQueue eventQueue;
|
||||
ARG->m_synergyAddress = new CNetworkAddress;
|
||||
ARG->m_config = new CConfig;
|
||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||
|
@ -759,14 +796,12 @@ parse(int argc, const char* const* argv)
|
|||
|
||||
static
|
||||
bool
|
||||
loadConfig(const char* pathname)
|
||||
loadConfig(const CString& pathname)
|
||||
{
|
||||
assert(pathname != NULL);
|
||||
|
||||
try {
|
||||
// load configuration
|
||||
LOG((CLOG_DEBUG "opening configuration \"%s\"", pathname));
|
||||
std::ifstream configStream(pathname);
|
||||
LOG((CLOG_DEBUG "opening configuration \"%s\"", pathname.c_str()));
|
||||
std::ifstream configStream(pathname.c_str());
|
||||
if (!configStream) {
|
||||
throw XConfigRead("cannot open file");
|
||||
}
|
||||
|
@ -776,7 +811,7 @@ loadConfig(const char* pathname)
|
|||
}
|
||||
catch (XConfigRead& e) {
|
||||
LOG((CLOG_DEBUG "cannot read configuration \"%s\": %s",
|
||||
pathname, e.what()));
|
||||
pathname.c_str(), e.what()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -788,7 +823,7 @@ loadConfig()
|
|||
bool loaded = false;
|
||||
|
||||
// load the config file, if specified
|
||||
if (ARG->m_configFile != NULL) {
|
||||
if (!ARG->m_configFile.empty()) {
|
||||
loaded = loadConfig(ARG->m_configFile);
|
||||
}
|
||||
|
||||
|
@ -801,14 +836,20 @@ loadConfig()
|
|||
path = ARCH->concatPath(path, USR_CONFIG_NAME);
|
||||
|
||||
// now try loading the user's configuration
|
||||
loaded = loadConfig(path.c_str());
|
||||
if (loadConfig(path)) {
|
||||
loaded = true;
|
||||
ARG->m_configFile = path;
|
||||
}
|
||||
}
|
||||
if (!loaded) {
|
||||
// try the system-wide config file
|
||||
path = ARCH->getSystemDirectory();
|
||||
if (!path.empty()) {
|
||||
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
|
||||
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
|
||||
CArch::interrupt()
|
||||
CArch::raiseSignal(ESignal signal)
|
||||
{
|
||||
m_mt->interrupt();
|
||||
m_mt->raiseSignal(signal);
|
||||
}
|
||||
|
||||
CArchSocket
|
||||
|
|
|
@ -120,8 +120,8 @@ public:
|
|||
virtual bool isExitedThread(CArchThread);
|
||||
virtual void* getResultOfThread(CArchThread);
|
||||
virtual ThreadID getIDOfThread(CArchThread);
|
||||
virtual void setInterruptHandler(InterruptFunc, void*);
|
||||
virtual void interrupt();
|
||||
virtual void setSignalHandler(ESignal, SignalFunc, void*);
|
||||
virtual void raiseSignal(ESignal);
|
||||
|
||||
// IArchNetwork overrides
|
||||
virtual CArchSocket newSocket(EAddressFamily, ESocketType);
|
||||
|
|
|
@ -108,9 +108,20 @@ CArchConsoleWindows::getNewlineForConsole()
|
|||
}
|
||||
|
||||
BOOL WINAPI
|
||||
CArchConsoleWindows::signalHandler(DWORD)
|
||||
CArchConsoleWindows::signalHandler(DWORD ctrlType)
|
||||
{
|
||||
// terminate app and skip remaining handlers
|
||||
ARCH->interrupt();
|
||||
switch (ctrlType) {
|
||||
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
|
||||
#endif
|
||||
|
||||
static
|
||||
void
|
||||
setSignalSet(sigset_t* sigset)
|
||||
{
|
||||
sigemptyset(sigset);
|
||||
sigaddset(sigset, SIGHUP);
|
||||
sigaddset(sigset, SIGINT);
|
||||
sigaddset(sigset, SIGTERM);
|
||||
}
|
||||
|
||||
//
|
||||
// CArchThreadImpl
|
||||
//
|
||||
|
@ -83,14 +93,18 @@ CArchMultithreadPosix* CArchMultithreadPosix::s_instance = NULL;
|
|||
|
||||
CArchMultithreadPosix::CArchMultithreadPosix() :
|
||||
m_newThreadCalled(false),
|
||||
m_nextID(0),
|
||||
m_signalFunc(NULL),
|
||||
m_signalUserData(NULL)
|
||||
m_nextID(0)
|
||||
{
|
||||
assert(s_instance == NULL);
|
||||
|
||||
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
|
||||
m_threadMutex = newMutex();
|
||||
|
||||
|
@ -353,13 +367,6 @@ CArchMultithreadPosix::newThread(ThreadFunc func, void* data)
|
|||
thread->m_func = func;
|
||||
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
|
||||
// if passed a NULL attr so use a default attr.
|
||||
pthread_attr_t attr;
|
||||
|
@ -370,9 +377,6 @@ CArchMultithreadPosix::newThread(ThreadFunc func, void* data)
|
|||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
|
||||
// restore signals
|
||||
pthread_sigmask(SIG_SETMASK, &oldsigset, NULL);
|
||||
|
||||
// check if thread was started
|
||||
if (status != 0) {
|
||||
// failed to start thread so clean up
|
||||
|
@ -560,23 +564,24 @@ CArchMultithreadPosix::getIDOfThread(CArchThread thread)
|
|||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::setInterruptHandler(InterruptFunc func, void* userData)
|
||||
CArchMultithreadPosix::setSignalHandler(
|
||||
ESignal signal, SignalFunc func, void* userData)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
m_signalFunc = func;
|
||||
m_signalUserData = userData;
|
||||
m_signalFunc[signal] = func;
|
||||
m_signalUserData[signal] = userData;
|
||||
unlockMutex(m_threadMutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::interrupt()
|
||||
CArchMultithreadPosix::raiseSignal(ESignal signal)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
if (m_signalFunc != NULL) {
|
||||
m_signalFunc(m_signalUserData);
|
||||
if (m_signalFunc[signal] != NULL) {
|
||||
m_signalFunc[signal](signal, m_signalUserData[signal]);
|
||||
unblockThread(m_mainThread);
|
||||
}
|
||||
else {
|
||||
else if (signal == kINTERRUPT || signal == kTERMINATE) {
|
||||
ARCH->cancelThread(m_mainThread);
|
||||
}
|
||||
unlockMutex(m_threadMutex);
|
||||
|
@ -587,11 +592,9 @@ CArchMultithreadPosix::startSignalHandler()
|
|||
{
|
||||
// set signal mask. the main thread blocks these signals and
|
||||
// the signal handler thread will listen for them.
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGINT);
|
||||
sigaddset(&sigset, SIGTERM);
|
||||
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
|
||||
sigset_t sigset, oldsigset;
|
||||
setSignalSet(&sigset);
|
||||
pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset);
|
||||
|
||||
// fire up the INT and TERM signal handler thread. we could
|
||||
// instead arrange to catch and handle these signals but
|
||||
|
@ -608,10 +611,7 @@ CArchMultithreadPosix::startSignalHandler()
|
|||
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);
|
||||
pthread_sigmask(SIG_UNBLOCK, &oldsigset, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -766,9 +766,7 @@ CArchMultithreadPosix::threadSignalHandler(void*)
|
|||
|
||||
// add signal to mask
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGINT);
|
||||
sigaddset(&sigset, SIGTERM);
|
||||
setSignalSet(&sigset);
|
||||
|
||||
// also wait on SIGABRT. on linux (others?) this thread (process)
|
||||
// will persist after all the other threads evaporate due to an
|
||||
|
@ -791,6 +789,22 @@ CArchMultithreadPosix::threadSignalHandler(void*)
|
|||
#endif
|
||||
|
||||
// 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 void* getResultOfThread(CArchThread);
|
||||
virtual ThreadID getIDOfThread(CArchThread);
|
||||
virtual void setInterruptHandler(InterruptFunc, void*);
|
||||
virtual void interrupt();
|
||||
virtual void setSignalHandler(ESignal, SignalFunc, void*);
|
||||
virtual void raiseSignal(ESignal);
|
||||
|
||||
private:
|
||||
void startSignalHandler();
|
||||
|
@ -104,8 +104,8 @@ private:
|
|||
ThreadID m_nextID;
|
||||
|
||||
pthread_t m_signalThread;
|
||||
InterruptFunc m_signalFunc;
|
||||
void* m_signalUserData;
|
||||
SignalFunc m_signalFunc[kNUM_SIGNALS];
|
||||
void* m_signalUserData[kNUM_SIGNALS];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -80,13 +80,17 @@ CArchThreadImpl::~CArchThreadImpl()
|
|||
|
||||
CArchMultithreadWindows* CArchMultithreadWindows::s_instance = NULL;
|
||||
|
||||
CArchMultithreadWindows::CArchMultithreadWindows() :
|
||||
m_signalFunc(NULL),
|
||||
m_signalUserData(NULL)
|
||||
CArchMultithreadWindows::CArchMultithreadWindows()
|
||||
{
|
||||
assert(s_instance == NULL);
|
||||
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
|
||||
m_threadMutex = newMutex();
|
||||
|
||||
|
@ -529,23 +533,24 @@ CArchMultithreadWindows::getIDOfThread(CArchThread thread)
|
|||
}
|
||||
|
||||
void
|
||||
CArchMultithreadWindows::setInterruptHandler(InterruptFunc func, void* userData)
|
||||
CArchMultithreadWindows::setSignalHandler(
|
||||
ESignal signal, SignalFunc func, void* userData)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
m_signalFunc = func;
|
||||
m_signalUserData = userData;
|
||||
m_signalFunc[signal] = func;
|
||||
m_signalUserData[signal] = userData;
|
||||
unlockMutex(m_threadMutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadWindows::interrupt()
|
||||
CArchMultithreadWindows::raiseSignal(ESignal signal)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
if (m_signalFunc != NULL) {
|
||||
m_signalFunc(m_signalUserData);
|
||||
if (m_signalFunc[signal] != NULL) {
|
||||
m_signalFunc[signal](signal, m_signalUserData[signal]);
|
||||
ARCH->unblockPollSocket(m_mainThread);
|
||||
}
|
||||
else {
|
||||
else if (signal == kINTERRUPT || signal == kTERMINATE) {
|
||||
ARCH->cancelThread(m_mainThread);
|
||||
}
|
||||
unlockMutex(m_threadMutex);
|
||||
|
|
|
@ -81,8 +81,8 @@ public:
|
|||
virtual bool isExitedThread(CArchThread);
|
||||
virtual void* getResultOfThread(CArchThread);
|
||||
virtual ThreadID getIDOfThread(CArchThread);
|
||||
virtual void setInterruptHandler(InterruptFunc, void*);
|
||||
virtual void interrupt();
|
||||
virtual void setSignalHandler(ESignal, SignalFunc, void*);
|
||||
virtual void raiseSignal(ESignal);
|
||||
|
||||
private:
|
||||
CArchThreadImpl* find(DWORD id);
|
||||
|
@ -107,8 +107,8 @@ private:
|
|||
CThreadList m_threadList;
|
||||
CArchThread m_mainThread;
|
||||
|
||||
InterruptFunc m_signalFunc;
|
||||
void* m_signalUserData;
|
||||
SignalFunc m_signalFunc[kNUM_SIGNALS];
|
||||
void* m_signalUserData[kNUM_SIGNALS];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -71,6 +71,19 @@ public:
|
|||
typedef void* (*ThreadFunc)(void*);
|
||||
//! Type of thread identifier
|
||||
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
|
||||
//@{
|
||||
|
@ -242,12 +255,16 @@ public:
|
|||
Sets the function to call on receipt of an external interrupt.
|
||||
By default and when \p func is NULL, the main thread is cancelled.
|
||||
*/
|
||||
typedef void (*InterruptFunc)(void*);
|
||||
virtual void setInterruptHandler(InterruptFunc func,
|
||||
virtual void setSignalHandler(ESignal, SignalFunc func,
|
||||
void* userData) = 0;
|
||||
|
||||
//! Invoke the interrupt handler
|
||||
virtual void interrupt() = 0;
|
||||
//! Invoke the signal handler
|
||||
/*!
|
||||
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
|
||||
* Copyright (C) 2004 Chris Schoeneman
|
||||
*
|
||||
|
@ -22,7 +22,7 @@
|
|||
// interrupt handler. this just adds a quit event to the queue.
|
||||
static
|
||||
void
|
||||
interrupt(void*)
|
||||
interrupt(CArch::ESignal, void*)
|
||||
{
|
||||
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||
}
|
||||
|
@ -37,14 +37,16 @@ CEventQueue::CEventQueue() :
|
|||
{
|
||||
setInstance(this);
|
||||
m_mutex = ARCH->newMutex();
|
||||
ARCH->setInterruptHandler(&interrupt, NULL);
|
||||
ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, NULL);
|
||||
ARCH->setSignalHandler(CArch::kTERMINATE, &interrupt, NULL);
|
||||
m_buffer = new CSimpleEventQueueBuffer;
|
||||
}
|
||||
|
||||
CEventQueue::~CEventQueue()
|
||||
{
|
||||
delete m_buffer;
|
||||
ARCH->setInterruptHandler(NULL, NULL);
|
||||
ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
|
||||
ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
|
||||
ARCH->closeMutex(m_mutex);
|
||||
setInstance(NULL);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue