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