X-Git-Url: http://git.iain.cx/?a=blobdiff_plain;f=service.cpp;h=5a286417526cd80167cde4499bbfb58c9c29e4f1;hb=2dbaf62e06018a7d0a934c79bd9f39b81dc43694;hp=406196b41a16c6590b7558fb5d2fa6a4412db660;hpb=f13f3f81d7ad3ccda728d06f615ce5f724023f4e;p=nssm.git diff --git a/service.cpp b/service.cpp index 406196b..5a28641 100644 --- a/service.cpp +++ b/service.cpp @@ -38,6 +38,7 @@ static inline int service_control_response(unsigned long control, unsigned long case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: switch (status) { + case SERVICE_RUNNING: case SERVICE_STOP_PENDING: return 1; @@ -73,6 +74,7 @@ static inline int service_control_response(unsigned long control, unsigned long } case SERVICE_CONTROL_INTERROGATE: + case NSSM_SERVICE_CONTROL_ROTATE: return 0; } @@ -81,12 +83,17 @@ static inline int service_control_response(unsigned long control, unsigned long static inline int await_service_control_response(unsigned long control, SC_HANDLE service_handle, SERVICE_STATUS *service_status, unsigned long initial_status) { int tries = 0; + unsigned long checkpoint = 0; + unsigned long waithint = 0; while (QueryServiceStatus(service_handle, service_status)) { int response = service_control_response(control, service_status->dwCurrentState); /* Alas we can't WaitForSingleObject() on an SC_HANDLE. */ if (! response) return response; if (response > 0 || service_status->dwCurrentState == initial_status) { - if (++tries > 10) return response; + if (service_status->dwCheckPoint != checkpoint || service_status->dwWaitHint != waithint) tries = 0; + checkpoint = service_status->dwCheckPoint; + waithint = service_status->dwWaitHint; + if (++tries > 10) tries = 10; Sleep(50 * tries); } else return response; @@ -1363,7 +1370,7 @@ void WINAPI service_main(unsigned long argc, TCHAR **argv) { /* Initialise status */ ZeroMemory(&service->status, sizeof(service->status)); service->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; - service->status.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; + service->status.dwControlsAccepted = 0; service->status.dwWin32ExitCode = NO_ERROR; service->status.dwServiceSpecificExitCode = 0; service->status.dwCheckPoint = 0; @@ -1688,10 +1695,13 @@ int start_service(nssm_service_t *service) { but be mindful of the fact that we are blocking the service control manager so abandon the wait before too much time has elapsed. */ - if (await_service_status_change(service, SERVICE_START_PENDING, _T("start_service"), service->throttle_delay) == 1) service->throttle = 0; + service->status.dwCurrentState = SERVICE_START_PENDING; + service->status.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; + if (await_single_handle(service->status_handle, &service->status, service->process_handle, service->name, _T("start_service"), service->throttle_delay) == 1) service->throttle = 0; /* Signal successful start */ service->status.dwCurrentState = SERVICE_RUNNING; + service->status.dwControlsAccepted &= ~SERVICE_ACCEPT_PAUSE_CONTINUE; SetServiceStatus(service->status_handle, &service->status); /* Continue waiting for a clean startup. */ @@ -1727,14 +1737,18 @@ int stop_service(nssm_service_t *service, unsigned long exitcode, bool graceful, if (graceful) { service->status.dwCurrentState = SERVICE_STOP_PENDING; service->status.dwWaitHint = NSSM_WAITHINT_MARGIN; - SetServiceStatus(service->status_handle, &service->status); } + service->status.dwControlsAccepted = 0; + SetServiceStatus(service->status_handle, &service->status); /* Nothing to do if service isn't running */ if (service->pid) { /* Shut down service */ log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_TERMINATEPROCESS, service->name, service->exe, 0); - kill_process(service, service->process_handle, service->pid, 0); + kill_t k; + service_kill_t(service, &k); + k.exitcode = 0; + kill_process(&k); } else log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_PROCESS_ALREADY_STOPPED, service->name, service->exe, 0); @@ -1793,7 +1807,11 @@ void CALLBACK end_service(void *arg, unsigned char why) { /* Clean up. */ if (exitcode == STILL_ACTIVE) exitcode = 0; - if (service->pid && service->kill_process_tree) kill_process_tree(service, service->pid, exitcode, service->pid); + if (service->pid && service->kill_process_tree) { + kill_t k; + service_kill_t(service, &k); + kill_process_tree(&k, service->pid); + } service->pid = 0; /* @@ -1879,6 +1897,7 @@ void throttle_restart(nssm_service_t *service) { } service->status.dwCurrentState = SERVICE_PAUSED; + service->status.dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE; SetServiceStatus(service->status_handle, &service->status); if (use_critical_section) { @@ -1915,13 +1934,16 @@ void throttle_restart(nssm_service_t *service) { Only doing both these things will prevent the system from killing the service. + If the status_handle and service_status arguments are omitted, this function + will not try to update the service manager but it will still log to the + event log that it is waiting for a handle. + Returns: 1 if the wait timed out. 0 if the wait completed. -1 on error. */ -int await_service_status_change(nssm_service_t *service, unsigned long status, unsigned long desired, TCHAR *function_name, unsigned long timeout) { +int await_single_handle(SERVICE_STATUS_HANDLE status_handle, SERVICE_STATUS *status, HANDLE handle, TCHAR *name, TCHAR *function_name, unsigned long timeout) { unsigned long interval; - unsigned long waithint; unsigned long ret; unsigned long waited; TCHAR interval_milliseconds[16]; @@ -1938,24 +1960,24 @@ int await_service_status_change(nssm_service_t *service, unsigned long status, u _sntprintf_s(timeout_milliseconds, _countof(timeout_milliseconds), _TRUNCATE, _T("%lu"), timeout); - waithint = service->status.dwWaitHint; waited = 0; while (waited < timeout) { interval = timeout - waited; if (interval > NSSM_SERVICE_STATUS_DEADLINE) interval = NSSM_SERVICE_STATUS_DEADLINE; - service->status.dwCurrentState = control; - service->status.dwWaitHint += interval; - service->status.dwCheckPoint++; - SetServiceStatus(service->status_handle, &service->status); + if (status) { + status->dwWaitHint += interval; + status->dwCheckPoint++; + SetServiceStatus(status_handle, status); + } if (waited) { _sntprintf_s(waited_milliseconds, _countof(waited_milliseconds), _TRUNCATE, _T("%lu"), waited); _sntprintf_s(interval_milliseconds, _countof(interval_milliseconds), _TRUNCATE, _T("%lu"), interval); - log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_AWAITING_SERVICE, function, service->name, waited_milliseconds, interval_milliseconds, timeout_milliseconds, service_status_text(status), 0); + log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_AWAITING_SINGLE_HANDLE, function, name, waited_milliseconds, interval_milliseconds, timeout_milliseconds, 0); } - switch (WaitForSingleObject(service->process_handle, interval)) { + switch (WaitForSingleObject(handle, interval)) { case WAIT_OBJECT_0: ret = 0; goto awaited;