Відстеження активності переривань та DPC

Для відстеження активності переривань і DPC можна скористатися засобом ProcessExplorer, відкривши діалогове вікно SystemInformation (Системна інформація) і перейшовши у вкладку CPU (Центральний процесор), де буде показана кількість переривань і DPC-процедур, зафіксована при кожному оновленні засобом Process Explorer. замовчуванням з періодичністю в одну секунду).

Можна також відстежити виконання конкретних процедур обслуговування переривань та відкладених дзвінків процедур, використовуючи вбудоване відстеження подій:

  1. Запустіть перехоплення подій. Відкрийте вікно командного рядка, перейдіть до каталогу Microsoft Windows Performance Toolkit (зазвичай він знаходиться в каталозі c:\Program Files) і наберіть наступну команду1: xperf –on PROC_THREAD+LOADER+DPC+INTERRUPT
  2. Зупиніть перехоплення подій, набравши таку команду: xperf –d dpcisr.etl
  3. Згенеруйте звіти для перехоплення подій, набравши таке: xperf dpcisr.etl tracerpt \kernel.etl – report dpcisr.html – f html В результаті буде згенерована веб-сторінка dpcisr.html.
  4. Відкрийте файл report.html і розкрийте підрозділ DPC/ISR. Розкрийте область DPC/ISR Breakdown і побачите зведення, що показує час, витрачений на ISR-процедури та DPC-дзвінки кожним драйвером. Наприклад, як у малюнку.

lkd> ln 0x806321C7

lkd> ln 0x820AED3F

lkd> ln 0x82051312

Вам буде надано можливість детально розглянути кожні DPC та ISR кожного драйвера, а також побачити тривалість та кількість, як показано на наступному малюнку.

Механізм потокових DPC-дзвінків включений за замовчуванням, але його можна вимкнути шляхом додавання нульового DWORD-значення до параметраHKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\kernel\ThreadDpcEnable. Оскільки потокові DPC-дзвінки можуть бути вимкнені, розробники драйверів, які користуються потоковими DPC-дзвінками, повинні писати свої процедури, дотримуючись тих самих правил, які поширюються на непотокові виклики.

Ці процедури не можуть звертатися до пам'яті, що вивантажується, чекати диспетчеризації або вибудовувати припущення щодо IRQL-рівня, з яким вони виконуються. Крім того, вони не повинні використовувати функції API KeAcquire/ReleaseSpinLockAtDpcLevel, оскільки функції припускають, що центральний процесор має рівень dispatch. Натомість у потокових DPC-дзвінках потрібно використовувати функцію KeAcquire/ReleaseSpinLockForDpc, яка виконує відповідну дію після перевірки поточного IRQL.

Оскільки APC-дзвінки вишиковуються в чергу на виконання в контексті конкретного потоку і запускаються на IRQL-рівні, що нижче рівня DPC/dispatch, вони не підпадають під такі ж обмеження, що накладаються на DPC. APC-процедура може отримувати ресурси (об'єкти), чекати на дескриптори об'єктів, справлятися з помилками відсутності сторінки і викликати системні служби.

APC-дзвінки описуються об'єктом керування ядра, званим APC-об'єктом. APC-дзвінки, які очікують на виконання, поміщаються в керовану ядром APC-чергу. На відміну від черги DPC, яка помітна всій системі, APC-черга відноситься до конкретного потоку - у кожного потоку є своя власна APC-черга. При запиті на розміщення в чергу APC-виклику ядро ​​вставляє її в чергу, що належить тому потоку, який виконуватиме APC-процедуру.

Ядро, у свою чергу, запитує програмне переривання на APC-рівні, а потім, коли потік через деякий час почне працювати, в ньому виконуєтьсяAPC-дзвінок.

Існує два види APC-дзвінків: режиму ядра та режиму користувача. APC-дзвінки режиму ядра не вимагають дозволу від цільового потоку на запуск у його контексті, а APC-дзвінки потоку користувача вимагають такого дозволу. APC-дзвінки режиму ядра переривають потік і виконуються без втручання або дозволу. Є також два види APC-дзвінків режиму ядра: звичайні та спеціальні. Спеціальні APC-дзвінки виконуються на рівні APC і дозволяють APC-процедурі змінювати деякі APC-параметри.

Звичайні APC-дзвінки виконуються на рівні passive та отримують змінені параметри від спеціальної APC-процедури (або вихідні параметри, якщо вони не були змінені).

Звичайні та спеціальні APC-дзвінки можуть бути відключені шляхом підвищення IRQL на APC-рівень або шляхом виклику процедури KeEnterGuardedRegion.

Вона відключає APC-доставку, встановлюючи поле SpecialApcDisable у структурі KTHREAD потоку, що викликає.

Потік може відключити звичайні APC-дзвінки лише шляхом виклику процедури KeEnterCriticalRegion, яка встановлює поле KernelApcDisable у структурі потоку KTHREAD. У таблиці зведено поведінку кожного виду APC-дзвінка за вставкою та доставкою APC.

Вставка та доставка APC.

Підсистеми середовища оточення використовують спеціальні APC-дзвінки режиму ядра, щоб змусити потік призупинити або завершити свою роботу, або отримати або встановити контекст його виконання в режимі користувача. Підсистема UNIX-додатків використовує APC-дзвінки режиму ядра для імітації доставки UNIX-сигналів процесам підсистеми для UNIX-додатків.

Інше важливе застосування APC-дзвінків режиму ядра стосується припинення або завершення потоку. Оскільки ці операції можуть ініціюватися довільними потоками та спрямовані на іншідовільні потоки, ядро ​​використовує APC для запиту контексту потоку, а також завершення потоку.

Драйвери пристроїв часто блокують APC-дзвінки або входять у критичну або охоронювану область, щоб запобігти виконанню цих операцій у той момент, коли вони утримують блокування, інакше блокування може бути ніколи не знято, і система зависне.

APC-дзвінки режиму ядра також використовуються драйверами пристроїв.

Наприклад, якщо ініційована операція введення-виводу та потік перейшов у режим очікування, може бути сплановано запуск іншого потоку в іншому процесі.

APC-дзвінки користувача режиму використовуються декількома Windows API-функціями, такими як ReadFileEx, WriteFileEx і QueueUserAPC. Наприклад, функції ReadFileEx і WriteFileEx дозволяють коду, що викликає, вказати підпрограму завершення, що викликається при закінченні операції введення-виведення.

Завершення введення-виведення реалізується постановкою APC-виклику в чергу потоку, який видав запит на введення-виведення. Але зворотний виклик процедури завершення не обов'язково відбувається при постановці APC-дзвінка в чергу, оскільки APC-дзвінки режиму користувача доставляються потоку тільки в тому випадку, коли він знаходиться в готовності до роботи в режимі очікування.

Потік може увійти в режим очікування або в очікуванні дескриптора об'єкта і позначення, що його очікування ведеться в готовності до роботи (за допомогою Windows-функції WaitForMulti pleObjectsEx) або безпосередньої перевірки на наявність відкладеного APC (за допомогою функції SleepEx). В обох випадках, якщо APC-виклик користувача режиму відкладено, ядро ​​перериває (повідомляє) потік, передаючи управління APC-процедурі, і відновлює виконання потоку, коли APC-процедура завершить свою роботу. На відміну від APC-викликів режиму ядра, які можуть здійснюватися на рівні APC, APC-дзвінки режиму користувача виконуються на рівні passive.

Доставка APC може змінити порядок черг очікування, тобто змінити списки, в яких зазначено, які потоки, що й у якому порядку очікують. Якщо при доставці виклику APC потік перебуває в стані очікування, після завершення APC-процедури очікування повторно виставляється або виконується.

Якщо очікування все ще не дозволено, потік повертається в стан очікування, але тепер він буде наприкінці списку щодо тих об'єктів, які очікуються. Наприклад, оскільки APC-дзвінки використовуються для призупинення виконання потоку, якщо потік чекає на якісь об'єкти, його очікування видаляється до тих пір, поки не відновиться виконання потоку, після чого цей потік буде в кінці списку потоків, які очікують доступу до об'єктів, яких він чекає. Потік, який чекає на готовність до роботи в режимі ядра, буде також збуджений при завершенні своєї роботи. Це дозволить такому потоку перевірити, чи розбуджений він у результаті завершення своєї роботи чи з якоїсь іншої причини.