Иллюстрированный самоучитель по программированию систем защиты

Сериализация

Синхронизация доступа к разделяемому ресурсу производится с помощью спин-блокировки (механизмы синхронизации будут рассмотрены в следующем разделе). Поскольку операции добавления и удаления записей в очередь на уровнях IRQL PASSIVE_LEVEL и DISPATCH_LEVEL очень распространены, для их безопасного осуществления предусмотрена специальная функция: ExInterlocked…List(). Для использования этой функции должна быть создана и инициализирована спин-блокировка. Создается она обычно там же, где и голова очереди (обычно в DeviceExtension), и инициализируется после инициализации головы очереди. Например:

typedef struct _DEVICE_EXTENSION
LIST__ENTRY ListHead; KSPIN^LOCK ListLock;
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
//В функции DriverEntry
InitializeListHead (& (pDeviceExtension › ListHead));
KelnitializeSpinLock (& (pDeviceExtension › ListLock));
//после этого можно добавлять и удалять записи
PLIST_ENTRY pOldHead = ExInterlockedlnsertHeadList
 (& (pDeviceExtension › ListHead), pNewListEntry, & (pDeviceExte'nsion › ListLock));

Как видно из определения структуры LIST_ENTRY, она не содержит полей для хранения собственно данных (например, указателя на пакет IRP). Поэтому распространенный способ использования структуры LIST_ENTRY – включение ее экземпляра в состав более общей структуры.

Для организации очереди пакетов IRP, в каждом пакете IRP в поле Tail.Over-lay.ListEntry содержится экземпляр структуры LIST_ENTRY. При этом встает вопрос, как, зная указатель на структуру LIST_ENTRY, получить указатель на структуру IRP, в состав которой входит LIST_ENTRY. Для этого DDK предоставляет специальный макрос CONTAINING_RECORD:

#define CONTAINING_RECORD (address, type, field) \
((type *) ((PCHAR) (address) – (ULONG_PTR) (&((type *) 0) › f ield)))

Где:

  • Address – Известный адрес некоторого поля структуры, адрес которой необходимо получить;
  • Type – Тип структуры, адрес которой необходимо получить;
  • Field – Имя поля внутри искомой структуры, адрес этого поля передан в параметре address.

Применительно к IRP, мы должны будем написать что-то вроде:

PListEntry = ExInterlockedRemoveHeadList (& (pDeviceExtension › ListHead),
 & (pDeviceExtension › ListLock));
plrp = CONTAINING_RECORD(pListEntry, IRP, Tail. Overlay. ListEntry); //далее – обработка IRP

Организация очереди пакетов IRP показана на рис. 12.

Иллюстрированный самоучитель по программированию систем защиты › Общая архитектура Windows NT › Сериализация
Рис. 12. Организация очереди пакетов IRP

Функции управления очередью высокого уровня – "Очередь Устройства" (Device Queue)

Драйвер создает дополнительные Очереди Устройства с помощью выделения памяти из невыгружаемой памяти под дополнительные объекты-Очереди Устройства (KDEVICE_QUEUE) и инициализирует эти объекты с помощью функции Kelnitia-HzeDeviceQueue().

Добавление пакетов IRP в эти очереди производится с помощью функции KelnsertDevieeQueue() или KelnsertByKeyDeviceQueue(), а выборка пакетов из очереди – KeRemoveDeviceQueue(), KeRemoveByKeyDeviceQueue() или KeRemoveEntryDeviceQueue().

Для организации очереди пакетов IRP используется структура типа KDEVICE_ QUEUE_ENTRY, указатель на которую содержится в пакете IRP в поле Tail.Overlay.DeviceQueueEntry.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.