case SERVICE_CONTROL_STOP:\r
case SERVICE_CONTROL_SHUTDOWN:\r
switch (status) {\r
+ case SERVICE_RUNNING:\r
case SERVICE_STOP_PENDING:\r
return 1;\r
\r
}\r
\r
case SERVICE_CONTROL_INTERROGATE:\r
+ case NSSM_SERVICE_CONTROL_ROTATE:\r
return 0;\r
}\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
int tries = 0;\r
+ unsigned long checkpoint = 0;\r
+ unsigned long waithint = 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
if (! response) return response;\r
if (response > 0 || service_status->dwCurrentState == initial_status) {\r
- if (++tries > 10) return response;\r
+ if (service_status->dwCheckPoint != checkpoint || service_status->dwWaitHint != waithint) tries = 0;\r
+ checkpoint = service_status->dwCheckPoint;\r
+ waithint = service_status->dwWaitHint;\r
+ if (++tries > 10) tries = 10;\r
Sleep(50 * tries);\r
}\r
else return response;\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_POWEREVENT | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;\r
+ service->status.dwControlsAccepted = 0;\r
service->status.dwWin32ExitCode = NO_ERROR;\r
service->status.dwServiceSpecificExitCode = 0;\r
service->status.dwCheckPoint = 0;\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
- if (await_service_status_change(service, SERVICE_START_PENDING, _T("start_service"), service->throttle_delay) == 1) service->throttle = 0;\r
+ service->status.dwCurrentState = SERVICE_START_PENDING;\r
+ service->status.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;\r
+ if (await_single_handle(service->status_handle, &service->status, service->process_handle, service->name, _T("start_service"), service->throttle_delay) == 1) service->throttle = 0;\r
\r
/* Signal successful start */\r
service->status.dwCurrentState = SERVICE_RUNNING;\r
+ service->status.dwControlsAccepted &= ~SERVICE_ACCEPT_PAUSE_CONTINUE;\r
SetServiceStatus(service->status_handle, &service->status);\r
\r
/* Continue waiting for a clean startup. */\r
if (graceful) {\r
service->status.dwCurrentState = SERVICE_STOP_PENDING;\r
service->status.dwWaitHint = NSSM_WAITHINT_MARGIN;\r
- SetServiceStatus(service->status_handle, &service->status);\r
}\r
+ service->status.dwControlsAccepted = 0;\r
+ SetServiceStatus(service->status_handle, &service->status);\r
\r
/* Nothing to do if service isn't running */\r
if (service->pid) {\r
/* Shut down service */\r
log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_TERMINATEPROCESS, service->name, service->exe, 0);\r
- kill_process(service, service->process_handle, service->pid, 0);\r
+ kill_t k;\r
+ service_kill_t(service, &k);\r
+ k.exitcode = 0;\r
+ kill_process(&k);\r
}\r
else log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_PROCESS_ALREADY_STOPPED, service->name, service->exe, 0);\r
\r
\r
/* Clean up. */\r
if (exitcode == STILL_ACTIVE) exitcode = 0;\r
- if (service->pid && service->kill_process_tree) kill_process_tree(service, service->pid, exitcode, service->pid);\r
+ if (service->pid && service->kill_process_tree) {\r
+ kill_t k;\r
+ service_kill_t(service, &k);\r
+ kill_process_tree(&k, service->pid);\r
+ }\r
service->pid = 0;\r
\r
/*\r
}\r
\r
service->status.dwCurrentState = SERVICE_PAUSED;\r
+ service->status.dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;\r
SetServiceStatus(service->status_handle, &service->status);\r
\r
if (use_critical_section) {\r
\r
Only doing both these things will prevent the system from killing the service.\r
\r
+ If the status_handle and service_status arguments are omitted, this function\r
+ will not try to update the service manager but it will still log to the\r
+ event log that it is waiting for a handle.\r
+\r
Returns: 1 if the wait timed out.\r
0 if the wait completed.\r
-1 on error.\r
*/\r
-int await_service_status_change(nssm_service_t *service, unsigned long status, unsigned long desired, TCHAR *function_name, unsigned long timeout) {\r
+int await_single_handle(SERVICE_STATUS_HANDLE status_handle, SERVICE_STATUS *status, HANDLE handle, TCHAR *name, TCHAR *function_name, unsigned long timeout) {\r
unsigned long interval;\r
- unsigned long waithint;\r
unsigned long ret;\r
unsigned long waited;\r
TCHAR interval_milliseconds[16];\r
\r
_sntprintf_s(timeout_milliseconds, _countof(timeout_milliseconds), _TRUNCATE, _T("%lu"), timeout);\r
\r
- waithint = service->status.dwWaitHint;\r
waited = 0;\r
while (waited < timeout) {\r
interval = timeout - waited;\r
if (interval > NSSM_SERVICE_STATUS_DEADLINE) interval = NSSM_SERVICE_STATUS_DEADLINE;\r
\r
- service->status.dwCurrentState = control;\r
- service->status.dwWaitHint += interval;\r
- service->status.dwCheckPoint++;\r
- SetServiceStatus(service->status_handle, &service->status);\r
+ if (status) {\r
+ status->dwWaitHint += interval;\r
+ status->dwCheckPoint++;\r
+ SetServiceStatus(status_handle, status);\r
+ }\r
\r
if (waited) {\r
_sntprintf_s(waited_milliseconds, _countof(waited_milliseconds), _TRUNCATE, _T("%lu"), waited);\r
_sntprintf_s(interval_milliseconds, _countof(interval_milliseconds), _TRUNCATE, _T("%lu"), interval);\r
- log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_AWAITING_SERVICE, function, service->name, waited_milliseconds, interval_milliseconds, timeout_milliseconds, service_status_text(status), 0);\r
+ log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_AWAITING_SINGLE_HANDLE, function, name, waited_milliseconds, interval_milliseconds, timeout_milliseconds, 0);\r
}\r
\r
- switch (WaitForSingleObject(service->process_handle, interval)) {\r
+ switch (WaitForSingleObject(handle, interval)) {\r
case WAIT_OBJECT_0:\r
ret = 0;\r
goto awaited;\r