+ unsigned long exitcode = 0;\r
+ TCHAR code[16];\r
+ if (service->process_handle) {\r
+ GetExitCodeProcess(service->process_handle, &exitcode);\r
+ if (exitcode == STILL_ACTIVE || get_process_exit_time(service->process_handle, &service->exit_time)) GetSystemTimeAsFileTime(&service->exit_time);\r
+ CloseHandle(service->process_handle);\r
+ }\r
+ else GetSystemTimeAsFileTime(&service->exit_time);\r
+\r
+ service->process_handle = 0;\r
+\r
+ /*\r
+ Log that the service ended BEFORE logging about killing the process\r
+ tree. See below for the possible values of the why argument.\r
+ */\r
+ if (! why) {\r
+ _sntprintf_s(code, _countof(code), _TRUNCATE, _T("%lu"), exitcode);\r
+ log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ENDED_SERVICE, service->exe, service->name, code, 0);\r
+ }\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
+ service->pid = 0;\r
+\r
+ /*\r
+ The why argument is true if our wait timed out or false otherwise.\r
+ Our wait is infinite so why will never be true when called by the system.\r
+ If it is indeed true, assume we were called from stop_service() because\r
+ this is a controlled shutdown, and don't take any restart action.\r
+ */\r
+ if (why) return;\r
+ if (! service->allow_restart) return;\r
+\r
+ /* What action should we take? */\r
+ int action = NSSM_EXIT_RESTART;\r
+ TCHAR action_string[ACTION_LEN];\r
+ bool default_action;\r
+ if (! get_exit_action(service->name, &exitcode, action_string, &default_action)) {\r
+ for (int i = 0; exit_action_strings[i]; i++) {\r
+ if (! _tcsnicmp((const TCHAR *) action_string, exit_action_strings[i], ACTION_LEN)) {\r
+ action = i;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ switch (action) {\r
+ /* Try to restart the service or return failure code to service manager */\r
+ case NSSM_EXIT_RESTART:\r
+ log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_EXIT_RESTART, service->name, code, exit_action_strings[action], service->exe, 0);\r
+ while (monitor_service(service)) {\r
+ log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_RESTART_SERVICE_FAILED, service->exe, service->name, 0);\r
+ Sleep(30000);\r
+ }\r
+ break;\r
+\r
+ /* Do nothing, just like srvany would */\r
+ case NSSM_EXIT_IGNORE:\r
+ log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_EXIT_IGNORE, service->name, code, exit_action_strings[action], service->exe, 0);\r
+ Sleep(INFINITE);\r
+ break;\r
+\r
+ /* Tell the service manager we are finished */\r
+ case NSSM_EXIT_REALLY:\r
+ log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_EXIT_REALLY, service->name, code, exit_action_strings[action], 0);\r
+ stop_service(service, exitcode, true, default_action);\r
+ break;\r
+\r
+ /* Fake a crash so pre-Vista service managers will run recovery actions. */\r
+ case NSSM_EXIT_UNCLEAN:\r
+ log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_EXIT_UNCLEAN, service->name, code, exit_action_strings[action], 0);\r
+ stop_service(service, exitcode, false, default_action);\r
+ free_imports();\r
+ exit(exitcode);\r
+ break;\r
+ }\r
+}\r
+\r
+void throttle_restart(nssm_service_t *service) {\r
+ /* This can't be a restart if the service is already running. */\r
+ if (! service->throttle++) return;\r
+\r
+ int ms = throttle_milliseconds(service->throttle);\r
+\r
+ if (service->throttle > 7) service->throttle = 8;\r