1
0
Fork 0

Finalize our own service control infrastructure.

This commit is contained in:
Willi Goesgens 2015-03-17 15:00:08 +01:00
parent 043b0cb62f
commit 92389a33b2
1 changed files with 50 additions and 80 deletions

View File

@ -227,7 +227,8 @@ static void DeleteService (int argc, char* argv[], bool force) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief Start the service and optionaly wait till its up & running /// @brief Start the service and optionaly wait till its up & running
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void StartArangoService(bool WaitForRunning) {
static void StartArangoService (bool WaitForRunning) {
TRI_ERRORBUF; TRI_ERRORBUF;
SERVICE_STATUS_PROCESS ssp; SERVICE_STATUS_PROCESS ssp;
DWORD bytesNeeded; DWORD bytesNeeded;
@ -239,9 +240,7 @@ static void StartArangoService(bool WaitForRunning) {
std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf << std::endl; std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Get a handle to the service. // Get a handle to the service.
auto arangoService = OpenService(schSCManager, auto arangoService = OpenService(schSCManager,
ServiceName.c_str(), ServiceName.c_str(),
SERVICE_START | SERVICE_START |
@ -254,7 +253,7 @@ static void StartArangoService(bool WaitForRunning) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Make sure the service is not already stopped. // Make sure the service is not already started.
if ( !QueryServiceStatusEx(arangoService, if ( !QueryServiceStatusEx(arangoService,
SC_STATUS_PROCESS_INFO, SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssp, (LPBYTE)&ssp,
@ -271,23 +270,20 @@ static void StartArangoService(bool WaitForRunning) {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
if (!StartService(arangoService, 0, NULL) ) {
TRI_SYSTEM_ERROR();
std::cout << "StartService failed " << windowsErrorBuf << std::endl;
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
// Save the tick count and initial checkpoint. // Save the tick count and initial checkpoint.
auto startTickCount = GetTickCount(); ssp.dwCurrentState = SERVICE_START_PENDING;
auto oldCheckPoint = ssp.dwCheckPoint;
while (WaitForRunning && ssp.dwCurrentState == SERVICE_RUNNING) { while (WaitForRunning && ssp.dwCurrentState != SERVICE_START_PENDING) {
// Do not wait longer than the wait hint. A good interval is // we sleep 1 second before we re-check the status.
// one-tenth the wait hint, but no less than 1 second and no Sleep(1000);
// more than 10 seconds.
auto dwWaitTime = ssp.dwWaitHint / 10;
if( dwWaitTime < 1000 )
dwWaitTime = 1000;
else if ( dwWaitTime > 10000 )
dwWaitTime = 10000;
Sleep( dwWaitTime );
// Check the status again. // Check the status again.
@ -296,22 +292,12 @@ static void StartArangoService(bool WaitForRunning) {
(LPBYTE) &ssp, // address of structure (LPBYTE) &ssp, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure sizeof(SERVICE_STATUS_PROCESS), // size of structure
&bytesNeeded ) ) { &bytesNeeded ) ) {
printf("QueryServiceStatusEx failed (%d)\n", GetLastError()); TRI_SYSTEM_ERROR();
break; std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf << std::endl;
} break;
if ( ssp.dwCheckPoint > oldCheckPoint ) {
// Continue to wait and check.
startTickCount = GetTickCount();
oldCheckPoint = ssp.dwCheckPoint;
}
else {
if(GetTickCount() - startTickCount > ssp.dwWaitHint) {
// No progress made within the wait hint.
break;
}
} }
} }
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager); CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
@ -319,7 +305,8 @@ static void StartArangoService(bool WaitForRunning) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief Stop the service and optionaly wait till its all dead /// @brief Stop the service and optionaly wait till its all dead
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void StopArangoService(bool WaitForShutdown) {
static void StopArangoService (bool WaitForShutdown) {
TRI_ERRORBUF; TRI_ERRORBUF;
SERVICE_STATUS_PROCESS ssp; SERVICE_STATUS_PROCESS ssp;
@ -334,7 +321,6 @@ static void StopArangoService(bool WaitForShutdown) {
} }
// Get a handle to the service. // Get a handle to the service.
auto arangoService = OpenService(schSCManager, auto arangoService = OpenService(schSCManager,
ServiceName.c_str(), ServiceName.c_str(),
SERVICE_STOP | SERVICE_STOP |
@ -365,51 +351,36 @@ static void StopArangoService(bool WaitForShutdown) {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
// Save the tick count and initial checkpoint. // Send a stop code to the service.
auto startTickCount = GetTickCount(); if ( !ControlService(arangoService,
auto oldCheckPoint = ssp.dwCheckPoint; SERVICE_CONTROL_STOP,
(LPSERVICE_STATUS) &ssp ) ) {
TRI_SYSTEM_ERROR();
std::cerr << "ControlService failed with " << windowsErrorBuf << std::endl;
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
while (WaitForShutdown && ssp.dwCurrentState == SERVICE_STOPPED) { while (WaitForShutdown && ssp.dwCurrentState == SERVICE_STOPPED) {
// Do not wait longer than the wait hint. A good interval is // we sleep 1 second before we re-check the status.
// one-tenth the wait hint, but no less than 1 second and no Sleep(1000);
// more than 10 seconds.
auto dwWaitTime = ssp.dwWaitHint / 10;
if( dwWaitTime < 1000 )
dwWaitTime = 1000;
else if ( dwWaitTime > 10000 )
dwWaitTime = 10000;
Sleep( dwWaitTime );
// Check the status again.
if (!QueryServiceStatusEx(arangoService, if (!QueryServiceStatusEx(arangoService,
SC_STATUS_PROCESS_INFO, // info level SC_STATUS_PROCESS_INFO,
(LPBYTE) &ssp, // address of structure (LPBYTE) &ssp,
sizeof(SERVICE_STATUS_PROCESS), // size of structure sizeof(SERVICE_STATUS_PROCESS),
&bytesNeeded ) ) { &bytesNeeded ) ) {
TRI_SYSTEM_ERROR(); TRI_SYSTEM_ERROR();
printf("QueryServiceStatusEx failed (%s)\n", windowsErrorBuf); printf("QueryServiceStatusEx failed (%s)\n", windowsErrorBuf);
break; CloseServiceHandle(arangoService);
} CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
if ( ssp.dwCheckPoint > oldCheckPoint ) {
// Continue to wait and check.
startTickCount = GetTickCount();
oldCheckPoint = ssp.dwCheckPoint;
}
else {
if(GetTickCount() - startTickCount > ssp.dwWaitHint) {
// No progress made within the wait hint.
break;
}
} }
} }
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager); CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
@ -500,7 +471,7 @@ static void WINAPI ServiceCtrl (DWORD dwCtrlCode) {
#include <DbgHelp.h> #include <DbgHelp.h>
LONG CALLBACK unhandledExceptionHandler(EXCEPTION_POINTERS *e) { LONG CALLBACK unhandledExceptionHandler (EXCEPTION_POINTERS *e) {
#if HAVE_BACKTRACE #if HAVE_BACKTRACE
if ((e != nullptr) && (e->ExceptionRecord != nullptr)) { if ((e != nullptr) && (e->ExceptionRecord != nullptr)) {
@ -559,8 +530,6 @@ LONG CALLBACK unhandledExceptionHandler(EXCEPTION_POINTERS *e) {
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief global entry function /// @brief global entry function
/// ///
@ -628,14 +597,17 @@ void TRI_GlobalExitFunction (int exitCode, void* data) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
class WindowsArangoServer : public ArangoServer { class WindowsArangoServer : public ArangoServer {
private: private:
DWORD _progress; DWORD _progress;
protected: protected:
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief wrap ArangoDB server so we can properly emmit a status once we're /// @brief wrap ArangoDB server so we can properly emmit a status once we're
/// really up and running. /// really up and running.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
virtual void startupProgress() { virtual void startupProgress () {
SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, _progress++, 20000); SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, _progress++, 20000);
} }
@ -668,7 +640,6 @@ static int ARGC;
static char** ARGV; static char** ARGV;
static void WINAPI ServiceMain (DWORD dwArgc, LPSTR *lpszArgv) { static void WINAPI ServiceMain (DWORD dwArgc, LPSTR *lpszArgv) {
// register the service ctrl handler, lpszArgv[0] contains service name // register the service ctrl handler, lpszArgv[0] contains service name
ServiceStatus = RegisterServiceCtrlHandlerA(lpszArgv[0], (LPHANDLER_FUNCTION) ServiceCtrl); ServiceStatus = RegisterServiceCtrlHandlerA(lpszArgv[0], (LPHANDLER_FUNCTION) ServiceCtrl);
@ -684,12 +655,11 @@ static void WINAPI ServiceMain (DWORD dwArgc, LPSTR *lpszArgv) {
SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0); SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief parse windows specific commandline options /// @brief parse windows specific commandline options
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool TRI_ParseMoreArgs(int argc, char* argv[]) bool TRI_ParseMoreArgs (int argc, char* argv[])
{ {
SetUnhandledExceptionFilter(unhandledExceptionHandler); SetUnhandledExceptionFilter(unhandledExceptionHandler);
@ -730,7 +700,7 @@ bool TRI_ParseMoreArgs(int argc, char* argv[])
/// @brief start the windows service /// @brief start the windows service
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void TRI_StartService(int argc, char* argv[]) void TRI_StartService (int argc, char* argv[])
{ {
// create and start an ArangoDB server // create and start an ArangoDB server