Поделиться через


Использование списков Lookaside

Драйверы, которые должны динамически выделять буферы фиксированного размера для выполнения операций ввода-вывода по запросу, могут использовать подпрограммы поддержки ExXxxLookasideListEx или ExXxxLookasideList . После инициализации такого драйвера список lookaside операционная система будет содержать некоторое количество динамически выделенных буферов заданного размера в списке внешнего вида драйвера, эффективно резервируя набор повторно используемых буферов фиксированного размера для драйвера. Формат и содержимое буферов фиксированного размера драйвера (также известных как записи) в списке lookaside определяются драйвером.

Например, драйверы классов хранилища, которые должны настроить блоки запросов SCSI (SRBS) для базовых драйверов портов SCSI или минипорта, используют списки lookaside. Такой драйвер класса выделяет буферы для SRB по мере необходимости из списка lookaside и освобождает каждый буфер SRB обратно в список lookaside для списка lookaside для повторного использования при возврате драйвера класса в завершенном IRP. Так как драйвер класса хранилища не может заранее определить, сколько ему необходимо использовать в любое время, так как спрос на ввод-вывод в драйвере увеличивается и падает, список lookaside является удобным и экономичным способом управления выделением и размещением буферов для фиксированных размеров SRBS в таком драйвере.

Операционная система поддерживает состояние всех страничных и непагированных списков lookaside, которые в настоящее время используются, динамически отслеживая спрос на выделение и распределение записей во всех списках и доступный системный пул для новых записей. Когда спрос на выделение высок, операционная система увеличивает количество записей, которые он содержит в каждом списке lookaside. Когда спрос снова падает, он освобождает избыточные записи lookaside обратно в системный пул.

Списки Lookaside являются потокобезопасными. Список lookaside имеет встроенную синхронизацию для включения нескольких параллельных потоков в драйвере для совместного использования списка lookaside. Эти потоки могут безопасно выделить буферы из общего списка lookaside и освободить эти буферы в список без необходимости явно синхронизировать эти операции драйвером. Однако, чтобы избежать возможных утечек и повреждения данных, набор потоков, совместно использующих список lookaside, должен явно синхронизировать инициализацию и удаление списка.

Интерфейсы списков Lookaside

Начиная с Windows Vista , структура LOOKASIDE_LIST_EX описывает список lookaside, который может содержать страницы или непаганные буферы. Если драйвер предоставляет пользовательские подпрограммы "Выделить " и "Бесплатный " для этого списка lookaside, эти подпрограммы получают закрытый контекст в качестве входного параметра. Драйвер может использовать этот контекст для сбора частных данных для списка lookaside. Например, контекст может использоваться для подсчета количества записей списка, динамически выделенных и освобожденных списком. Пример кода, демонстрирующий использование контекста таким образом, см. в разделе ExInitializeLookasideListEx.

Следующие системные подпрограммы поддерживают списки lookaside, описанные структурой LOOKASIDE_LIST_EX :

ExAllocateFromLookasideListEx

ExDeleteLookasideListEx

ExFlushLookasideListEx

ExFreeToLookasideListEx

ExInitializeLookasideListEx

Начиная с Windows 2000 структура PAGED_LOOKASIDE_LIST описывает список lookaside, содержащий страничные буферы. Если драйвер предоставляет пользовательские подпрограммы "Выделить " и "Бесплатный " для этого списка lookaside, эти подпрограммы не получают закрытый контекст в качестве входного параметра. По этой причине, если драйвер предназначен для запуска только в Windows Vista и более поздних версиях Windows, рекомендуется использовать структуру LOOKASIDE_LIST_EX вместо структуры PAGED_LOOKASIDE_LIST для списков lookaside. Следующие системные подпрограммы поддерживают списки lookaside, описываемые структурой PAGED_LOOKASIDE_LIST :

ExAllocateFromPagedLookasideList

ExDeletePagedLookasideList

ExFreeToPagedLookasideList

ExInitializePagedLookasideList

Начиная с Windows 2000, структура NPAGED_LOOKASIDE_LIST описывает список lookaside, содержащий непагаченные буферы. Если драйвер предоставляет пользовательские подпрограммы "Выделить " и "Бесплатный " для этого списка lookaside, эти подпрограммы не получают закрытый контекст в качестве входного параметра. Опять же, если драйвер предназначен для запуска только в Windows Vista и более поздних версиях Windows, рассмотрите возможность использования LOOKASIDE_LIST_EX структуры вместо структуры NPAGED_LOOKASIDE_LIST для списков lookaside. Следующие системные подпрограммы поддерживают списки lookaside, описываемые структурой NPAGED_LOOKASIDE_LIST :

ExAllocateFromNPagedLookasideList

ExDeleteNPagedLookasideList

ExFreeToNPagedLookasideList

ExInitializeNPagedLookasideList

Руководство по применению

Чтобы реализовать список lookaside, использующий структуру LOOKASIDE_LIST_EX , выполните следующие рекомендации по проектированию:

  • Вызовите ExInitializeLookasideListEx , чтобы настроить список lookaside. В этом вызове укажите, должны ли записи в списке lookaside отображаться на страницах или непагрегированных буферах. Используйте непагированные буферы, если драйвер или любой базовый драйвер, в который он передает свои записи списка lookaside, может получить доступ к этим записям в IRQL >= DISPATCH_LEVEL. Используйте буферы страниц только в том случае, если доступ к записям списка lookaside драйвера всегда выполняется в IRQL <= APC_LEVEL.

  • Структура LOOKASIDE_LIST_EX для списка lookaside всегда должна находиться в неупакованной системной памяти независимо от того, страницы или не страницы записей в списке.

  • Для повышения производительности передайте указатели NULL для параметров "Выделить" и "Бесплатный" в ExInitializeLookasideListEx, если только подпрограммы выделения и распределения сделки не должны выполнять больше, чем просто выделить и освободить память для записей списка lookaside. Например, эти подпрограммы могут записывать сведения об использовании динамически выделенных буферов драйвера.

  • Предоставленный драйвером подпрограмма "Выделить" может передавать входные параметры (PoolType, Tag и Size), которые он получает непосредственно в подпрограмму ExAllocatePoolWithTag или ExAllocatePoolWiolWithQuotaTag для выделения нового буфера.

  • Для каждого вызова ExAllocateFromLookasideListEx сделайте обратный вызов ExFreeToLookasideListEx как можно скорее, когда ранее выделенная запись больше не используется.

Предоставление подпрограмм "Выделение" и "Бесплатный", которые не делают больше, чем вызов ExAllocatePoolWithTag и ExFreePool соответственно, циклы процессора отходов. ExAllocateFromLookasideListEx делает необходимые вызовы ExAllocatePoolWithTag и ExFreePool автоматически, когда драйвер передает null Allocate и Free указатели на ExInitializeLookasideListEx.

Любая подпрограмма, предоставляемая драйвером, не должна выделять память для записи из страничного пула, которая будет храниться в непагированном списке lookaside или наоборот. Он также должен выделять записи фиксированного размера, так как любой последующий вызов драйвера к ExAllocateFromLookasideListEx возвращает первую запись, которая в настоящее время хранится в списке lookaside, если список не пуст. То есть вызов exAllocateFromLookasideListEx вызывает вызов предоставленной драйвером подпрограммы "Выделить ", только если заданный список lookaside в настоящее время пуст. Таким образом, при каждом вызове ExAllocateFromLookasideListEx возвращенная запись будет именно размер, который требуется драйверу, только если все записи в списке lookaside имеют фиксированный размер. Предоставленный драйвером подпрограмма "Выделение " также не должна изменять значение тега , которое драйвер первоначально передал в ExInitializeLookasideListEx, так как изменения в значении тега пула будут более сложными для отладки и отслеживания использования памяти драйвера.

Вызовы к хранилищу ExFreeToLookasideListEx, ранее выделенные записи в списке lookaside, если список еще не заполнен (т. е. список содержит определяемое системой максимальное количество записей). Для повышения производительности драйвер должен сделать обратный вызов ExFreeToLookasideListEx , как можно быстрее, как это может для каждого вызова, который он делает для ExAllocateFromLookasideListEx. Когда драйвер освобождает записи обратно в список lookaside быстро, этот драйвер следующий вызов ExAllocateFromLookasideListEx гораздо менее вероятно, что производительность динамического выделения памяти для новой записи.

Аналогичные рекомендации применяются к списку lookaside, использующему PAGED_LOOKASIDE_LIST или структуру NPAGED_LOOKASIDE_LIST .