return ret * 1000;\r
 }\r
 \r
+/*\r
+  Wrapper to be called in a new thread so that we can acknowledge a STOP\r
+  control immediately.\r
+*/\r
+static unsigned long WINAPI shutdown_service(void *arg) {\r
+  return stop_service(0, true, true);\r
+}\r
+\r
 /* Connect to the service manager */\r
 SC_HANDLE open_service_manager() {\r
   SC_HANDLE ret = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);\r
     case SERVICE_CONTROL_SHUTDOWN:\r
     case SERVICE_CONTROL_STOP:\r
       log_service_control(service_name, control, true);\r
-      stop_service(0, true, true);\r
+      /*\r
+        We MUST acknowledge the stop request promptly but we're committed to\r
+        waiting for the application to exit.  Spawn a new thread to wait\r
+        while we acknowledge the request.\r
+      */\r
+      if (! CreateThread(NULL, 0, shutdown_service, (void *) service_name, 0, NULL)) {\r
+        log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATETHREAD_FAILED, error_string(GetLastError()), 0);\r
+\r
+        /*\r
+          We couldn't create a thread to tidy up so we'll have to force the tidyup\r
+          to complete in time in this thread.\r
+        */\r
+        kill_console_delay = NSSM_KILL_CONSOLE_GRACE_PERIOD;\r
+        kill_window_delay = NSSM_KILL_WINDOW_GRACE_PERIOD;\r
+        kill_threads_delay = NSSM_KILL_THREADS_GRACE_PERIOD;\r
+\r
+        stop_service(0, true, true);\r
+      }\r
       return NO_ERROR;\r
 \r
     case SERVICE_CONTROL_CONTINUE:\r
   if (graceful) {\r
     service_status.dwCurrentState = SERVICE_STOP_PENDING;\r
     service_status.dwWaitHint = NSSM_WAITHINT_MARGIN;\r
-    if (stop_method & NSSM_STOP_METHOD_CONSOLE && imports.AttachConsole) service_status.dwWaitHint += kill_console_delay;\r
-    if (stop_method & NSSM_STOP_METHOD_WINDOW) service_status.dwWaitHint += kill_window_delay;\r
-    if (stop_method & NSSM_STOP_METHOD_THREADS) service_status.dwWaitHint += kill_threads_delay;\r
     SetServiceStatus(service_handle, &service_status);\r
   }\r
 \r