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 列表条目。 ExFreeToPagedLookasideList 例程调用此 LookasideListFreeEx 例程(即列表已包含由作系统确定的最大条目数)。 此参数为可选参数,如果不需要自定义解除分配例程,则可以指定为 NULL。 如果此参数 NULL,则调用 ExFreeToPagedLookasideList 自动释放指定条目的存储。

[in] PoolType

指定外观列表中的条目的池类型。 将此参数设置为有效的 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。 否则,默认分配例程的行为是未定义的。

如果 标志 = EX_LOOKASIDE_LIST_EX_FLAGS_RAISE_ON_FAIL,则 PoolType 参数值是带POOL_RAISE_IF_ALLOCATION_FAILURE标志位的按位 ORed,以形成传递给 lookasideListAllocateEx 例程的PoolType 参数值。 LookasideListAllocateEx 例程可以将此 PoolType 值(无需修改)传递给 ExAllocatePoolWithTag 例程。 有关POOL_RAISE_IF_ALLOCATION_FAILURE标志的详细信息,请参阅 ExAllocatePoolWithTag

如果 标志 = 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

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

[in] Depth

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

返回值

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

返回代码 描述
STATUS_INVALID_PARAMETER_4 PoolType 参数值无效。
STATUS_INVALID_PARAMETER_5 标志 参数值无效。

言论

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

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

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

提供 lookasideListAllocateExLookasideListFreeEx 例程没有任何好处,这些例程只 调用 exAllocatePoolWithTagExFreePool。 通过将 分配免费 参数设置为 NULL,可以实现相同的效果。

在驱动程序卸载之前,它必须显式释放它创建的任何外观列表。 未能这样做是一个严重的编程错误。 调用 ExDeleteLookasideListEx 例程以释放 lookaside 列表。 此例程释放指定外观列表中所有剩余条目的存储,然后从系统范围内的活动望边列表中删除该列表。

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

在 Windows 2000 及更高版本的 Windows 中,可以分别通过 PAGED_LOOKASIDE_LISTNPAGED_LOOKASIDE_LIST 结构来描述包含分页或非分页条目的望边列表。

有关外观列表的详细信息,请参阅 使用 Lookaside 列表

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

例子

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

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

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

#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 列表

要求

要求 价值
最低支持的客户端 从 Windows Vista 开始可用。
目标平台 普遍
标头 wdm.h (包括 Wdm.h、Ntddk.h、Ntifs.h)
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