Respect throttle time when trying to start a service.
authorIain Patterson <me@iain.cx>
Tue, 2 Aug 2016 10:32:05 +0000 (11:32 +0100)
committerIain Patterson <me@iain.cx>
Tue, 2 Aug 2016 10:32:05 +0000 (11:32 +0100)
If we manage the service, retrieve the AppThrottle milliseconds value
and return if the start control doesn't return in that time.

This prevents hanging waiting for a service which fails to start.

service.cpp

index c9f4700..336cf27 100644 (file)
@@ -83,10 +83,11 @@ static inline int service_control_response(unsigned long control, unsigned long
   return 0;\r
 }\r
 \r
-static inline int await_service_control_response(unsigned long control, SC_HANDLE service_handle, SERVICE_STATUS *service_status, unsigned long initial_status) {\r
+static inline int await_service_control_response(unsigned long control, SC_HANDLE service_handle, SERVICE_STATUS *service_status, unsigned long initial_status, unsigned long cutoff) {\r
   int tries = 0;\r
   unsigned long checkpoint = 0;\r
   unsigned long waithint = 0;\r
+  unsigned long waited = 0;\r
   while (QueryServiceStatus(service_handle, service_status)) {\r
     int response = service_control_response(control, service_status->dwCurrentState);\r
     /* Alas we can't WaitForSingleObject() on an SC_HANDLE. */\r
@@ -96,13 +97,22 @@ static inline int await_service_control_response(unsigned long control, SC_HANDL
       checkpoint = service_status->dwCheckPoint;\r
       waithint = service_status->dwWaitHint;\r
       if (++tries > 10) tries = 10;\r
-      Sleep(50 * tries);\r
+      unsigned long wait = 50 * tries;\r
+      if (cutoff) {\r
+        if (waited > cutoff) return response;\r
+        waited += wait;\r
+      }\r
+      Sleep(wait);\r
     }\r
     else return response;\r
   }\r
   return -1;\r
 }\r
 \r
+static inline int await_service_control_response(unsigned long control, SC_HANDLE service_handle, SERVICE_STATUS *service_status, unsigned long initial_status) {\r
+  return await_service_control_response(control, service_handle, service_status, initial_status, 0);\r
+}\r
+\r
 static inline void wait_for_hooks(nssm_service_t *service, bool notify) {\r
   SERVICE_STATUS_HANDLE status_handle;\r
   SERVICE_STATUS *status;\r
@@ -1407,7 +1417,16 @@ int control_service(unsigned long control, int argc, TCHAR **argv) {
     }\r
 \r
     if (ret) {\r
-      int response = await_service_control_response(control, service_handle, &service_status, initial_status);\r
+      unsigned long cutoff = 0;\r
+\r
+      /* If we manage the service, respect the throttle time. */\r
+      HKEY key = open_registry(service_name, 0, KEY_READ, false);\r
+      if (key) {\r
+        if (get_number(key, NSSM_REG_THROTTLE, &cutoff, false) != 1) cutoff = NSSM_RESET_THROTTLE_RESTART;\r
+        RegCloseKey(key);\r
+      }\r
+\r
+      int response = await_service_control_response(control, service_handle, &service_status, initial_status, cutoff);\r
       CloseServiceHandle(service_handle);\r
 \r
       if (response) {\r