|
|
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|