Программирование драйверов Windows

Работа с ассоциативными списками


Иногда выделение памяти при помощи системных вызовов, описанных выше, становится неоптимальным. Например, частое выделение и освобождение мелких блоков при помощи системных вызовов оказывается причиной существенного падения быстродействия. Между тем, если известно заранее, что манипуляция будет производиться блоками определенного и постоянного размера, то имеет смысл организовать "локальную кучу", которая управлялась бы более производительными функциями.

Такую возможность предоставляет механизм ассоциативных списков (lookaside list), который реализован в системных вызовах, представленных ниже. Поначалу, ассоциативный список &#8212 это всего лишь заранее созданный заголовок, который должен хранить информацию о состоянии списка, и не содержит никаких выделенных блоков памяти. По мере выполнения вызовов ExAllocateFrom(N)PagedLookasideList

(таблицы 7.9 и 7.10) такие блоки создаются &#8212 либо системным вызовом ExAllocatePoolWithTag, либо внутри предоставленной драйвером функции (указанной драйвером параметром pAllocFunction). По мере создания и, возможно, последующего освобождения выделенных ранее блоков (системным вызовом ExFreePool, либо предоставленной драйвером функцией), ассоциативный список может оказаться держателем некоторого количества блоков фиксированного размера в страничной либо нестраничной памяти (в зависимости от способа инициализации).

Таблица 7.9. Прототип вызова ExInitializePagedLookasideList



PVOID ExInitializePagedLookasideList IRQL &#60 DISPATCH_LEVEL
Параметры Создание ассоциативного списка блоков страничной памяти
IN PPAGED_LOOKASIDE_LIST pLookasideListHeader Указатель на предварительно выделенную драйвером область размером sizeof(PAGED_LOOKASIDE_LIST)
Остальные параметры совпадают с параметрами вызова ExInitializeNPagedLookasideList, см. ниже таблицу 7.10
Возвращаемое значение void

В настоящий момент, Windows XP и Server 2003 самостоятельно и динамически определяет максимальное число элементов в ассоциативном списке.
Для Windows 2000 в качестве такого параметра был анонсирован параметр Depth. (K сожалению, в документации способ определения значения этого параметра умалчивается, начиная с версии DDK Win98.) Следует отметить, что до достижения данного максимума освобождаемые драйвером блоки не возвращаются в системную память, оставаясь в составе списка. Если в списке имеются ранее освобожденные блоки, и поступил запрос на новый блок, то предоставляется указатель на один из них. Ситуация кардинально меняется если максимум достигнут. При запросе нового блока (и при этом ранее освобожденных блоков в списке нет) память под него берется непосредственно из системной памяти и при освобождении сразу же возвращается в соответствующий пул системной памяти &#8212 иными словами, исчезают преимущества использования ассоциативного списка.

Таблица 7.10. Прототип вызова ExInitializeNPagedLookasideList

VOID ExInitializeNPagedLookasideList IRQL &#60= DISPATCH_LEVEL
Параметры Создание ассоциативного списка блоков нестраничной памяти
IN PNPAGED_LOOKASIDE_LIST

pLookasideListHeader
Указатель на предварительно выделенную драйвером область размером sizeof(NPAGED_LOOKASIDE_LIST)
IN OPTIONAL PALLOCATE_FUNCTION

pAllocFunction
NULL или указатель на предоставляемую драйвером функцию, которая будет заниматься выделением блоков из массива системной нестраничной памяти (если NULL &#8212 будет использован системный вызов ExAllocatePoolWithTag)
IN OPTIONAL PFREE_FUNCTION

pFreeFunction
NULL или указатель на предоставляемую драйвером функцию, которая будет заниматься освобождением блоков (если NULL &#8212 будет использован вызов ExFreePool)
IN ULONG Flags Зарезервировано. Указывать 0
IN ULONG ByteSize Размер отдельных блоков, поддерживаемых данным списком
IN ULONG Tag Метка (тег) для создаваемых блоков, можно задавать как 4 символа, например, 'ABCD'
IN USHORT Depth Зарезервировано. Указывать 0
Возвращаемое значение void
Перед вызовом процедуры инициализации, для хранения заголовка ассоциативного списка драйвер должен получить область в нестраничной памяти



размером sizeof(PAGED_LOOKASIDE_LIST) или sizeof(NPAGED_LOOKASIDE_LIST) &#8212 в зависимости от того, какой список инициализируется. Для этих целей можно использовать описанные выше системные вызовы ExAllocatePool

или ExAllocatePoolWithTag. В конце работы со списком обязательно следует выполнить вызов ExDelete(N)PagedLookasideList.

Функции, на которые указывает pAllocFunction, имеют прототип:

PVOID MyAllocateFunction ( IN_POOL_TYPE PoolType, // PagedPool или NonPagedPool IN ULONG NumberOfBytes, // размер IN ULONG Tag // тег );

Функции, на которые указывает pFreeFunction, имеют прототип:

PVOID MyFreeFunction (PVOID pBuffer);

Таблица 7.11. Прототип вызова ExAllocateFromNPagedLookasideList

PVOID ExAllocateFromNPagedLookasideList IRQL &#60= DISPATCH_LEVEL
Параметры Выполняет выделение блока памяти из нестраничного списка
IN PNPAGED_LOOKASIDE_LIST

pLookasideList
Указатель на инициализированный ассоциативный список
Возвращаемое значение Указатель на блок фиксированного размера или NULL (если функция выделения памяти не смогла получить очередной блок)
Таблица 7.12. Прототип вызова ExAllocateFromPagedLookasideList

PVOID ExAllocateFromPagedLookasideList IRQL &#60 DISPATCH_LEVEL
Параметры Выполняет выделение блока памяти из страничного списка
IN PPAGED_LOOKASIDE_LIST

pLookasideList
Указатель на инициализированный ассоциативный список
Возвращаемое значение Указатель на блок фиксированного размера или NULL (если функция выделения памяти не смогла получить очередной блок)
Таблица 7.13. Прототип вызова ExFreeToNPagedLookasideList

VOID ExFreeToNPagedLookasideList IRQL &#60= DISPATCH_LEVEL
Параметры Возвращает блок в нестраничный ассоциативный список
IN PNPAGED_LOOKASIDE_LIST pLookasideList Указатель на инициализированный ассоциативный список
IN PVOID pEntry Указатель на ранее полученный из списка блок фиксированного размера
Возвращаемое значение void
Таблица 7.14. Прототип вызова ExFreeToPagedLookasideList



VOID ExFreeToPagedLookasideList IRQL &#60 DISPATCH_LEVEL
Параметры Возвращает блок в страничный ассоциативный список
IN PPAGED_LOOKASIDE_LIST

pLookasideList
Указатель на инициализированный ассоциативный список
IN PVOID pEntry Указатель на ранее полученный из списка блок фиксированного размера
Возвращаемое значение void
Таблица 7.15. Прототип вызова ExDeleteNPagedLookasideList

VOID ExDeleteNPagedLookasideList IRQL &#60= DISPATCH_LEVEL
Параметры Выполняет удаление нестраничного ассоциативного списка
IN PNPAGED_LOOKASIDE_LIST

pLookasideList
Указатель на ассоциативный список
Возвращаемое значение void
Таблица 7.16. Прототип вызова ExDeletePagedLookasideList

VOID ExDeletePagedLookasideList IRQL &#60 DISPATCH_LEVEL
Параметры Выполняет удаление страничного ассоциативного списка
IN PPAGED_LOOKASIDE_LIST

pLookasideList
Указатель на ассоциативный список
Возвращаемое значение void

Содержание раздела