Allow slow service startup again.
authorIain Patterson <me@iain.cx>
Mon, 15 Dec 2014 14:05:55 +0000 (14:05 +0000)
committerIain Patterson <me@iain.cx>
Tue, 30 Dec 2014 15:27:46 +0000 (15:27 +0000)
Previously we enforced a maximum delay in reporting to the service
manager that the service was started, and waited for the application to
become unthrottled in the background.

Users may prefer that the service not report a started state until the
application is unthrottled.  Therefore we now loop and increment the
status checkpoint and wait hint to satisfy the service manager that we
aren't hung.

Thanks Tom Saul.

service.cpp
service.h

index 52937cf..7e13da7 100644 (file)
@@ -1394,6 +1394,7 @@ void WINAPI service_main(unsigned long argc, TCHAR **argv) {
     if (services) {\r
       service->handle = open_service(services, service->name, SERVICE_CHANGE_CONFIG, 0, 0);\r
       set_service_recovery(service);\r
+\r
       CloseServiceHandle(services);\r
     }\r
   }\r
@@ -1687,16 +1688,7 @@ int start_service(nssm_service_t *service) {
     but be mindful of the fact that we are blocking the service control manager\r
     so abandon the wait before too much time has elapsed.\r
   */\r
-  unsigned long delay = service->throttle_delay;\r
-  if (delay > NSSM_SERVICE_STATUS_DEADLINE) {\r
-    TCHAR delay_milliseconds[16];\r
-    _sntprintf_s(delay_milliseconds, _countof(delay_milliseconds), _TRUNCATE, _T("%lu"), delay);\r
-    TCHAR deadline_milliseconds[16];\r
-    _sntprintf_s(deadline_milliseconds, _countof(deadline_milliseconds), _TRUNCATE, _T("%lu"), NSSM_SERVICE_STATUS_DEADLINE);\r
-    log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_STARTUP_DELAY_TOO_LONG, service->name, delay_milliseconds, NSSM, deadline_milliseconds, 0);\r
-    delay = NSSM_SERVICE_STATUS_DEADLINE;\r
-  }\r
-  unsigned long deadline = WaitForSingleObject(service->process_handle, delay);\r
+  await_startup(service);\r
 \r
   /* Signal successful start */\r
   service->status.dwCurrentState = SERVICE_RUNNING;\r
@@ -1985,3 +1977,38 @@ awaited:
 \r
   return ret;\r
 }\r
+\r
+int await_startup(nssm_service_t *service) {\r
+  unsigned long interval;\r
+  unsigned long waithint;\r
+  unsigned long waited;\r
+\r
+  waithint = service->status.dwWaitHint;\r
+  waited = 0;\r
+  while (waited < service->throttle_delay) {\r
+    interval = service->throttle_delay - waited;\r
+    if (interval > NSSM_SERVICE_STATUS_DEADLINE) interval = NSSM_SERVICE_STATUS_DEADLINE;\r
+\r
+    service->status.dwCurrentState = SERVICE_START_PENDING;\r
+    service->status.dwWaitHint += interval;\r
+    service->status.dwCheckPoint++;\r
+    SetServiceStatus(service->status_handle, &service->status);\r
+\r
+    switch (WaitForSingleObject(service->process_handle, interval)) {\r
+      case WAIT_OBJECT_0:\r
+        return 1;\r
+\r
+      case WAIT_TIMEOUT:\r
+      break;\r
+\r
+      default:\r
+        return -1;\r
+    }\r
+\r
+    waited += interval;\r
+  }\r
+\r
+  service->throttle = 0;\r
+\r
+  return 0;\r
+}\r
index c5a5d33..4ac3d6f 100644 (file)
--- a/service.h
+++ b/service.h
@@ -146,5 +146,6 @@ int stop_service(nssm_service_t *, unsigned long, bool, bool);
 void CALLBACK end_service(void *, unsigned char);\r
 void throttle_restart(nssm_service_t *);\r
 int await_shutdown(nssm_service_t *, TCHAR *, unsigned long);\r
+int await_startup(nssm_service_t *);\r
 \r
 #endif\r