Browse Source

Implement watchdog for only Stop on both Windows and Linux.


git-svn-id: https://svn.microneil.com/svn/CodeDweller/branches/adeniz_1@45 d34b734f-a00e-4b39-a726-e4eeb87269ab
adeniz_1
adeniz 10 years ago
parent
commit
f9629ec3bc
2 changed files with 63 additions and 135 deletions
  1. 52
    124
      service.cpp
  2. 11
    11
      service.hpp

+ 52
- 124
service.cpp View File

std::vector<Service::Callback *> Service::stopCallbacks; std::vector<Service::Callback *> Service::stopCallbacks;
int Service::callbackTimeout_ms = 30 * 1000;
int Service::stopCallbackTimeout_ms = 30 * 1000;
Service::Service() {
Service::Service() :
stopCallbacksActive(true) {
} }
return cmdLineArgs; return cmdLineArgs;
} }
void Service::setCallbackTimeout_ms(int timeout_ms) {
callbackTimeout_ms = (timeout_ms < 1 ? 1 : timeout_ms);
void Service::setStopCallbackTimeout_ms(int timeout_ms) {
stopCallbackTimeout_ms = (timeout_ms < 1 ? 1 : timeout_ms);
} }
void Service::onPauseCall(Callback &pauseFunctor) { void Service::onPauseCall(Callback &pauseFunctor) {
serviceStatus.dwCurrentState = SERVICE_PAUSE_PENDING; serviceStatus.dwCurrentState = SERVICE_PAUSE_PENDING;
serviceStatus.dwWin32ExitCode = NO_ERROR; serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 1; serviceStatus.dwCheckPoint = 1;
serviceStatus.dwWaitHint = callbackTimeout_ms;
serviceStatus.dwWaitHint = 1000 * 60;
(void) SetServiceStatus(serviceStatusHandle, &serviceStatus); (void) SetServiceStatus(serviceStatusHandle, &serviceStatus);
pauseReceived = true; pauseReceived = true;
serviceStatus.dwCurrentState = SERVICE_CONTINUE_PENDING; serviceStatus.dwCurrentState = SERVICE_CONTINUE_PENDING;
serviceStatus.dwWin32ExitCode = NO_ERROR; serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 1; serviceStatus.dwCheckPoint = 1;
serviceStatus.dwWaitHint = callbackTimeout_ms;
serviceStatus.dwWaitHint = 1000 * 60;
(void) SetServiceStatus(serviceStatusHandle, &serviceStatus); (void) SetServiceStatus(serviceStatusHandle, &serviceStatus);
resumeReceived = true; resumeReceived = true;
case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_SHUTDOWN:
{
#ifdef DEBUG_LOG_FILE #ifdef DEBUG_LOG_FILE
logStream.open(DEBUG_LOG_FILE, std::fstream::app);
logStream << "processCtrlMessage. Received "
<< (message == SERVICE_CONTROL_STOP ? "STOP" : "SHUTDOWN")
<< std::endl;
logStream.close();
logStream.open(DEBUG_LOG_FILE, std::fstream::app);
logStream << "processCtrlMessage. Received "
<< (message == SERVICE_CONTROL_STOP ? "STOP" : "SHUTDOWN")
<< std::endl;
logStream.close();
#endif #endif
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 1;
serviceStatus.dwWaitHint = callbackTimeout_ms;
(void) SetServiceStatus(serviceStatusHandle, &serviceStatus);
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 1;
serviceStatus.dwWaitHint = stopCallbackTimeout_ms;
(void) SetServiceStatus(serviceStatusHandle, &serviceStatus);
stopReceived = true;
stopReceived = true;
stopCallbacksActive = true;
// Get the timeout time.
timeoutTime =
std::chrono::steady_clock::now() +
std::chrono::milliseconds(stopCallbackTimeout_ms);
// Start watchdog thread.
std::thread watchdogThread(&Service::watchdog, this);
for (auto callback : stopCallbacks) {
(*callback)();
timeoutTime =
std::chrono::steady_clock::now() +
std::chrono::milliseconds(stopCallbackTimeout_ms);
serviceStatus.dwCheckPoint++;
(void) SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
stopCallbacksActive = false;
watchdogThread.join();
for (auto callback : stopCallbacks) {
(*callback)();
serviceStatus.dwCheckPoint++;
(void) SetServiceStatus(serviceStatusHandle, &serviceStatus);
} }
break; break;
{ {
pauseReceived = true; pauseReceived = true;
callbacksActive = true;
// Get the timeout time.
timeoutTime =
std::chrono::steady_clock::now() +
std::chrono::milliseconds(callbackTimeout_ms);
// Start watchdog thread.
std::thread watchdogThread(&Service::watchdog, this);
#ifdef DEBUG_LOG_FILE
std::ofstream logStream;
auto startTime = std::chrono::steady_clock::now();
logStream.open(DEBUG_LOG_FILE, std::fstream::app);
logStream << "Service::processMessages. Calling Pause callbacks--"
<< std::endl;
#endif
for (auto callback : pauseCallbacks) { for (auto callback : pauseCallbacks) {
(*callback)(); (*callback)();
timeoutTime =
std::chrono::steady_clock::now() +
std::chrono::milliseconds(callbackTimeout_ms);
#ifdef DEBUG_LOG_FILE
logStream << "Service::processMessages. "
<< "Cumulative time after callback (ms): "
<< std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::steady_clock::now() - startTime).count()
<< std::endl;
#endif
} }
callbacksActive = false;
#ifdef DEBUG_LOG_FILE
logStream << "Service::processMessages. "
<< "Cumulative time after all callback (ms): "
<< std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::steady_clock::now() - startTime).count()
<< std::endl;
#endif
watchdogThread.join();
#ifdef DEBUG_LOG_FILE
logStream << "Service::processMessages. "
<<" Cumulative time after joining watchdog (ms): "
<< std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::steady_clock::now() - startTime).count()
<< std::endl;
logStream.close();
#endif
} }
break; break;
{ {
resumeReceived = true; resumeReceived = true;
callbacksActive = true;
// Get the timeout time.
timeoutTime =
std::chrono::steady_clock::now() +
std::chrono::milliseconds(callbackTimeout_ms);
// Start watchdog thread.
std::thread watchdogThread(&Service::watchdog, this);
for (auto callback : resumeCallbacks) { for (auto callback : resumeCallbacks) {
(*callback)(); (*callback)();
timeoutTime =
std::chrono::steady_clock::now() +
std::chrono::milliseconds(callbackTimeout_ms);
} }
callbacksActive = false;
watchdogThread.join();
} }
break; break;
{ {
stopReceived = true; stopReceived = true;
callbacksActive = true;
stopCallbacksActive = true;
// Get the timeout time. // Get the timeout time.
timeoutTime = timeoutTime =
std::chrono::steady_clock::now() + std::chrono::steady_clock::now() +
std::chrono::milliseconds(callbackTimeout_ms);
std::chrono::milliseconds(stopCallbackTimeout_ms);
// Start watchdog thread. // Start watchdog thread.
std::thread watchdogThread(&Service::watchdog, this); std::thread watchdogThread(&Service::watchdog, this);
(*callback)(); (*callback)();
timeoutTime = timeoutTime =
std::chrono::steady_clock::now() + std::chrono::steady_clock::now() +
std::chrono::milliseconds(callbackTimeout_ms);
std::chrono::milliseconds(stopCallbackTimeout_ms);
} }
callbacksActive = false;
stopCallbacksActive = false;
watchdogThread.join(); watchdogThread.join();
void Service::watchdog() { void Service::watchdog() {
#ifdef DEBUG_LOG_FILE
auto startTime = std::chrono::steady_clock::now();
std::ofstream logStream;
logStream.open(DEBUG_LOG_FILE, std::fstream::app);
logStream << "**Service::watchdog. Thread starting." << std::endl;
logStream.close();
#endif
// Sleep and check whether the process should exit. // Sleep and check whether the process should exit.
std::chrono::milliseconds sleepTime(100); std::chrono::milliseconds sleepTime(100);
while (std::chrono::steady_clock::now() < timeoutTime) { while (std::chrono::steady_clock::now() < timeoutTime) {
std::this_thread::sleep_for(sleepTime); std::this_thread::sleep_for(sleepTime);
if (!callbacksActive) {
#ifdef DEBUG_LOG_FILE
logStream.open(DEBUG_LOG_FILE, std::fstream::app);
logStream << "**Service::watchdog. Exiting at "
<< std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::steady_clock::now() - startTime).count()
<< " ms after starting"
<< std::endl;
logStream.close();
#endif
if (!stopCallbacksActive) {
return; return;
} }
#ifdef DEBUG_LOG_FILE
logStream.open(DEBUG_LOG_FILE, std::fstream::app);
logStream << "Service::watchdog. Cumulative time since starting (ms): "
<< std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::steady_clock::now() - startTime).count()
<< std::endl;
logStream.close();
#endif
} }
// Timeout expired. // Timeout expired.
#ifdef DEBUG_LOG_FILE
logStream.open(DEBUG_LOG_FILE, std::fstream::app);
logStream << "**Service::watchdog. Callback timeout expired. "
<< "Cumulative time (ms): "
<< std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::steady_clock::now() - startTime).count()
<< std::endl;
logStream.close();
#endif
std::exit(EXIT_FAILURE); std::exit(EXIT_FAILURE);
} }

+ 11
- 11
service.hpp View File

// //
static const std::vector<std::string> &arguments(); static const std::vector<std::string> &arguments();


/// Set the timeout for executing one callback.
/// Set the timeout for executing one Stop callback.
// //
// If a callback takes longer than the specified timeout, the
// If a Stop callback takes longer than the specified timeout, the
// service aborts. // service aborts.
// //
// \param[in] timeout_ms is the timeout in milliseconds. If a // \param[in] timeout_ms is the timeout in milliseconds. If a
// value less than 1 is specified, a value of 1 is used. // value less than 1 is specified, a value of 1 is used.
// //
static void setCallbackTimeout_ms(int timeout_ms);
static void setStopCallbackTimeout_ms(int timeout_ms);


private: private:


/// Functions to invoke when the Stop is received. /// Functions to invoke when the Stop is received.
static std::vector<Callback *> stopCallbacks; static std::vector<Callback *> stopCallbacks;


/// Callback timeout.
static int callbackTimeout_ms;
/// Stop message callback timeout.
static int stopCallbackTimeout_ms;

/// Absolute time at which the Stop callback timeout expires.
std::chrono::time_point<std::chrono::steady_clock> timeoutTime;

/// True if the Stop callbacks are being invoked.
bool stopCallbacksActive;


#ifdef WIN32 #ifdef WIN32




friend int ::main(int argc, char *argv[]); friend int ::main(int argc, char *argv[]);


/// Absolute time at which the callback timeout expires.
std::chrono::time_point<std::chrono::steady_clock> timeoutTime;

/// True if the callbacks are being invoked.
bool callbacksActive;

#endif #endif


}; };

Loading…
Cancel
Save