Fixed running as a service on Windows NT family.

This commit is contained in:
crs 2003-01-22 08:36:43 +00:00
parent 784297af24
commit a55119f096
9 changed files with 74 additions and 63 deletions

View File

@ -145,6 +145,7 @@ realMain(void)
locked = false;
s_client->mainLoop();
locked = true;
DAEMON_RUNNING(false);
// get client status
if (s_client->wasRejected()) {
@ -157,6 +158,7 @@ realMain(void)
#define FINALLY do { \
if (!locked) { \
DAEMON_RUNNING(false); \
locked = true; \
} \
if (s_client != NULL) { \
if (opened) { \
@ -488,13 +490,6 @@ byeThrow(int x)
CArchMiscWindows::daemonFailed(x);
}
static
void
daemonStop(void)
{
s_client->exitMainLoop();
}
static
int
daemonStartup(int argc, const char** argv)
@ -511,7 +506,7 @@ daemonStartup(int argc, const char** argv)
ARG->m_backend = false;
// run as a service
return CArchMiscWindows::runDaemon(realMain, daemonStop);
return CArchMiscWindows::runDaemon(realMain);
}
static
@ -545,12 +540,13 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
int result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
if (result == -1) {
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
return kExitFailed;
}
return result;
}
// parse command line
@ -564,8 +560,8 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
}
catch (XArchDaemon&) {
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));
result = kExitFailed;
}
}

View File

@ -175,12 +175,12 @@ realMain(void)
DAEMON_RUNNING(true);
locked = false;
s_server->mainLoop();
locked = true;
// clean up
#define FINALLY do { \
if (!locked) { \
DAEMON_RUNNING(false); \
locked = true; \
} \
if (s_server != NULL) { \
if (opened) { \
@ -209,7 +209,7 @@ realMain(void)
catch (...) {
// don't try to restart and fail
ARG->m_restartable = false;
result = kExitFailed;
result = kExitFailed;
FINALLY;
}
#undef FINALLY
@ -220,7 +220,7 @@ realMain(void)
catch (XThread&) {
// terminated
ARG->m_restartable = false;
result = kExitTerminated;
result = kExitTerminated;
}
} while (ARG->m_restartable);
@ -619,13 +619,6 @@ byeThrow(int x)
CArchMiscWindows::daemonFailed(x);
}
static
void
daemonStop(void)
{
s_server->exitMainLoop();
}
static
int
daemonStartup(int argc, const char** argv)
@ -645,7 +638,7 @@ daemonStartup(int argc, const char** argv)
loadConfig();
// run as a service
return CArchMiscWindows::runDaemon(realMain, daemonStop);
return CArchMiscWindows::runDaemon(realMain);
}
static
@ -682,8 +675,8 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon&) {
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;
}
}
@ -702,8 +695,8 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
}
catch (XArchDaemon&) {
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));
result = kExitFailed;
}
}

View File

@ -24,7 +24,8 @@
CArchDaemonWindows* CArchDaemonWindows::s_daemon = NULL;
CArchDaemonWindows::CArchDaemonWindows()
CArchDaemonWindows::CArchDaemonWindows() :
m_daemonThread(NULL)
{
// do nothing
}
@ -35,11 +36,11 @@ CArchDaemonWindows::~CArchDaemonWindows()
}
int
CArchDaemonWindows::runDaemon(RunFunc runFunc, StopFunc stopFunc)
CArchDaemonWindows::runDaemon(RunFunc runFunc)
{
assert(s_daemon != NULL);
return s_daemon->doRunDaemon(runFunc, stopFunc);
return s_daemon->doRunDaemon(runFunc);
}
void
@ -293,7 +294,7 @@ CArchDaemonWindows::daemonize(const char* name, DaemonFunc func)
// hook us up to the service control manager. this won't return
// (if successful) until the processes have terminated.
s_daemon = this;
if (StartServiceCtrlDispatcher(entry)) {
if (StartServiceCtrlDispatcher(entry) == 0) {
// StartServiceCtrlDispatcher failed
s_daemon = NULL;
throw XArchDaemonFailed(new XArchEvalWindows);
@ -536,7 +537,7 @@ CArchDaemonWindows::openUserStartupKey()
}
int
CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
CArchDaemonWindows::doRunDaemon(RunFunc run)
{
// should only be called from DaemonFunc
assert(m_serviceMutex != NULL);
@ -546,7 +547,6 @@ CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
ARCH->lockMutex(m_serviceMutex);
try {
int result;
m_stop = stop;
m_serviceHandlerWaiting = false;
m_serviceRunning = false;
for (;;) {
@ -555,13 +555,11 @@ CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
// run callback in another thread
m_serviceRunning = true;
{
CArchThread thread = ARCH->newThread(
m_daemonThread = ARCH->newThread(
&CArchDaemonWindows::runDaemonThreadEntry, run);
ARCH->wait(thread, -1.0);
result = reinterpret_cast<int>(ARCH->getResultOfThread(thread));
ARCH->closeThread(thread);
}
ARCH->wait(m_daemonThread, -1.0);
result = reinterpret_cast<int>(
ARCH->getResultOfThread(m_daemonThread));
m_serviceRunning = false;
// notify handler that the server stopped. if handler
@ -585,6 +583,10 @@ CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
if (m_serviceState == SERVICE_STOPPED) {
break;
}
// done with callback thread
ARCH->closeThread(m_daemonThread);
m_daemonThread = NULL;
}
// prevent daemonHandler from changing state
@ -598,7 +600,10 @@ CArchDaemonWindows::doRunDaemon(RunFunc run, StopFunc stop)
setStatus(m_serviceState);
// clean up
m_stop = NULL;
if (m_daemonThread != NULL) {
ARCH->closeThread(m_daemonThread);
m_daemonThread = NULL;
}
ARCH->unlockMutex(m_serviceMutex);
return result;
@ -716,7 +721,7 @@ CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
}
// 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.
// the first argument doesn't count because it's the service name.
@ -830,12 +835,12 @@ CArchDaemonWindows::serviceHandler(DWORD ctrl)
case SERVICE_CONTROL_PAUSE:
// update state
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
if (m_serviceRunning) {
m_serviceHandlerWaiting = true;
m_stop();
ARCH->cancelThread(m_daemonThread);
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
}
@ -860,12 +865,12 @@ CArchDaemonWindows::serviceHandler(DWORD ctrl)
case SERVICE_CONTROL_SHUTDOWN:
// update state
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
if (m_serviceRunning) {
m_serviceHandlerWaiting = true;
m_stop();
ARCH->cancelThread(m_daemonThread);
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
}

View File

@ -29,7 +29,6 @@
class CArchDaemonWindows : public IArchDaemon {
public:
typedef int (*RunFunc)(void);
typedef void (*StopFunc)(void);
CArchDaemonWindows();
virtual ~CArchDaemonWindows();
@ -41,12 +40,13 @@ public:
daemon processing. The \c runFunc should perform the daemon's
main loop, calling \c daemonRunning(true) when it enters the main loop
(i.e. after initialization) and \c daemonRunning(false) when it leaves
the main loop. The \c stopFunc function is called when the daemon
must exit the main loop and must cause \c runFunc to return. This
function returns what \c runFunc returns. \c runFunc should call
\c daemonFailed() if the daemon fails.
the main loop. The \c runFunc is called in a new thread and when the
daemon must exit the main loop due to some external control the
thread is cancelled on behalf of the client. This function returns
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
/*!
@ -87,7 +87,7 @@ private:
static HKEY open95ServicesKey();
static HKEY openUserStartupKey();
int doRunDaemon(RunFunc runFunc, StopFunc stopFunc);
int doRunDaemon(RunFunc runFunc);
void doDaemonRunning(bool running);
static void setStatus(DWORD state);
@ -120,8 +120,8 @@ private:
DWORD m_serviceState;
bool m_serviceHandlerWaiting;
bool m_serviceRunning;
StopFunc m_stop;
CArchThread m_daemonThread;
DaemonFunc m_daemonFunc;
int m_daemonResult;

View File

@ -77,7 +77,7 @@ CArchLogWindows::writeLog(ELevel level, const char* msg)
0, // event ID
NULL,
0,
strlen(msg + 1), // raw data size
strlen(msg) + 1, // raw data size
NULL,
const_cast<char*>(msg));// raw data
}

View File

@ -35,9 +35,9 @@ CArchMiscWindows::isWindows95Family()
}
int
CArchMiscWindows::runDaemon(RunFunc runFunc, StopFunc stopFunc)
CArchMiscWindows::runDaemon(RunFunc runFunc)
{
return CArchDaemonWindows::runDaemon(runFunc, stopFunc);
return CArchDaemonWindows::runDaemon(runFunc);
}
void

View File

@ -19,7 +19,6 @@
class CArchMiscWindows {
public:
typedef int (*RunFunc)(void);
typedef void (*StopFunc)(void);
//! Test if windows 95, et al.
/*!
@ -31,7 +30,7 @@ public:
/*!
Delegates to CArchDaemonWindows.
*/
static int runDaemon(RunFunc runFunc, StopFunc stopFunc);
static int runDaemon(RunFunc runFunc);
//! Indicate daemon is in main loop
/*!

View File

@ -311,7 +311,7 @@ CArchMultithreadWindows::closeThread(CArchThread thread)
// remove thread from list
lockMutex(m_threadMutex);
assert(findNoRef(thread->m_id) == thread);
assert(findNoRefOrCreate(thread->m_id) == thread);
erase(thread);
unlockMutex(m_threadMutex);
@ -531,6 +531,23 @@ CArchMultithreadWindows::find(DWORD id)
CArchThreadImpl*
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
for (CThreadList::const_iterator index = m_threadList.begin();
@ -548,7 +565,7 @@ CArchMultithreadWindows::insert(CArchThreadImpl* thread)
assert(thread != NULL);
// thread shouldn't already be on the list
assert(findNoRef(thread->m_id) == NULL);
assert(findNoRefOrCreate(thread->m_id) == NULL);
// append to list
m_threadList.push_back(thread);
@ -570,7 +587,7 @@ void
CArchMultithreadWindows::refThread(CArchThreadImpl* thread)
{
assert(thread != NULL);
assert(findNoRef(thread->m_id) != NULL);
assert(findNoRefOrCreate(thread->m_id) != NULL);
++thread->m_refCount;
}

View File

@ -78,6 +78,7 @@ public:
private:
CArchThreadImpl* find(DWORD id);
CArchThreadImpl* findNoRef(DWORD id);
CArchThreadImpl* findNoRefOrCreate(DWORD id);
void insert(CArchThreadImpl* thread);
void erase(CArchThreadImpl* thread);