bool allow_restart;\r
unsigned long throttle_delay;\r
unsigned long stop_method;\r
+CRITICAL_SECTION throttle_section;\r
+CONDITION_VARIABLE throttle_condition;\r
HANDLE throttle_timer;\r
LARGE_INTEGER throttle_duetime;\r
+bool use_critical_section;\r
FILETIME creation_time;\r
\r
+extern imports_t imports;\r
+\r
static enum { NSSM_EXIT_RESTART, NSSM_EXIT_IGNORE, NSSM_EXIT_REALLY, NSSM_EXIT_UNCLEAN } exit_actions;\r
static const char *exit_action_strings[] = { "Restart", "Ignore", "Exit", "Suicide", 0 };\r
\r
return;\r
}\r
\r
+ /* We can use a condition variable in a critical section on Vista or later. */\r
+ if (imports.SleepConditionVariableCS && imports.WakeConditionVariable) use_critical_section = true;\r
+ else use_critical_section = false;\r
+\r
/* Initialise status */\r
ZeroMemory(&service_status, sizeof(service_status));\r
service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;\r
}\r
\r
/* Used for signalling a resume if the service pauses when throttled. */\r
- throttle_timer = CreateWaitableTimer(0, 1, 0);\r
- if (! throttle_timer) {\r
- log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_CREATEWAITABLETIMER_FAILED, service_name, error_string(GetLastError()), 0);\r
+ if (use_critical_section) InitializeCriticalSection(&throttle_section);\r
+ else {\r
+ throttle_timer = CreateWaitableTimer(0, 1, 0);\r
+ if (! throttle_timer) {\r
+ log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_CREATEWAITABLETIMER_FAILED, service_name, error_string(GetLastError()), 0);\r
+ }\r
}\r
\r
monitor_service();\r
\r
case SERVICE_CONTROL_CONTINUE:\r
log_service_control(service_name, control, true);\r
- if (! throttle_timer) return ERROR_CALL_NOT_IMPLEMENTED;\r
throttle = 0;\r
- ZeroMemory(&throttle_duetime, sizeof(throttle_duetime));\r
- SetWaitableTimer(throttle_timer, &throttle_duetime, 0, 0, 0, 0);\r
+ if (use_critical_section) imports.WakeConditionVariable(&throttle_condition);\r
+ else {\r
+ if (! throttle_timer) return ERROR_CALL_NOT_IMPLEMENTED;\r
+ ZeroMemory(&throttle_duetime, sizeof(throttle_duetime));\r
+ SetWaitableTimer(throttle_timer, &throttle_duetime, 0, 0, 0, 0);\r
+ }\r
service_status.dwCurrentState = SERVICE_CONTINUE_PENDING;\r
service_status.dwWaitHint = throttle_milliseconds() + NSSM_WAITHINT_MARGIN;\r
log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_RESET_THROTTLE, service_name, 0);\r
_snprintf_s(milliseconds, sizeof(milliseconds), _TRUNCATE, "%d", ms);\r
log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_THROTTLED, service_name, threshold, milliseconds, 0);\r
\r
- if (throttle_timer) {\r
+ if (use_critical_section) EnterCriticalSection(&throttle_section);\r
+ else if (throttle_timer) {\r
ZeroMemory(&throttle_duetime, sizeof(throttle_duetime));\r
throttle_duetime.QuadPart = 0 - (ms * 10000LL);\r
SetWaitableTimer(throttle_timer, &throttle_duetime, 0, 0, 0, 0);\r
service_status.dwCurrentState = SERVICE_PAUSED;\r
SetServiceStatus(service_handle, &service_status);\r
\r
- if (throttle_timer) WaitForSingleObject(throttle_timer, INFINITE);\r
- else Sleep(ms);\r
+ if (use_critical_section) {\r
+ imports.SleepConditionVariableCS(&throttle_condition, &throttle_section, ms);\r
+ LeaveCriticalSection(&throttle_section);\r
+ }\r
+ else {\r
+ if (throttle_timer) WaitForSingleObject(throttle_timer, INFINITE);\r
+ else Sleep(ms);\r
+ }\r
}\r