Поиск идей, отлаживающих запутанный запуск сервисов Windows

В последние несколько месяцев я получил несколько отчетов от QA о том, что один из наших сервисов висит. Изучив вешалку с помощью WinDbg, каждый раз, когда я обнаружил одно и то же: критический раздел блокировки загрузчика заблокирован, но нигде нигде не найти нить. Поскольку поток пропал, и единственная трассировка, которую я вижу, - это глобальный критический раздел, который он оставил позади, я не вижу, какой код работал в потоке нити или даже с какой DLL-линией, из которой произошел поток, он может даже не быть одним из наш (т.е. сторонний поставщик).

Эта проблема очень спорадическая, ее видели только 3-4 раза за последние 6 месяцев, которые происходят естественным образом в дикой природе. Все остальные времена, обслуживание работает отлично. Поэтому это заставляет меня поверить в то, что это какое-то время/состояние гонки.

Недавно я решил взять это на себя, чтобы понять это. Я настраиваю машину с помощью WinTask script, которая постоянно запускает/останавливает указанную службу. Хорошая новость заключается в том, что в течение 5-6 часов я могу воспроизвести проблему.

Теперь для следующей части: как ее изолировать?

Это то, что я пробовал до сих пор:

  • используется поле "отладчик" в настройках изображения gflags для автоматического запуска службы в режиме cdb при каждом запуске. До сих пор это работало в течение двух дней и никогда не висело, поэтому я думаю, что отладчик представил достаточно временного изменения, чтобы сделать проблему невидимой.

  • Загрузите Application Verifier и настройте процесс для этого. Найден абсолютно несвязанный баг, в котором мы создаем временную переменную CComBSTR, присваиваем ее VARIANT и передаем вариант в вызов функции, хотя CComBSTR долго удалял выделенную строку этой точкой. Не верьте, что эта ошибка связана с тем, что строка доступна только для чтения, а поток, на котором работает, не умирает.

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

Я, хотя была утилита Windows, которая искусственно загружала процессор и делала другие вещи, чтобы создать условия гонки, и я думал, что верификатор приложения сделал такую ​​вещь, но, по-видимому, это не так. Кто-нибудь знает, что я принимаю, или мне просто снилось это?

Если в выходные дни ничего не произойдет, моим следующим шагом будет отключить все отладчики, вернуться к запасу и взломать один из DllMains для записи событий THREAD_ATTACH/THREAD_DETACH. По крайней мере, я смогу перехватить поток, который умирает, когда он будет создан. Это может пролить свет.

Ответ 1

Что-то, что я мог бы попробовать, это добавить отладчик ядра, а затем запустить процесс под Verilation Verifier. У AV есть проверки на выгрузку DLL, когда он содержит CS и завершает потоки, которые все еще содержат CS. Таким образом, эти точки останова должны запускаться в отладчике ядра, и, надеюсь, вы можете поймать его в действии. Запуск его под KD, надеюсь, не замедлит его, как это делает отладчик пользовательского режима.

Ответ 2

Итак, оказывается, я был ближе к решению, чем понял. С сервисом, работающим под cdb, который изменил время и затем выполнил его с помощью верификатора приложения, что еще больше изменило сроки (сбрасывание страницы позволяет сделать распределение медленнее), секретный компонент, который я отсутствовал, был prim95.exe. Запустив prim95.exe с нормальным приоритетом, действительно напутал все время, которое я пытался не менять, но это заставило проблему появиться через 15 минут.

Причина:

Сторонний SDK для получения данных с аппаратных плат. Когда наша служба запускается, мы будем запрашивать различные компоненты захвата для своих возможностей. После того, как запрос будет выполнен, мы освободим экземпляр компонента. По-видимому, эта DLL запустила отдельный поток, который приобрел блокировку загрузчика, а затем продолжил выполнять кучу инициализации в этом потоке. Если за это время наш запрос возможностей был выполнен, и мы выпустили компонент, их код вызовет TerminateThread() на этом другом потоке, оставив блокировку блокировки навсегда заблокированной. Prime95 замедлил все, что было достаточно для меня, чтобы поймать это состояние гонки и получить следующее сообщение остановки остановки:

=======================================
VERIFIER STOP 00000200: pid 0x1A8C: Thread cannot own a critical section. 

0000091C : Thread ID.
77E17340 : Critical section address.
00000000 : Critical section debug information address.
00000000 : Critical section initialization stack trace.

Забавная часть заключается в том, что этот поток "исчезал" без каких-либо исключений, поэтому отладчик даже не поймал бы первую возможность. Кто использует TerminateThread????

Спасибо, всем за предложения и поддержку. Я действительно начинал с нетерпением ждать вождения в Radioshack во время обеда, чтобы купить серийный кабель, а затем потратить несколько дней на игру с KD. Похоже, что придется ждать до следующего раза:)

Ответ 3

Некоторые случайные идеи: если привязка отладчика не помогает, то следующий шаг - инструментарий (ваша последняя точка). Но как нить просто умереть, не сводя на нет весь процесс, вы где-нибудь ловите исключения? Возможно, вы захотите также зарегистрироваться там. Вы также можете установить WinDbg для разблокировки всех исключений первого раза, если это помогает. Окно вывода WinDbg в любом случае покажет исключительные исключения, даже если вы не сломаетесь.

Ответ 4

Я бы попробовал неинвазивный отладчик и посмотрел, как это происходит, пока вы не сможете остановить процесс, вы должны иметь возможность видеть любые сообщения отладки, а также любые потоки, которые запускаются и останавливаются, и он должен иметь минимальное влияние на производительность процесса. Я обычно использую windbg для моей отладки, но я думаю, что у cbd есть аналогичные варианты. Это, скорее всего, позволит вам увидеть, что происходит в процессе, и, по крайней мере, начать помогать сузить его. Одна вещь, которую вы, возможно, захотите сделать, это перенаправить вывод (.logopen в windbg), чтобы убедиться, что ничего не выходит за пределы вашего буфера.