Função ExInitializeLookasideListEx (wdm.h)
A rotina ExInitializeLookasideListEx inicializa uma lista lookaside.
Sintaxe
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
);
Parâmetros
[out] Lookaside
Um ponteiro para a estrutura LOOKASIDE_LIST_EX a ser inicializada. No retorno, essa estrutura descreve uma lista lookaside vazia. O chamador deve usar espaço do sistema nãopagado para essa estrutura, independentemente de as entradas na lista lookaside serem alocadas de memória paginada ou não. Em plataformas de 64 bits, essa estrutura deve estar alinhada a 16 bytes.
[in, optional] Allocate
Um ponteiro para uma rotina LookasideListAllocateEx fornecida pelo chamador que aloca uma nova entrada lookaside-list. A rotina ExAllocateFromLookasideListEx chama essa rotina LookasideListAllocateEx se a lista lookaside estiver vazia (não contém entradas). Esse parâmetro é opcional e pode ser especificado como NULL se uma rotina de alocação personalizada não for necessária. Se esse parâmetro for NULL, as chamadas para ExAllocateFromPagedLookasideList alocarão automaticamente o armazenamento paginado ou nãopagado (conforme determinado pelo parâmetro PoolType ) para as novas entradas.
[in, optional] Free
Um ponteiro para uma rotina LookasideListFreeEx fornecida pelo chamador que libera uma entrada lookaside-list alocada anteriormente. A rotina ExFreeToPagedLookasideList chama essa rotina LookasideListFreeEx se a lista lookaside estiver completa (ou seja, a lista já contém o número máximo de entradas, conforme determinado pelo sistema operacional). Esse parâmetro é opcional e pode ser especificado como NULL se uma rotina de desalocação personalizada não for necessária. Se esse parâmetro for NULL, as chamadas para ExFreeToPagedLookasideList liberarão automaticamente o armazenamento para as entradas especificadas.
[in] PoolType
Especifica o tipo de pool das entradas na lista lookaside. Defina esse parâmetro como um valor de enumeração de POOL_TYPE válido.
[in] Flags
Especifica um valor de sinalizador opcional para modificar o comportamento padrão da rotina LookasideListAllocateEx . Defina esse parâmetro como zero ou como um dos seguintes bits de sinalizador EX_LOOKASIDE_LIST_EX_FLAGS_XXX .
Bit de sinalizador | Descrição |
---|---|
EX_LOOKASIDE_LIST_EX_FLAGS_RAISE_ON_FAIL | Se a alocação falhar, gere uma exceção. |
EX_LOOKASIDE_LIST_EX_FLAGS_FAIL_NO_RAISE | Se a alocação falhar, retorne NULL em vez de gerar uma exceção. Esse sinalizador destina-se a ser usado com uma rotina de alocação, como ExAllocatePoolWithQuotaTag, que cobra cotas para uso do pool. |
Esses dois bits de sinalizador são mutuamente exclusivos.
Se Allocate for NULL, defina Sinalizadores como zero ou EX_LOOKASIDE_LIST_EX_FLAGS_RAISE_ON_FAIL, mas não para EX_LOOKASIDE_LIST_EX_FLAGS_FAIL_NO_RAISE. Caso contrário, o comportamento da rotina de alocação padrão é indefinido.
Se Flags = EX_LOOKASIDE_LIST_EX_FLAGS_RAISE_ON_FAIL, o valor do parâmetro PoolType será ORed bit a bit com o bit de sinalizador POOL_RAISE_IF_ALLOCATION_FAILURE para formar o valor do parâmetro PoolType que é passado para a rotina LookasideListAllocateEx . A rotina LookasideListAllocateEx pode passar esse valor PoolType , sem modificação, para a rotina ExAllocatePoolWithTag . Para obter mais informações sobre o sinalizador POOL_RAISE_IF_ALLOCATION_FAILURE, consulte ExAllocatePoolWithTag.
Se Flags = EX_LOOKASIDE_LIST_EX_FLAGS_FAIL_NO_RAISE, o valor do parâmetro PoolType será ORed bit a bit com o bit de sinalizador POOL_QUOTA_FAIL_INSTEAD_OF_RAISE para formar o valor do parâmetro PoolType que é passado para a rotina LookasideListAllocateEx . A rotina LookasideListAllocateEx pode passar esse valor PoolType , sem modificação, para a rotina ExAllocatePoolWithQuotaTag . Para obter mais informações sobre o sinalizador POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, consulte ExAllocatePoolWithQuotaTag.
[in] Size
Especifica o tamanho, em bytes, de cada entrada na lista lookaside.
[in] Tag
Especifica a marca de pool de quatro bytes a ser usada para marcar o armazenamento alocado para entradas lookaside-list. Para obter mais informações sobre marcas de pool, consulte a descrição do parâmetro Tag em ExAllocatePoolWithTag.
[in] Depth
Reservado. Sempre defina esse parâmetro como zero.
Retornar valor
ExInitializeLookasideListEx retornará STATUS_SUCCESS se a chamada for bem-sucedida. Os possíveis valores retornados incluem o seguinte código de erro:
Código de retorno | Descrição |
---|---|
STATUS_INVALID_PARAMETER_4 | O valor do parâmetro PoolType não é válido. |
STATUS_INVALID_PARAMETER_5 | O valor do parâmetro Flags não é válido. |
Comentários
Um driver deve chamar essa rotina para inicializar uma lista lookaside antes que o driver possa começar a usar a lista. Uma lista lookaside é um pool de buffers de tamanho fixo que o driver pode gerenciar localmente para reduzir o número de chamadas para rotinas de alocação do sistema e, assim, melhorar o desempenho. Os buffers são armazenados como entradas na lista lookaside. Todas as entradas na lista são do mesmo tamanho uniforme, que é especificado pelo parâmetro Size .
Depois que ExInitializeLookasideListEx retorna, a lista lookaside é inicializada, mas não contém entradas. Quando um cliente chama a rotina ExAllocateFromLookasideListEx para solicitar uma entrada, essa rotina determina que a lista lookaside está vazia e chama a rotina LookasideListAllocateEx fornecida pelo driver para alocar dinamicamente o armazenamento para uma nova entrada. Entradas adicionais podem ser alocadas em resposta a solicitações semelhantes de clientes. Posteriormente, quando os clientes chamam o ExFreeToLookasideListEx para liberar essas entradas, essa rotina insere as entradas na lista lookaside. Se o número de entradas na lista atingir um limite determinado pelo sistema operacional, ExFreeToLookasideListEx deixará de adicionar entradas adicionais à lista e, em vez disso, passará essas entradas para a rotina LookasideListFreeEx fornecida pelo driver a ser liberada.
Se o driver não fornecer rotinas LookasideListAllocateEx e LookasideListFreeEx , as rotinas ExAllocateFromLookasideListEx e ExFreeToLookasideListEx usarão rotinas padrão de alocação e desalocação.
Não há nenhum benefício em fornecer rotinas LookasideListAllocateEx e LookasideListFreeEx que não fazem nada além de chamar ExAllocatePoolWithTag e ExFreePool. O mesmo efeito pode ser obtido com melhor desempenho simplesmente definindo os parâmetros Allocate e Free como NULL.
Antes que um driver descarregue, ele deve liberar explicitamente todas as listas lookaside criadas. Falha ao fazer isso é um grave erro de programação. Chame a rotina ExDeleteLookasideListEx para liberar uma lista lookaside. Essa rotina libera o armazenamento de todas as entradas restantes na lista lookaside especificada e, em seguida, remove a lista do conjunto de listas lookaside ativas em todo o sistema.
O sistema operacional controla todas as listas lookaside que estão em uso no momento. Como a quantidade de memória nãopagada disponível e a demanda por entradas de lista lookaside variam ao longo do tempo, o sistema operacional ajusta dinamicamente seus limites para o número máximo de entradas em cada lista lookaside nãopagada.
No Windows 2000 e versões posteriores do Windows, uma lista lookaside que contém entradas paginadas ou não pagas pode ser descrita por uma estrutura PAGED_LOOKASIDE_LIST ou NPAGED_LOOKASIDE_LIST , respectivamente.
Para obter mais informações sobre listas lookaside, consulte Using Lookaside Listas.
Os chamadores de ExInitializeLookasideListEx podem estar em execução em IRQL <= DISPATCH_LEVEL, mas normalmente são executados em IRQL = PASSIVE_LEVEL.
Exemplos
As rotinas LookasideListAllocateEx e LookasideListFreeEx fornecidas pelo driver recebem parâmetros Lookaside que apontam para a estrutura LOOKASIDE_LIST_EX que descreve a lista lookaside. As rotinas podem usar esse parâmetro para acessar dados privados que o driver associou à lista lookaside. Por exemplo, o driver pode alocar uma instância da seguinte estrutura para coletar dados privados para cada lista lookaside que ele cria:
typedef struct
{
ULONG NumberOfAllocations; // number of entries allocated
ULONG NumberOfFrees; // number of entries freed
LOOKASIDE_LIST_EX LookasideField;
} MY_PRIVATE_DATA;
O driver pode inicializar uma lista lookaside, conforme mostrado no exemplo de código a seguir:
#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;
}
O exemplo de código a seguir mostra como a rotina LookasideListAllocateEx pode usar seu parâmetro Lookaside para acessar os dados privados associados à lista 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;
}
A macro CONTAINING_RECORD é definida no arquivo de cabeçalho Ntdef.h. A rotina LookAsideListFreeEx pode usar de forma semelhante seu parâmetro Lookaside para acessar dados privados.
Depois que a rotina MyLookasideListAllocateEx neste exemplo retorna, ExAllocateFromLookasideListEx insere o buffer apontado pela variável NewEntry na lista lookaside. Para tornar essa operação de inserção thread-safe, ExAllocateFromLookasideListEx sincroniza seu acesso à lista lookaside com outras operações de inserção e remoção de lista que podem ser executadas por outros threads. Da mesma forma, quando ExFreeFromLookasideListEx remove um buffer da lista lookaside, ele sincroniza seu acesso à lista.
ExAllocateFromLookasideListEx e ExFreeFromLookasideListEx não sincronizam suas chamadas para as rotinas LookasideListAllocateEx e LookasideListFreeEx fornecidas pelo driver. Portanto, se as rotinas MyLookasideListAllocateEx e MyLookasideListFreeEx nos exemplos de código anteriores precisarem ser thread-safe, o driver deverá fornecer a sincronização necessária.
A rotina de exemplo, MyLookasideListAllocateEx, sincroniza seu acesso da variável MyContext-NumberOfAllocations> com outros threads que podem incrementar e diminuir essa variável. Para fornecer essa sincronização, MyLookasideListAllocateEx chama a rotina InterlockedIncrement para incrementar atomicamente essa variável. Da mesma forma, a rotina MyLookasideListFreeEx (não mostrada) pode chamar a rotina InterlockedDecrement para diminuir atomicamente essa variável.
No entanto, se a única finalidade da variável MyContext-NumberOfAllocations> no exemplo de código anterior for simplesmente coletar estatísticas sobre alocações de lista lookaside, incrementos atômicos e decrementos dificilmente serão necessários. Nesse caso, a possibilidade remota de um incremento ou decremento perdido não deve ser uma preocupação.
Para obter mais informações sobre a segurança de threads para listas lookaside, consulte Using Lookaside Listas.
Requisitos
Requisito | Valor |
---|---|
Cliente mínimo com suporte | Disponível a partir do Windows Vista. |
Plataforma de Destino | Universal |
Cabeçalho | wdm.h (include Wdm.h, Ntddk.h, Ntifs.h) |
Biblioteca | NtosKrnl.lib |
DLL | NtosKrnl.exe |
IRQL | <= DISPATCH_LEVEL (consulte a seção Comentários) |