2013-12-07 2 views
1

Я наткнулся серьезной проблема в моей/сервисной программе клиента, которая работает следующим образом:SetServiceStatus устанавливает SERVICE_STOPPED, но QueryServiceStatusEx возвращает SERVICE_STOP_PENDING

  • Клиентское приложение использует ControlService(... SERVICE_CONTROL_STOP ...), чтобы остановить службу.
  • Пока служба останавливается, приложение периодически вызывает QueryServiceStatusEx, чтобы проверить, dwCurrentState is SERVICE_STOPPED. Он также проверяет dwWaitHint на время ожидания.

Тем временем служба делает это:

  • Перед чисткой вверх, он вызывает SetServiceStatus с dwCurrentState = SERVICE_STOP_PENDING и dwWaitHint = 3000.
  • После очистки, он вызывает SetServiceStatus с dwCurrentState = SERVICE_STOPPED и dwWaitHint = 0.

После воспроизведения и протоколирование вопрос, который я придумал это:

Все работает, как и ожидалось кроме в последний раз, когда клиент вызывает QueryServiceStatusEx, который возвращает dwCurrentState = SERVICE_STOP_PENDING и dwWaitHint = 0! Это приводит к тому, что он ведет себя так, как будто время ожидания операции.

Я не знаю, как это может произойти, я четко вижу в журналах, что служба устанавливает dwCurrentState = SERVICE_STOPPED перед выходом.

Это известная проблема? У вас есть какая-то подсказка, что может произойти здесь?

Update:

Вот логи клиентского приложения:

24437 ssStatus.dwWaitHint: 3000, ssStatus.dwCurrentState: 3 
24546 ssStatus.dwWaitHint: 0, ssStatus.dwCurrentState: 3 
24609 ssStatus.dwWaitHint: 0, ssStatus.dwCurrentState: 3 
... 
26000 ssStatus.dwWaitHint: 0, ssStatus.dwCurrentState: 3 
26062 ssStatus.dwWaitHint: 0, ssStatus.dwCurrentState: 3 
26218 Stopped 

Как вы можете видеть, служба остановленные между 24437 и 24546 (GetTickCount), и это состояние было изменено на 26218. Это означает, что он был помечен как SERVICE_STOP_PENDING за дополнительные 1,672 секунды. Может быть, Windows изменяет состояние? Почему он был помечен так долго?

Update 2:

Больше наблюдения:

  • вызова SetServiceStatus влияет на все, кроме dwCurrentState, которая остается в SERVICE_STOP_PENDING до тех пор, как процесс обслуживания работает. Это особенность Windows? Документировано?
  • Мой сервисный процесс остается висящим более чем на одну секунду после возвращения с LPSERVICE_MAIN_FUNCTION и перед возвратом с StartServiceCtrlDispatcher. Почему это происходит? (P.S. это происходит при загрузке Windows).
  • Попытка написать исполняемый файл службы иногда возвращает ERROR_SHARING_VIOLATION, хотя это состояние SERVICE_STOPPED. Есть ли надежный способ убедиться, что процесс полностью завершен?

Может кто-нибудь объяснить это? Раймонд Чен?

Update 3:

Более интересная информация: QueryServiceStatusEx возвращает dwWaitHint: 0, dwCurrentState: 3, dwCheckPoint: 0, даже если я никогда не ставил dwWaitHint и dwCheckPoint к нулю! Что тут происходит?

+0

Ну, вы ничего не можете с этим поделать, чтобы просто решить проблему. dwWaitHint не имеет смысла для остановленного состояния, поэтому просто не меняйте его. –

+0

Это то, что MS делает в своем [пример] (http://msdn.microsoft.com/en-us/library/windows/desktop/bb540475%28v=vs.85%29.aspx) («ReportSvcStatus (SERVICE_STOPPED, NO_ERROR, 0); "), и мое приложение основано на нем, следовательно, поведение. Я сделал несколько дополнительных протоколов и обновил вопрос. – Paul

+0

Я подозреваю, что ваша служба выполняет некоторую работу между настройкой статуса на SERVICE_STOPPED и выходом ServiceMain. Возможно, у вас есть куча состояния, внедренного в локальную переменную в вашей функции ServiceMain, поэтому она очищается в деструкторе, когда функция, по-видимому, завершена? – arx

ответ

1

Я создал простую службу и попробовал запросить состояние службы из самой службы, чтобы запросы были синхронизированы с изменениями состояния.

SCM попросил службу остановиться. Запрошенное состояние было SERVICE_RUNNING. Служба установила состояние SERVICE_STOPPED, запросила его снова и получила SERVICE_STOP_PENDING (с ожиданием ожидания 0). Наконец, служба запросила состояние после возврата StartServiceCtrlDispatcher и получила SERVICE_STOPPED.

Это не совсем согласовано; Есть два возможных результата для трех запросов:

SERVICE_RUNNING, SERVICE_STOP_PENDING и SERVICE_STOPPED или

SERVICE_RUNNING, SERVICE_STOPPED и SERVICE_STOPPED.

Я вижу то же самое с инструментом командной строки sc. Если я попрошу его прекратить мое обслуживание, он иногда сообщает о состоянии как остановленном и иногда сообщает об этом как ожидающем, даже несмотря на то, что мое обслуживание никогда не заставляет его ждать.

Существует короткое окно SERVICE_STOP_PENDING сразу после того, как служба устанавливает состояние SERVICE_STOPPED, но до того, как Windows вернет управление потоку диспетчера (основного). Если машина загружается и, таким образом, занята, это окно SERVICE_STOP_PENDING может быть довольно длинным.

Поведение воспроизводимо и кажется преднамеренным. Но, как вы говорите, он нигде не документируется.

+0

Благодарим вас за анализ. Я думаю, лучшее решение здесь должно быть защитным - я больше не считаю 'dwWaitHint' значением тайм-аута, только как подсказку с задержкой. Это отстой, что я должен найти эти нюансы сложным способом. Я имею в виду, что мой код был основан на примерах из MSDN. Где я должен ожидать получить правильные фрагменты, если не MSDN? – Paul

Смежные вопросы