Usando listas lookaside

Os drivers que devem alocar buffers de tamanho fixo dinamicamente para executar operações de E/S sob demanda podem usar as rotinas de suporte ExXxxLookasideListEx ou ExXxxLookasideList . Depois que esse driver inicializar sua lista lookaside, o sistema operacional conterá alguns buffers alocados dinamicamente do tamanho especificado na lista lookaside do driver, reservando efetivamente um conjunto de buffers reutilizáveis de tamanho fixo para o driver. O formato e o conteúdo dos buffers de tamanho fixo de um driver (também conhecidos como entradas) em sua lista lookaside são determinados pelo driver.

Por exemplo, os drivers de classe de armazenamento que devem configurar os SRBs (blocos de solicitação SCSI) para os drivers de porta/miniport scsi subjacentes usam listas lookaside. Esse driver de classe aloca buffers para SRBs conforme necessário de sua lista lookaside e libera cada buffer SRB de volta para a lista lookaside para que a lista lookaside seja reutilizado sempre que um SRB é retornado ao driver de classe em um IRP concluído. Como um driver de classe de armazenamento não pode predeterminar quantas SRBs ele precisa usar a qualquer momento porque a demanda de E/S no driver aumenta e cai, uma lista lookaside é uma maneira conveniente e econômica de gerenciar a alocação e a desalocação de buffers para SRBs de tamanho fixo em tal driver.

O sistema operacional mantém o estado sobre todas as listas lookaside paginadas e nãopagadas que estão sendo usadas no momento, acompanhando dinamicamente a demanda por alocações e desalocações de entradas em todas as listas e o pool de sistemas disponível para novas entradas. Quando a demanda por alocações é alta, o sistema operacional aumenta o número de entradas que contém em cada lista lookaside. Quando a demanda cai novamente, ela libera as entradas lookaside excedentes de volta ao pool do sistema.

As listas lookaside são thread-safe. Uma lista lookaside tem sincronização interna para habilitar vários threads em execução simultânea em um driver para compartilhar uma lista lookaside. Esses threads podem alocar buffers com segurança da lista lookaside compartilhada e liberar esses buffers para a lista sem exigir que o driver sincronize explicitamente essas operações. No entanto, para evitar possíveis vazamentos e corrupção de dados, um conjunto de threads que compartilham uma lista lookaside deve sincronizar explictly a inicialização e a exclusão da lista.

Interfaces de lista lookaside

A partir do Windows Vista, a estrutura LOOKASIDE_LIST_EX descreve uma lista lookaside que pode conter buffers paginados ou nãopagados. Se um driver fornecer rotinas personalizadas alocar e gratuitamente para essa lista lookaside, essas rotinas receberão um contexto privado como um parâmetro de entrada. Um driver pode usar esse contexto para coletar dados privados para a lista lookaside. Por exemplo, o contexto pode ser usado para contar o número de entradas de lista que são alocadas dinamicamente e liberadas pela lista. Para obter um exemplo de código que mostra como usar um contexto dessa maneira, consulte ExInitializeLookasideListEx.

As seguintes rotinas fornecidas pelo sistema dão suporte a listas lookaside descritas por uma estrutura LOOKASIDE_LIST_EX :

ExAllocateFromLookasideListEx

ExDeleteLookasideListEx

ExFlushLookasideListEx

ExFreeToLookasideListEx

ExInitializeLookasideListEx

A partir do Windows 2000, a estrutura PAGED_LOOKASIDE_LIST descreve uma lista lookaside que contém buffers paginado. Se um driver fornecer rotinas personalizadas alocar e gratuitamente para essa lista lookaside, essas rotinas não receberão um contexto privado como um parâmetro de entrada. Por esse motivo, se o driver se destina a ser executado somente no Windows Vista e em versões posteriores do Windows, considere usar a estrutura LOOKASIDE_LIST_EX em vez da estrutura PAGED_LOOKASIDE_LIST para suas listas lookaside. As seguintes rotinas fornecidas pelo sistema dão suporte a listas lookaside descritas por uma estrutura PAGED_LOOKASIDE_LIST :

ExAllocateFromPagedLookasideList

ExDeletePagedLookasideList

ExFreeToPagedLookasideList

ExInitializePagedLookasideList

A partir do Windows 2000, a estrutura NPAGED_LOOKASIDE_LIST descreve uma lista lookaside que contém buffers nãopagados. Se um driver fornecer rotinas personalizadas alocar e gratuitamente para essa lista lookaside, essas rotinas não receberão um contexto privado como um parâmetro de entrada. Novamente, se o driver se destina a ser executado somente no Windows Vista e em versões posteriores do Windows, considere usar a estrutura LOOKASIDE_LIST_EX em vez da estrutura NPAGED_LOOKASIDE_LIST para suas listas lookaside. As seguintes rotinas fornecidas pelo sistema dão suporte a listas lookaside descritas por uma estrutura NPAGED_LOOKASIDE_LIST :

ExAllocateFromNPagedLookasideList

ExDeleteNPagedLookasideList

ExFreeToNPagedLookasideList

ExInitializeNPagedLookasideList

Diretrizes de implementação

Para implementar uma lista lookaside que usa uma estrutura LOOKASIDE_LIST_EX , siga estas diretrizes de design:

  • Chame ExInitializeLookasideListEx para configurar uma lista lookaside. Nesta chamada, especifique se as entradas na lista lookaside devem ser buffers paginados ou não. Use buffers nãopagados se o próprio driver ou qualquer driver subjacente ao qual ele passa suas entradas de lista lookaside poderão acessar essas entradas em IRQL >= DISPATCH_LEVEL. Use buffers paginado somente se os acessos às entradas da lista lookaside do driver sempre ocorrerem em IRQL <= APC_LEVEL.

  • A estrutura LOOKASIDE_LIST_EX para a lista lookaside sempre deve residir na memória do sistema nãopagada, independentemente de as entradas na lista serem paginadas ou não.

  • Para obter um melhor desempenho, passe os ponteiros NULL para os parâmetros Allocate e Free para ExInitializeLookasideListEx , a menos que as rotinas de alocação e desalocação precisem fazer mais do que apenas alocar e liberar memória para entradas de lista lookaside. Por exemplo, essas rotinas podem registrar informações sobre o uso do driver de buffers alocados dinamicamente.

  • Uma rotina allocate fornecida pelo driver pode passar os parâmetros de entrada (PoolType, Tag e Size) que recebe diretamente para a rotina ExAllocatePoolWithTag ou ExAllocatePoolWithQuotaTag para alocar um novo buffer.

  • Para cada chamada para ExAllocateFromLookasideListEx, faça a chamada recíproca para ExFreeToLookasideListEx o mais rápido possível sempre que uma entrada alocada anteriormente não estiver mais sendo usada.

Fornecer rotinas Allocate e Free que não fazem nada mais do que chamar ExAllocatePoolWithTag e ExFreePool, respectivamente, desperdiça ciclos de processador. ExAllocateFromLookasideListEx faz as chamadas necessárias para ExAllocatePoolWithTag e ExFreePool automaticamente quando um driver passa ponteiros NULLAllocate e Free para ExInitializeLookasideListEx.

Qualquer rotina allocate fornecida pelo driver não deve alocar memória para uma entrada do pool de páginas a ser mantida em uma lista lookaside não paga ou vice-versa. Ele também deve alocar entradas de tamanho fixo, pois qualquer chamada de driver subsequente para ExAllocateFromLookasideListEx retorna a primeira entrada atualmente mantida na lista lookaside, a menos que a lista esteja vazia. Ou seja, uma chamada para ExAllocateFromLookasideListEx causará uma chamada para a rotina Allocate fornecida pelo driver somente se a lista lookaside fornecida estiver vazia no momento. Portanto, em cada chamada para ExAllocateFromLookasideListEx, a entrada retornada será exatamente do tamanho que o driver só precisa se todas as entradas na lista lookaside forem de um tamanho fixo. Uma rotina allocate fornecida pelo driver também não deve alterar o valor de Marca que o driver originalmente passou para ExInitializeLookasideListEx, pois as alterações no valor de marca de pool dificultariam a depuração e o acompanhamento do uso de memória do driver.

Chamadas para o repositório ExFreeToLookasideListEx alocadas anteriormente na lista lookaside, a menos que a lista já esteja completa (ou seja, a lista contém o número máximo de entradas determinado pelo sistema). Para obter um melhor desempenho, um driver deve fazer uma chamada recíproca para ExFreeToLookasideListEx o mais rápido possível para cada chamada feita a ExAllocateFromLookasideListEx. Quando um driver libera entradas de volta à sua lista lookaside rapidamente, a próxima chamada desse driver para ExAllocateFromLookasideListEx é muito menos provável que incorre na penalidade de desempenho de alocar dinamicamente memória para uma nova entrada.

Diretrizes semelhantes se aplicam a uma lista lookaside que usa uma estrutura de PAGED_LOOKASIDE_LIST ou NPAGED_LOOKASIDE_LIST .