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
指定要用于标记查找列表条目的已分配存储的四字节池标记。 有关池标记的详细信息,请参阅 ExAllocatePoolWithTag 中 Tag 参数的说明。
[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 例程以释放。
如果驱动程序不提供 LookasideListAllocateEx 和 LookasideListFreeEx 例程, 则 ExAllocateFromLookasideListEx 和 ExFreeToLookasideListEx 例程改用默认分配和解除分配例程。
提供 LookasideListAllocateEx 和 LookasideListFreeEx 例程除了调用 ExAllocatePoolWithTag 和 ExFreePool 之外,没有任何好处。 只需将 “分配 ”和“ 释放 ”参数设置为 NULL 即可实现相同的效果,同时提高性能。
在驱动程序卸载之前,它必须显式释放它创建的任何旁观列表。 否则是严重的编程错误。 调用 ExDeleteLookasideListEx 例程以释放 lookaside 列表。 此例程释放指定 lookaside 列表中任何剩余条目的存储,然后从系统范围的活动查找列表集中删除该列表。
操作系统会跟踪当前正在使用的所有旁观列表。 由于可用非分页内存量和对查找列表条目的需求随时间而变化,操作系统会动态调整每个非分页列表的最大条目数的限制。
在 Windows 2000 及更高版本的 Windows 中,包含分页或非分页条目的查看列表可以分别由 PAGED_LOOKASIDE_LIST 或 NPAGED_LOOKASIDE_LIST 结构描述。
有关 lookaside 列表的详细信息,请参阅 Using Lookaside Lists。
ExInitializeLookasideListEx 的调用方可以在 IRQL <= DISPATCH_LEVEL运行,但通常以 IRQL = PASSIVE_LEVEL运行。
示例
驱动程序提供的 LookasideListAllocateEx 和 LookasideListFreeEx 例程都接收 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 例程返回后, ExAllocateFromLookasideListEx 将 NewEntry 变量指向的缓冲区插入到 lookaside 列表中。 为了使此插入操作线程安全, ExAllocateFromLookasideListEx 将其对 lookaside 列表的访问与其他线程可能执行的其他列表插入和删除操作同步。 同样,当 ExFreeFromLookasideListEx 从 lookaside 列表中删除缓冲区时,它会同步其对列表的访问。
ExAllocateFromLookasideListEx 和 ExFreeFromLookasideListEx 不同步它们对驱动程序提供的 LookasideListAllocateEx 和 LookasideListFreeEx 例程的调用。 因此,如果前面的代码示例中的 MyLookasideListAllocateEx 和 MyLookasideListFreeEx 例程必须是线程安全的,则驱动程序必须提供必要的同步。
示例例程 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 (请参阅备注部分) |