Необходимо было найти способ реализации DeadlockDetection, который позволил бы выполнить все предыдущие требования. Во-первых, необходимо было определить, какие нужны функции для организации такого управления программой, который дал бы возможность сообщать пользователю полную трассу блокировки. В табл. 12.1 перечислены (и сгруппированы по типам) все функции, которые, по моему мнению, были нужны для организации управления в программе DeadlockDetection.
Обдумывая, как собрать информацию, необходимую для удовлетворения первых четырех требований, я понял, что надо перехватывать (или подключаться по адресу1) функции, указанные в табл 12.1, для того чтобы регистрировать (записывать) получение и освобождение объектов синхронизации. Подключение функций через адрес — нетривиальная задача (реализация соответствующего кода рассмотрена в разделе "Подключение импортированных функций" чуть ниже). Такое подключение накладывает на DeadlockDetection следующее ограничение: ее код должен постоянно храниться в DLL, потому что такие подключения применяются только к адресному пространству, в котором он создан. Это ограничение означает, что пользователь должен загрузить DLL с программой DeadlockDetection в ее адресное пространство. Это требование не слишком жестко по сравнению с получаемыми от него преимуществами. Как и DLL, утилита будет легко объединяться с программой пользователя (см. условие, указанное в п. 7 списка требований предыдущего раздела).
Сбор информации, удовлетворяющей требованиям 1—4, является прямым следствием выбора особого подхода "с подключением функций в процессе выполнения программы" (in-process function hooking approach). Такой подход означает, что каждая многопоточная функция и функция синхронизации будет вызываться прямо в процессе выполнения DeadlockDetection вместе со всей необходимой информацией.
Таблица 12.1. Функции, мониторинг которых осуществляет DeadlockDetection
Тип | Функция |
Функции, относящиеся к потокам |
CreateThread ExitThread SuspendThread ResumeThread TerminateThread |
Функции критической секции |
Initial izeCr it icalSection InitializeCriticalSectionAndSpinCount DeleteCr it icalSection EnterCr it icalSection LeaveCr it icalSection SetCriticalSectionSpinCount TryEnterCriticalSection |
Функции мьютекса |
CreateMutexA CreateMutexW OpenMutexA OpenMutexW ReleaseMutex |