Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
199
Добавлен:
20.02.2016
Размер:
110.59 Кб
Скачать

[10.2.2.2.1] Функции управления очередью низкого уровня

Для организации очереди с помощью функций низкого уровня используется стандартная структура LIST_ENTRY.

typedef struct _LIST_ENTRY {

struct _LIST_ENTRY *volatile Flink; // Указатель на следующий элемент списка

struct _LIST_ENTRY *volatile Blink; // Указатель на предыдущий элемент списка

} LIST_ENTRY, *PLIST_ENTRY;

Очередь, как это видно из определения структуры, двунаправленная.

В структуре DeviceExtension обычно создается экземпляр структурыLIST_ENTRY, представляющей голову очереди, который затем инициализируется с помощью функции InitializeListHead(). После этого можно добавлять или удалять записи в очередь. Для этого используются функции InsertHeadList(), InsertTailList(), RemoveHeadList(), RemoveTailList(), RemoveEntryList().

Пакеты IRP добавляются в очередь в диспетчерской функции, скорее всего работающей на уровне IRQL = PASSIVE_LEVEL. При этом выниматься из очереди они могут функциями, работающими на любом уровне IRQL, причем функции, выбирающие IRP из очереди, могут вытеснять функции, помещающие IRPв очередь. Возникает проблема синхронизации. Если ее не решить, незаконченная операция помещения IRP в очередь может быть прервана операцией выборки IRPиз очереди, что приведет к появлению синего экрана.

Синхронизация доступа к разделяемому ресурсу производится с помощью спин-блокировки (механизмы синхронизации будут рассмотрены на следующей лекции). Поскольку операции добавления и удаления записей в очередь на уровнях 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));

KeInitializeSpinLock(&(pDeviceExtension->ListLock));

//после этого можно добавлять и удалять записи

PLIST_ENTRY pOldHead = ExInterlockedInsertHeadList(

&(pDeviceExtension->ListHead),

pNewListEntry,

&(pDeviceExtension->ListLock));

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

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

#define CONTAINING_RECORD (address,type,field) \

((type *)((PCHAR)(address) – (ULONG_PTR)(&((type *)0)->field)))

address: Известный адрес некоторого поля структуры, адрес которой необходимо получить.

type: Тип структуры, адрес которой необходимо получить.

field: Имя поля внутри искомой структуры, адрес этого поля передан в параметре address.

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

PListEntry = ExInterlockedRemoveHeadList(

&(pDeviceExtension->ListHead),

&(pDeviceExtension->ListLock));

pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);

//далее – обработка IRP

Организация очереди пакетов IRP показана на следующем рисунке.

Рис. 1

Соседние файлы в папке Лабы по драйверам