service->kill_console_delay = NSSM_KILL_CONSOLE_GRACE_PERIOD;\r
service->kill_window_delay = NSSM_KILL_WINDOW_GRACE_PERIOD;\r
service->kill_threads_delay = NSSM_KILL_THREADS_GRACE_PERIOD;\r
+ service->kill_process_tree = 1;\r
}\r
\r
/* Allocate and zero memory for a service. */\r
/* Initialise status */\r
ZeroMemory(&service->status, sizeof(service->status));\r
service->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;\r
- service->status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;\r
+ service->status.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;\r
service->status.dwWin32ExitCode = NO_ERROR;\r
service->status.dwServiceSpecificExitCode = 0;\r
service->status.dwCheckPoint = 0;\r
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
case SERVICE_CONTROL_CONTINUE: return _T("CONTINUE");\r
case SERVICE_CONTROL_INTERROGATE: return _T("INTERROGATE");\r
case NSSM_SERVICE_CONTROL_ROTATE: return _T("ROTATE");\r
+ case SERVICE_CONTROL_POWEREVENT: return _T("POWEREVENT");\r
default: return 0;\r
}\r
}\r
if (service->rotate_stdout_online == NSSM_ROTATE_ONLINE) service->rotate_stdout_online = NSSM_ROTATE_ONLINE_ASAP;\r
if (service->rotate_stderr_online == NSSM_ROTATE_ONLINE) service->rotate_stderr_online = NSSM_ROTATE_ONLINE_ASAP;\r
return NO_ERROR;\r
+\r
+ case SERVICE_CONTROL_POWEREVENT:\r
+ if (event != PBT_APMRESUMEAUTOMATIC) {\r
+ log_service_control(service->name, control, false);\r
+ return NO_ERROR;\r
+ }\r
+ log_service_control(service->name, control, true);\r
+ end_service((void *) service, false);\r
+ return NO_ERROR;\r
}\r
\r
/* Unknown control */\r
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
\r
/* Clean up. */\r
if (exitcode == STILL_ACTIVE) exitcode = 0;\r
- if (service->pid) kill_process_tree(service, service->pid, exitcode, service->pid);\r
+ if (service->pid && service->kill_process_tree) kill_process_tree(service, service->pid, exitcode, service->pid);\r
service->pid = 0;\r
\r
/*\r
\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