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

@@ -142,9 +142,10 @@ namespace CodeDweller {
std::vector<Service::Callback *> Service::stopCallbacks;
int Service::callbackTimeout_ms = 30 * 1000;
int Service::stopCallbackTimeout_ms = 30 * 1000;
Service::Service() {
Service::Service() :
stopCallbacksActive(true) {
}
@@ -383,8 +384,8 @@ namespace CodeDweller {
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) {
@@ -453,7 +454,7 @@ namespace CodeDweller {
serviceStatus.dwCurrentState = SERVICE_PAUSE_PENDING;
serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 1;
serviceStatus.dwWaitHint = callbackTimeout_ms;
serviceStatus.dwWaitHint = 1000 * 60;
(void) SetServiceStatus(serviceStatusHandle, &serviceStatus);
pauseReceived = true;
@@ -522,7 +523,7 @@ namespace CodeDweller {
serviceStatus.dwCurrentState = SERVICE_CONTINUE_PENDING;
serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 1;
serviceStatus.dwWaitHint = callbackTimeout_ms;
serviceStatus.dwWaitHint = 1000 * 60;
(void) SetServiceStatus(serviceStatusHandle, &serviceStatus);
resumeReceived = true;
@@ -547,27 +548,51 @@ namespace CodeDweller {
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
{
#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
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;
@@ -602,58 +627,11 @@ namespace CodeDweller {
{
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) {
(*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;
@@ -662,27 +640,11 @@ namespace CodeDweller {
{
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) {
(*callback)();
timeoutTime =
std::chrono::steady_clock::now() +
std::chrono::milliseconds(callbackTimeout_ms);
}
callbacksActive = false;
watchdogThread.join();
}
break;
@@ -691,12 +653,12 @@ namespace CodeDweller {
{
stopReceived = true;
callbacksActive = true;
stopCallbacksActive = true;
// Get the timeout time.
timeoutTime =
std::chrono::steady_clock::now() +
std::chrono::milliseconds(callbackTimeout_ms);
std::chrono::milliseconds(stopCallbackTimeout_ms);
// Start watchdog thread.
std::thread watchdogThread(&Service::watchdog, this);
@@ -705,10 +667,10 @@ namespace CodeDweller {
(*callback)();
timeoutTime =
std::chrono::steady_clock::now() +
std::chrono::milliseconds(callbackTimeout_ms);
std::chrono::milliseconds(stopCallbackTimeout_ms);
}
callbacksActive = false;
stopCallbacksActive = false;
watchdogThread.join();
@@ -730,51 +692,17 @@ namespace CodeDweller {
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.
std::chrono::milliseconds sleepTime(100);
while (std::chrono::steady_clock::now() < timeoutTime) {
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;
}
#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.
#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);
}

+ 11
- 11
service.hpp View File

@@ -175,15 +175,15 @@ namespace CodeDweller {
//
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.
//
// \param[in] timeout_ms is the timeout in milliseconds. If a
// 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:

@@ -290,8 +290,14 @@ namespace CodeDweller {
/// Functions to invoke when the Stop is received.
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

@@ -314,12 +320,6 @@ namespace CodeDweller {

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

};

Loading…
Cancel
Save