~/home

Snipping Tool висит на курсоре загрузки: виноват переиспользованный PID

· windows, отладка

TL;DR: Если по Win+Shift+S появляется только курсор загрузки, а процессы SnippingTool.exe копятся, помогает taskkill /f /im SnippingTool.exe. Причина в коде AppInstance из Windows App SDK: он считает переиспользованный PID живым и оставляет мьютекс захваченным.

Перестал работать хоткей для скриншотов. Каждое нажатие на секунду показывало курсор загрузки и оставляло ещё один SnippingTool.exe без окна. Когда я наконец заглянул в диспетчер задач, их там висело 19.

Решение

taskkill /f /im SnippingTool.exe

Убивать нужно все. Если по одному, то сначала прибейте ждущие, а потом тот, что держит лок, иначе ждущие проснутся и каждый откроет свой оверлей.

Что происходило

Wait Chain Traversal показал, что каждый новый экземпляр ждёт мьютекс, которым владеет один старый. Остальное прояснилось после чтения AppInstance.cpp в открытом Windows App SDK:

  • Экземпляры регистрируют свои PID в общей секции памяти. При выходе свой PID никто не убирает, мёртвые записи вычищает следующий запуск.
  • Единственная проверка «жив ли процесс» — удался ли OpenProcess(SYNCHRONIZE). Если Windows уже отдала этот PID другому, постороннему процессу, мёртвая запись считается живой.
  • Для каждого PID из списка новый экземпляр создаёт <app>_<pid>_Mutex с начальным владением, рассчитывая, что настоящий владелец создал его раньше. Если PID переиспользован, владельцем становится сам новый экземпляр и держит мьютекс до своего выхода.
  • Отменённый скриншот (Esc) оставляет процесс висеть в памяти. Если именно он держит утёкший лок, все следующие запуски ждут вечно.

У меня PID, который Snipping Tool использовал часом раньше, достался процессу Python. Через несколько часов один отменённый скриншот захватил лок, и хоткей умер.

Что пригодится при таких зависаниях

  • Событие 201 в журнале Microsoft-Windows-AppModel-Runtime/Admin фиксирует каждый запуск. Сравните со временем файлов в Pictures\Screenshots и увидите, какие запуски дали скриншот.
  • cdb -pv -p <pid> -c "!handle 0 f Mutant; qd" из Windows SDK показывает именованные мьютексы без символов и не останавливает процесс.