ExInitializeLookasideListEx 函数 (wdm.h)

ExInitializeLookasideListEx 例程初始化 lookaside 列表。

语法

NTSTATUS ExInitializeLookasideListEx(
  [out]          PLOOKASIDE_LIST_EX    Lookaside,
  [in, optional] PALLOCATE_FUNCTION_EX Allocate,
  [in, optional] PFREE_FUNCTION_EX     Free,
  [in]           POOL_TYPE             PoolType,
  [in]           ULONG                 Flags,
  [in]           SIZE_T                Size,
  [in]           ULONG                 Tag,
  [in]           USHORT                Depth
);

参数

[out] Lookaside

指向要初始化 的LOOKASIDE_LIST_EX 结构的指针。 返回时,此结构描述一个空的旁观列表。 调用方必须为此结构使用非分页系统空间,无论查看列表中的条目是从分页内存还是非分页内存中分配的。 在 64 位平台上,此结构必须对齐 16 字节。

[in, optional] Allocate

指向调用方提供的 LookasideListAllocateEx 例程的指针,该例程分配新的 lookaside-list 条目。 如果 lookaside 列表为空, ExAllocateFromLookasideListEx 例程将调用此 LookasideListAllocateEx 例程 () 不包含任何条目。 此参数是可选的,如果不需要自定义分配例程,则可以将其指定为 NULL 。 如果此参数为 NULL,则调用 ExAllocateFromPagedLookasideList 会自动分配分页或非分页存储 (,由新条目的 PoolType 参数) 确定。

[in, optional] Free

指向调用方提供的 LookasideListFreeEx 例程的指针,该例程释放以前分配的 lookaside-list 条目。 如果 lookaside 列表已满 (,则 ExFreeToPagedLookasideList 例程调用此 LookasideListFreeEx 例程,即列表已包含由操作系统) 确定的最大条目数。 此参数是可选的,如果不需要自定义解除分配例程,则可以将其指定为 NULL 。 如果此参数为 NULL,则调用 ExFreeToPagedLookasideList 会自动释放指定条目的存储。

[in] PoolType

指定 lookaside 列表中条目的池类型。 将此参数设置为有效的 POOL_TYPE 枚举值。

[in] Flags

指定可选标志值以修改 LookasideListAllocateEx 例程的默认行为。 将此参数设置为零或设置为以下EX_LOOKASIDE_LIST_EX_FLAGS_XXX 标志位之一。

标记位 说明
EX_LOOKASIDE_LIST_EX_FLAGS_RAISE_ON_FAIL 如果分配失败,则引发异常。
EX_LOOKASIDE_LIST_EX_FLAGS_FAIL_NO_RAISE 如果分配失败,则返回 NULL ,而不是引发异常。 此标志旨在与分配例程(例如 ExAllocatePoolWithQuotaTag)一起使用,该例程对池使用情况收取配额。

这两个标志位是互斥的。

如果 “分配”NULL,请将 “标志 ”设置为零或EX_LOOKASIDE_LIST_EX_FLAGS_RAISE_ON_FAIL,但不设置为“EX_LOOKASIDE_LIST_EX_FLAGS_FAIL_NO_RAISE”。 否则,默认分配例程的行为未定义。

如果 Flags = EX_LOOKASIDE_LIST_EX_FLAGS_RAISE_ON_FAIL,则 PoolType 参数值为按位 ORed,POOL_RAISE_IF_ALLOCATION_FAILURE标志位以形成传递给 LookasideListAllocateEx 例程的 PoolType 参数值。 LookasideListAllocateEx 例程可以在不进行修改的情况下将此 PoolType 值传递给 ExAllocatePoolWithTag 例程。 有关POOL_RAISE_IF_ALLOCATION_FAILURE标志的详细信息,请参阅 ExAllocatePoolWithTag

如果 Flags = EX_LOOKASIDE_LIST_EX_FLAGS_FAIL_NO_RAISE,则 PoolType 参数值是按位 ORed,具有POOL_QUOTA_FAIL_INSTEAD_OF_RAISE标志位,以形成传递给 LookasideListAllocateEx 例程的 PoolType 参数值。 LookasideListAllocateEx 例程可以在不进行修改的情况下将此 PoolType 值传递给 ExAllocatePoolWithQuotaTag 例程。 有关 POOL_QUOTA_FAIL_INSTEAD_OF_RAISE 标志的详细信息,请参阅 ExAllocatePoolWithQuotaTag

[in] Size

指定 lookaside 列表中每个条目的大小(以字节为单位)。

[in] Tag

指定要用于标记查找列表条目的已分配存储的四字节池标记。 有关池标记的详细信息,请参阅 ExAllocatePoolWithTagTag 参数的说明。

[in] Depth

保留。 始终将此参数设置为零。

返回值

如果调用成功,ExInitializeLookasideListEx 将返回STATUS_SUCCESS。 可能的返回值包括以下错误代码:

返回代码 说明
STATUS_INVALID_PARAMETER_4 PoolType 参数值无效。
STATUS_INVALID_PARAMETER_5 Flags 参数值无效。

注解

驱动程序必须调用此例程来初始化查看列表,然后驱动程序才能开始使用该列表。 旁观列表是一个固定大小的缓冲区池,驱动程序可以在本地管理这些缓冲区,以减少对系统分配例程的调用数,从而提高性能。 缓冲区作为条目存储在 lookaside 列表中。 列表中的所有条目都具有相同的统一大小,由 Size 参数指定。

ExInitializeLookasideListEx 返回后,将初始化 lookaside 列表,但不包含任何条目。 当客户端调用 ExAllocateFromLookasideListEx 例程来请求条目时,此例程确定 lookaside 列表为空,并调用驱动程序提供的 LookasideListAllocateEx 例程来动态分配新条目的存储。 为了响应来自客户端的类似请求,可能会分配其他条目。 稍后,当客户端调用 ExFreeToLookasideListEx 来释放这些条目时,此例程会将条目插入到 lookaside 列表中。 如果列表中的条目数达到操作系统确定的限制, ExFreeToLookasideListEx 将停止向列表中添加更多条目,而是将这些条目传递给驱动程序提供的 LookasideListFreeEx 例程以释放。

如果驱动程序不提供 LookasideListAllocateExLookasideListFreeEx 例程, 则 ExAllocateFromLookasideListExExFreeToLookasideListEx 例程改用默认分配和解除分配例程。

提供 LookasideListAllocateExLookasideListFreeEx 例程除了调用 ExAllocatePoolWithTagExFreePool 之外,没有任何好处。 只需将 “分配 ”和“ 释放 ”参数设置为 NULL 即可实现相同的效果,同时提高性能。

在驱动程序卸载之前,它必须显式释放它创建的任何旁观列表。 否则是严重的编程错误。 调用 ExDeleteLookasideListEx 例程以释放 lookaside 列表。 此例程释放指定 lookaside 列表中任何剩余条目的存储,然后从系统范围的活动查找列表集中删除该列表。

操作系统会跟踪当前正在使用的所有旁观列表。 由于可用非分页内存量和对查找列表条目的需求随时间而变化,操作系统会动态调整每个非分页列表的最大条目数的限制。

在 Windows 2000 及更高版本的 Windows 中,包含分页或非分页条目的查看列表可以分别由 PAGED_LOOKASIDE_LISTNPAGED_LOOKASIDE_LIST 结构描述。

有关 lookaside 列表的详细信息,请参阅 Using Lookaside Lists

ExInitializeLookasideListEx 的调用方可以在 IRQL <= DISPATCH_LEVEL运行,但通常以 IRQL = PASSIVE_LEVEL运行。

示例

驱动程序提供的 LookasideListAllocateExLookasideListFreeEx 例程都接收 Lookaside 参数,这些参数指向描述 lookaside 列表 的LOOKASIDE_LIST_EX 结构。 例程可以使用此参数访问驱动程序与 lookaside 列表关联的私有数据。 例如,驱动程序可能会分配以下结构的实例,以收集其创建的每个旁观列表的私有数据:

typedef struct
{
  ULONG NumberOfAllocations;  // number of entries allocated
  ULONG NumberOfFrees;        // number of entries freed
  LOOKASIDE_LIST_EX LookasideField;
} MY_PRIVATE_DATA;

驱动程序可以初始化 lookaside 列表,如以下代码示例所示:

#define ENTRY_SIZE  256
#define MY_POOL_TAG  'tsLL'      
MY_PRIVATE_DATA *MyContext;
NTSTATUS status = STATUS_SUCCESS;
 
MyContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(MY_PRIVATE_DATA), MY_POOL_TAG);
if (MyContext)
{
    MyContext.NumberOfAllocations = 0;
    MyContext.NumberOfFrees = 0;

    status = ExInitializeLookasideListEx(
                 &MyContext.LookasideField,
                 MyLookasideListAllocateEx,
                 MyLookasideListFreeEx,
                 NonPagedPool,
                 0,
                 ENTRY_SIZE,
                 MY_POOL_TAG,
                 0);
}
else
{
    status = STATUS_INSUFFICIENT_RESOURCES;
}

下面的代码示例演示 LookasideListAllocateEx 例程如何使用其 Lookaside 参数访问与 lookaside 列表关联的私有数据:

PVOID
  MyLookasideListAllocateEx(
    __in POOL_TYPE  PoolType,
    __in SIZE_T  NumberOfBytes,
    __in ULONG  Tag,
    __inout PLOOKASIDE_LIST_EX  Lookaside)
{
    MY_PRIVATE_DATA *MyContext;
    PVOID NewEntry;

    MyContext = CONTAINING_RECORD(Lookaside, MY_PRIVATE_DATA, LookasideField);

    NewEntry = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);

    if (NewEntry)
    {
        ULONG NumberOfAllocations = (ULONG) InterlockedIncrement((LONG volatile*)&MyContext->NumberOfAllocations);
    }

    return NewEntry;
}

CONTAINING_RECORD宏在 Ntdef.h 头文件中定义。 LookAsideListFreeEx 例程同样可以使用其 Lookaside 参数来访问私有数据。

在此示例中的 MyLookasideListAllocateEx 例程返回后, ExAllocateFromLookasideListExNewEntry 变量指向的缓冲区插入到 lookaside 列表中。 为了使此插入操作线程安全, ExAllocateFromLookasideListEx 将其对 lookaside 列表的访问与其他线程可能执行的其他列表插入和删除操作同步。 同样,当 ExFreeFromLookasideListEx 从 lookaside 列表中删除缓冲区时,它会同步其对列表的访问。

ExAllocateFromLookasideListExExFreeFromLookasideListEx 不同步它们对驱动程序提供的 LookasideListAllocateExLookasideListFreeEx 例程的调用。 因此,如果前面的代码示例中的 MyLookasideListAllocateExMyLookasideListFreeEx 例程必须是线程安全的,则驱动程序必须提供必要的同步。

示例例程 MyLookasideListAllocateEx 将其 MyContext-NumberOfAllocations> 变量的访问与其他线程同步,这些线程可能会递增和递减此变量。 为了提供此同步, MyLookasideListAllocateEx 调用 InterlockedIncrement 例程以原子方式递增此变量。 同样, MyLookasideListFreeEx 例程 (未显示) 可以调用 InterlockedDecrement 例程以原子方式递减此变量。

但是,如果前面的代码示例中 MyContext-NumberOfAllocations> 变量的唯一用途只是收集有关 lookaside 列表分配的统计信息,则几乎不需要原子增量和递减。 在这种情况下,不应考虑错过增量或递减的远程可能性。

有关 lookaside 列表的线程安全性的详细信息,请参阅使用 Lookaside Lists

要求

要求
最低受支持的客户端 从 Windows Vista 开始可用。
目标平台 通用
标头 wdm.h(包括 Wdm.h、Ntddk.h、Ntifs.h)
Library NtosKrnl.lib
DLL NtosKrnl.exe
IRQL <= DISPATCH_LEVEL (请参阅备注部分)

另请参阅

ExAllocateFromLookasideListEx

ExAllocatePoolWithQuotaTag

ExAllocatePoolWithTag

ExDeleteLookasideListEx

ExFreePool

ExFreeToLookasideListEx

InterlockedDecrement

InterlockedIncrement

LOOKASIDE_LIST_EX

LookasideListAllocateEx

LookasideListFreeEx

NPAGED_LOOKASIDE_LIST

PAGED_LOOKASIDE_LIST

POOL_TYPE