Fixed running as a service on Windows NT family.
This commit is contained in:
parent
784297af24
commit
a55119f096
|
@ -145,6 +145,7 @@ realMain(void)
|
||||||
locked = false;
|
locked = false;
|
||||||
s_client->mainLoop();
|
s_client->mainLoop();
|
||||||
locked = true;
|
locked = true;
|
||||||
|
DAEMON_RUNNING(false);
|
||||||
|
|
||||||
// get client status
|
// get client status
|
||||||
if (s_client->wasRejected()) {
|
if (s_client->wasRejected()) {
|
||||||
|
@ -157,6 +158,7 @@ realMain(void)
|
||||||
#define FINALLY do { \
|
#define FINALLY do { \
|
||||||
if (!locked) { \
|
if (!locked) { \
|
||||||
DAEMON_RUNNING(false); \
|
DAEMON_RUNNING(false); \
|
||||||
|
locked = true; \
|
||||||
} \
|
} \
|
||||||
if (s_client != NULL) { \
|
if (s_client != NULL) { \
|
||||||
if (opened) { \
|
if (opened) { \
|
||||||
|
@ -488,13 +490,6 @@ byeThrow(int x)
|
||||||
CArchMiscWindows::daemonFailed(x);
|
CArchMiscWindows::daemonFailed(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
daemonStop(void)
|
|
||||||
{
|
|
||||||
s_client->exitMainLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup(int argc, const char** argv)
|
daemonStartup(int argc, const char** argv)
|
||||||
|
@ -511,7 +506,7 @@ daemonStartup(int argc, const char** argv)
|
||||||
ARG->m_backend = false;
|
ARG->m_backend = false;
|
||||||
|
|
||||||
// run as a service
|
// run as a service
|
||||||
return CArchMiscWindows::runDaemon(realMain, daemonStop);
|
return CArchMiscWindows::runDaemon(realMain);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -545,12 +540,13 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||||
// of the service code path.
|
// of the service code path.
|
||||||
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||||
int result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
try {
|
||||||
if (result == -1) {
|
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||||
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
}
|
||||||
|
catch (XArchDaemon& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||||
return kExitFailed;
|
return kExitFailed;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse command line
|
// parse command line
|
||||||
|
@ -564,8 +560,8 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
try {
|
try {
|
||||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||||
}
|
}
|
||||||
catch (XArchDaemon&) {
|
catch (XArchDaemon& e) {
|
||||||
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,12 +175,12 @@ realMain(void)
|
||||||
DAEMON_RUNNING(true);
|
DAEMON_RUNNING(true);
|
||||||
locked = false;
|
locked = false;
|
||||||
s_server->mainLoop();
|
s_server->mainLoop();
|
||||||
locked = true;
|
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
#define FINALLY do { \
|
#define FINALLY do { \
|
||||||
if (!locked) { \
|
if (!locked) { \
|
||||||
DAEMON_RUNNING(false); \
|
DAEMON_RUNNING(false); \
|
||||||
|
locked = true; \
|
||||||
} \
|
} \
|
||||||
if (s_server != NULL) { \
|
if (s_server != NULL) { \
|
||||||
if (opened) { \
|
if (opened) { \
|
||||||
|
@ -619,13 +619,6 @@ byeThrow(int x)
|
||||||
CArchMiscWindows::daemonFailed(x);
|
CArchMiscWindows::daemonFailed(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
daemonStop(void)
|
|
||||||
{
|
|
||||||
s_server->exitMainLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup(int argc, const char** argv)
|
daemonStartup(int argc, const char** argv)
|
||||||
|
@ -645,7 +638,7 @@ daemonStartup(int argc, const char** argv)
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
// run as a service
|
// run as a service
|
||||||
return CArchMiscWindows::runDaemon(realMain, daemonStop);
|
return CArchMiscWindows::runDaemon(realMain);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -682,8 +675,8 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
try {
|
try {
|
||||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||||
}
|
}
|
||||||
catch (XArchDaemon&) {
|
catch (XArchDaemon& e) {
|
||||||
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||||
return kExitFailed;
|
return kExitFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -702,8 +695,8 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
try {
|
try {
|
||||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||||
}
|
}
|
||||||
catch (XArchDaemon&) {
|
catch (XArchDaemon& e) {
|
||||||
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,8 @@
|
||||||
|
|
||||||
CArchDaemonWindows* CArchDaemonWindows::s_daemon = NULL;
|
CArchDaemonWindows* CArchDaemonWindows::s_daemon = NULL;
|
||||||
|
|
||||||
CArchDaemonWindows::CArchDaemonWindows()
|
CArchDaemonWindows::CArchDaemonWindows() :
|
||||||
|
m_daemonThread(NULL)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
@ -35,11 +36,11 @@ CArchDaemonWindows::~CArchDaemonWindows()
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
CArchDaemonWindows::runDaemon(RunFunc runFunc, StopFunc stopFunc)
|
CArchDaemonWindows::runDaemon(RunFunc runFunc)
|
||||||
{
|
{
|
||||||
assert(s_daemon != NULL);
|
assert(s_daemon != NULL);
|
||||||
|
|
||||||
return s_daemon->doRunDaemon(runFunc, stopFunc);
|
return s_daemon->doRunDaemon(runFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -293,7 +294,7 @@ CArchDaemonWindows::daemonize(const char* name, DaemonFunc func)
|
||||||
// hook us up to the service control manager. this won't return
|
// hook us up to the service control manager. this won't return
|
||||||
// (if successful) until the processes have terminated.
|
// (if successful) until the processes have terminated.
|
||||||
s_daemon = this;
|
s_daemon = this;
|
||||||
if (StartServiceCtrlDispatcher(entry)) {
|
if (StartServiceCtrlDispatcher(entry) == 0) {
|
||||||
// StartServiceCtrlDispatcher failed
|
// StartServiceCtrlDispatcher failed
|
||||||
s_daemon = NULL;
|
s_daemon = NULL;
|
||||||
throw XArchDaemonFailed(new XArchEvalWindows);
|
throw XArchDaemonFailed(new XArchEvalWindows);
|
||||||
|
@ -536,7 +537,7 @@ CArchDaemonWindows::openUserStartupKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
|
CArchDaemonWindows::doRunDaemon(RunFunc run)
|
||||||
{
|
{
|
||||||
// should only be called from DaemonFunc
|
// should only be called from DaemonFunc
|
||||||
assert(m_serviceMutex != NULL);
|
assert(m_serviceMutex != NULL);
|
||||||
|
@ -546,7 +547,6 @@ CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
|
||||||
ARCH->lockMutex(m_serviceMutex);
|
ARCH->lockMutex(m_serviceMutex);
|
||||||
try {
|
try {
|
||||||
int result;
|
int result;
|
||||||
m_stop = stop;
|
|
||||||
m_serviceHandlerWaiting = false;
|
m_serviceHandlerWaiting = false;
|
||||||
m_serviceRunning = false;
|
m_serviceRunning = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -555,13 +555,11 @@ CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
|
||||||
|
|
||||||
// run callback in another thread
|
// run callback in another thread
|
||||||
m_serviceRunning = true;
|
m_serviceRunning = true;
|
||||||
{
|
m_daemonThread = ARCH->newThread(
|
||||||
CArchThread thread = ARCH->newThread(
|
|
||||||
&CArchDaemonWindows::runDaemonThreadEntry, run);
|
&CArchDaemonWindows::runDaemonThreadEntry, run);
|
||||||
ARCH->wait(thread, -1.0);
|
ARCH->wait(m_daemonThread, -1.0);
|
||||||
result = reinterpret_cast<int>(ARCH->getResultOfThread(thread));
|
result = reinterpret_cast<int>(
|
||||||
ARCH->closeThread(thread);
|
ARCH->getResultOfThread(m_daemonThread));
|
||||||
}
|
|
||||||
m_serviceRunning = false;
|
m_serviceRunning = false;
|
||||||
|
|
||||||
// notify handler that the server stopped. if handler
|
// notify handler that the server stopped. if handler
|
||||||
|
@ -585,6 +583,10 @@ CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
|
||||||
if (m_serviceState == SERVICE_STOPPED) {
|
if (m_serviceState == SERVICE_STOPPED) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// done with callback thread
|
||||||
|
ARCH->closeThread(m_daemonThread);
|
||||||
|
m_daemonThread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent daemonHandler from changing state
|
// prevent daemonHandler from changing state
|
||||||
|
@ -598,7 +600,10 @@ CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
|
||||||
setStatus(m_serviceState);
|
setStatus(m_serviceState);
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
m_stop = NULL;
|
if (m_daemonThread != NULL) {
|
||||||
|
ARCH->closeThread(m_daemonThread);
|
||||||
|
m_daemonThread = NULL;
|
||||||
|
}
|
||||||
ARCH->unlockMutex(m_serviceMutex);
|
ARCH->unlockMutex(m_serviceMutex);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -716,7 +721,7 @@ CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell service control manager that we're starting
|
// tell service control manager that we're starting
|
||||||
setStatus(SERVICE_START_PENDING, 0, 1000);
|
setStatus(SERVICE_START_PENDING, 0, 10000);
|
||||||
|
|
||||||
// if no arguments supplied then try getting them from the registry.
|
// if no arguments supplied then try getting them from the registry.
|
||||||
// the first argument doesn't count because it's the service name.
|
// the first argument doesn't count because it's the service name.
|
||||||
|
@ -830,12 +835,12 @@ CArchDaemonWindows::serviceHandler(DWORD ctrl)
|
||||||
case SERVICE_CONTROL_PAUSE:
|
case SERVICE_CONTROL_PAUSE:
|
||||||
// update state
|
// update state
|
||||||
m_serviceState = SERVICE_PAUSE_PENDING;
|
m_serviceState = SERVICE_PAUSE_PENDING;
|
||||||
setStatus(m_serviceState, 0, 1000);
|
setStatus(m_serviceState, 0, 5000);
|
||||||
|
|
||||||
// stop run callback if running and wait for it to finish
|
// stop run callback if running and wait for it to finish
|
||||||
if (m_serviceRunning) {
|
if (m_serviceRunning) {
|
||||||
m_serviceHandlerWaiting = true;
|
m_serviceHandlerWaiting = true;
|
||||||
m_stop();
|
ARCH->cancelThread(m_daemonThread);
|
||||||
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -860,12 +865,12 @@ CArchDaemonWindows::serviceHandler(DWORD ctrl)
|
||||||
case SERVICE_CONTROL_SHUTDOWN:
|
case SERVICE_CONTROL_SHUTDOWN:
|
||||||
// update state
|
// update state
|
||||||
m_serviceState = SERVICE_STOP_PENDING;
|
m_serviceState = SERVICE_STOP_PENDING;
|
||||||
setStatus(m_serviceState, 0, 1000);
|
setStatus(m_serviceState, 0, 5000);
|
||||||
|
|
||||||
// stop run callback if running and wait for it to finish
|
// stop run callback if running and wait for it to finish
|
||||||
if (m_serviceRunning) {
|
if (m_serviceRunning) {
|
||||||
m_serviceHandlerWaiting = true;
|
m_serviceHandlerWaiting = true;
|
||||||
m_stop();
|
ARCH->cancelThread(m_daemonThread);
|
||||||
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
class CArchDaemonWindows : public IArchDaemon {
|
class CArchDaemonWindows : public IArchDaemon {
|
||||||
public:
|
public:
|
||||||
typedef int (*RunFunc)(void);
|
typedef int (*RunFunc)(void);
|
||||||
typedef void (*StopFunc)(void);
|
|
||||||
|
|
||||||
CArchDaemonWindows();
|
CArchDaemonWindows();
|
||||||
virtual ~CArchDaemonWindows();
|
virtual ~CArchDaemonWindows();
|
||||||
|
@ -41,12 +40,13 @@ public:
|
||||||
daemon processing. The \c runFunc should perform the daemon's
|
daemon processing. The \c runFunc should perform the daemon's
|
||||||
main loop, calling \c daemonRunning(true) when it enters the main loop
|
main loop, calling \c daemonRunning(true) when it enters the main loop
|
||||||
(i.e. after initialization) and \c daemonRunning(false) when it leaves
|
(i.e. after initialization) and \c daemonRunning(false) when it leaves
|
||||||
the main loop. The \c stopFunc function is called when the daemon
|
the main loop. The \c runFunc is called in a new thread and when the
|
||||||
must exit the main loop and must cause \c runFunc to return. This
|
daemon must exit the main loop due to some external control the
|
||||||
function returns what \c runFunc returns. \c runFunc should call
|
thread is cancelled on behalf of the client. This function returns
|
||||||
\c daemonFailed() if the daemon fails.
|
what \c runFunc returns. \c runFunc should call \c daemonFailed() if
|
||||||
|
the daemon fails.
|
||||||
*/
|
*/
|
||||||
static int runDaemon(RunFunc runFunc, StopFunc stopFunc);
|
static int runDaemon(RunFunc runFunc);
|
||||||
|
|
||||||
//! Indicate daemon is in main loop
|
//! Indicate daemon is in main loop
|
||||||
/*!
|
/*!
|
||||||
|
@ -87,7 +87,7 @@ private:
|
||||||
static HKEY open95ServicesKey();
|
static HKEY open95ServicesKey();
|
||||||
static HKEY openUserStartupKey();
|
static HKEY openUserStartupKey();
|
||||||
|
|
||||||
int doRunDaemon(RunFunc runFunc, StopFunc stopFunc);
|
int doRunDaemon(RunFunc runFunc);
|
||||||
void doDaemonRunning(bool running);
|
void doDaemonRunning(bool running);
|
||||||
|
|
||||||
static void setStatus(DWORD state);
|
static void setStatus(DWORD state);
|
||||||
|
@ -120,8 +120,8 @@ private:
|
||||||
DWORD m_serviceState;
|
DWORD m_serviceState;
|
||||||
bool m_serviceHandlerWaiting;
|
bool m_serviceHandlerWaiting;
|
||||||
bool m_serviceRunning;
|
bool m_serviceRunning;
|
||||||
StopFunc m_stop;
|
|
||||||
|
|
||||||
|
CArchThread m_daemonThread;
|
||||||
DaemonFunc m_daemonFunc;
|
DaemonFunc m_daemonFunc;
|
||||||
int m_daemonResult;
|
int m_daemonResult;
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ CArchLogWindows::writeLog(ELevel level, const char* msg)
|
||||||
0, // event ID
|
0, // event ID
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
strlen(msg + 1), // raw data size
|
strlen(msg) + 1, // raw data size
|
||||||
NULL,
|
NULL,
|
||||||
const_cast<char*>(msg));// raw data
|
const_cast<char*>(msg));// raw data
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,9 @@ CArchMiscWindows::isWindows95Family()
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
CArchMiscWindows::runDaemon(RunFunc runFunc, StopFunc stopFunc)
|
CArchMiscWindows::runDaemon(RunFunc runFunc)
|
||||||
{
|
{
|
||||||
return CArchDaemonWindows::runDaemon(runFunc, stopFunc);
|
return CArchDaemonWindows::runDaemon(runFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
class CArchMiscWindows {
|
class CArchMiscWindows {
|
||||||
public:
|
public:
|
||||||
typedef int (*RunFunc)(void);
|
typedef int (*RunFunc)(void);
|
||||||
typedef void (*StopFunc)(void);
|
|
||||||
|
|
||||||
//! Test if windows 95, et al.
|
//! Test if windows 95, et al.
|
||||||
/*!
|
/*!
|
||||||
|
@ -31,7 +30,7 @@ public:
|
||||||
/*!
|
/*!
|
||||||
Delegates to CArchDaemonWindows.
|
Delegates to CArchDaemonWindows.
|
||||||
*/
|
*/
|
||||||
static int runDaemon(RunFunc runFunc, StopFunc stopFunc);
|
static int runDaemon(RunFunc runFunc);
|
||||||
|
|
||||||
//! Indicate daemon is in main loop
|
//! Indicate daemon is in main loop
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -311,7 +311,7 @@ CArchMultithreadWindows::closeThread(CArchThread thread)
|
||||||
|
|
||||||
// remove thread from list
|
// remove thread from list
|
||||||
lockMutex(m_threadMutex);
|
lockMutex(m_threadMutex);
|
||||||
assert(findNoRef(thread->m_id) == thread);
|
assert(findNoRefOrCreate(thread->m_id) == thread);
|
||||||
erase(thread);
|
erase(thread);
|
||||||
unlockMutex(m_threadMutex);
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
@ -531,6 +531,23 @@ CArchMultithreadWindows::find(DWORD id)
|
||||||
|
|
||||||
CArchThreadImpl*
|
CArchThreadImpl*
|
||||||
CArchMultithreadWindows::findNoRef(DWORD id)
|
CArchMultithreadWindows::findNoRef(DWORD id)
|
||||||
|
{
|
||||||
|
CArchThreadImpl* impl = findNoRefOrCreate(id);
|
||||||
|
if (impl == NULL) {
|
||||||
|
// create thread for calling thread which isn't in our list and
|
||||||
|
// add it to the list. this won't normally happen but it can if
|
||||||
|
// the system calls us under a new thread, like it does when we
|
||||||
|
// run as a service.
|
||||||
|
impl = new CArchThreadImpl;
|
||||||
|
impl->m_thread = NULL;
|
||||||
|
impl->m_id = GetCurrentThreadId();
|
||||||
|
insert(impl);
|
||||||
|
}
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThreadImpl*
|
||||||
|
CArchMultithreadWindows::findNoRefOrCreate(DWORD id)
|
||||||
{
|
{
|
||||||
// linear search
|
// linear search
|
||||||
for (CThreadList::const_iterator index = m_threadList.begin();
|
for (CThreadList::const_iterator index = m_threadList.begin();
|
||||||
|
@ -548,7 +565,7 @@ CArchMultithreadWindows::insert(CArchThreadImpl* thread)
|
||||||
assert(thread != NULL);
|
assert(thread != NULL);
|
||||||
|
|
||||||
// thread shouldn't already be on the list
|
// thread shouldn't already be on the list
|
||||||
assert(findNoRef(thread->m_id) == NULL);
|
assert(findNoRefOrCreate(thread->m_id) == NULL);
|
||||||
|
|
||||||
// append to list
|
// append to list
|
||||||
m_threadList.push_back(thread);
|
m_threadList.push_back(thread);
|
||||||
|
@ -570,7 +587,7 @@ void
|
||||||
CArchMultithreadWindows::refThread(CArchThreadImpl* thread)
|
CArchMultithreadWindows::refThread(CArchThreadImpl* thread)
|
||||||
{
|
{
|
||||||
assert(thread != NULL);
|
assert(thread != NULL);
|
||||||
assert(findNoRef(thread->m_id) != NULL);
|
assert(findNoRefOrCreate(thread->m_id) != NULL);
|
||||||
++thread->m_refCount;
|
++thread->m_refCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ public:
|
||||||
private:
|
private:
|
||||||
CArchThreadImpl* find(DWORD id);
|
CArchThreadImpl* find(DWORD id);
|
||||||
CArchThreadImpl* findNoRef(DWORD id);
|
CArchThreadImpl* findNoRef(DWORD id);
|
||||||
|
CArchThreadImpl* findNoRefOrCreate(DWORD id);
|
||||||
void insert(CArchThreadImpl* thread);
|
void insert(CArchThreadImpl* thread);
|
||||||
void erase(CArchThreadImpl* thread);
|
void erase(CArchThreadImpl* thread);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue