Partager via


Utilisation de listes lookaside

Les pilotes qui doivent allouer dynamiquement des mémoires tampons de taille fixe pour effectuer des opérations d’E/S à la demande peuvent utiliser les routines de prise en charge ExXxxLookasideListEx ou ExXxxLookasideList. Une fois que le pilote a initialisé sa liste lookaside, le système d’exploitation conserve un certain nombre de mémoires tampons de taille donnée alloués dynamiquement dans la liste lookaside du pilote, réservant ainsi à ce dernier un ensemble de mémoires tampons réutilisables de taille fixe. Le format et le contenu des mémoires tampons de taille fixe d’un pilote (également appelés entrées) dans sa liste lookaside sont déterminés par le pilote.

Par exemple, les pilotes de classe de stockage qui doivent configurer des blocs de requêtes SCSI (SRB) pour les pilotes de port/miniport SCSI sous-jacents utilisent des listes lookaside. Un pilote de ce type alloue des mémoires tampons pour les SRB en fonction des besoins à partir de sa liste lookaside et libère chaque mémoire tampon SRB dans la liste lookaside pour que celle-ci puisse la réutiliser chaque fois qu’un SRB est renvoyé au pilote de classe dans une IRP achevée. Étant donné qu’un pilote de classe de stockage ne peut pas déterminer à l’avance le nombre de SRB qu’il doit utiliser à tout moment parce que la demande d’E/S sur le pilote augmente et diminue, une liste lookaside est un moyen pratique et économique de gérer l’allocation et la désallocation des mémoires tampons pour les SRB de taille fixe dans un tel pilote.

Le système d’exploitation conserve l’état de toutes les listes lookaside paginées et non paginées actuellement utilisées, en suivant dynamiquement la demande d’allocations et de désallocations d’entrées dans toutes les listes et le pool système disponible pour les nouvelles entrées. Lorsque la demande d’allocations est élevée, le système d’exploitation augmente le nombre d’entrées qu’il contient dans chaque liste lookaside. Lorsque la demande chute à nouveau, il libère des entrées lookaside excédentaires dans le pool système.

Les listes lookaside sont thread-safe. La synchronisation intégrée à une liste lookaside permet à plusieurs threads s’exécutant simultanément dans un pilote de partager cette liste. Ces threads peuvent allouer en toute sécurité des mémoires tampons à partir de la liste lookaside partagée et libérer ces dernières dans la liste sans qu’il soit nécessaire que le pilote synchronise explicitement ces opérations. Toutefois, pour éviter des fuites potentielles et la corruption des données, un ensemble de threads qui partagent une liste lookaside doit synchroniser explicitement l’initialisation et la suppression de cette dernière.

Interfaces d’une liste lookaside

À partir de Windows Vista, la structure LOOKASIDE_LIST_EX décrit une liste lookaside qui peut contenir des mémoires tampons paginées ou non paginées. Si un pilote fournit des routines Allocate and Free personnalisées pour cette liste lookaside, ces dernières reçoivent un contexte privé en tant que paramètre d’entrée. Un pilote peut utiliser ce contexte pour collecter des données privées pour la liste lookaside. Par exemple, le contexte peut être utilisé pour compter le nombre d’entrées de liste qui sont dynamiquement allouées et libérées par la liste. Pour obtenir un exemple de code qui montre comment utiliser un contexte de cette façon, consultez ExInitializeLookasideListEx.

Les routines suivantes fournies par le système prennent en charge les listes lookaside décrites par une structure LOOKASIDE_LIST_EX :

ExAllocateFromLookasideListEx

ExDeleteLookasideListEx

ExFlushLookasideListEx

ExFreeToLookasideListEx

ExInitializeLookasideListEx

À partir de Windows 2000, la structure PAGED_LOOKASIDE_LIST décrit une liste lookaside contenant des mémoires tampons paginées. Si un pilote fournit des routines Allocate and Free personnalisées pour cette liste lookaside, ces dernières ne reçoivent pas de contexte privé en tant que paramètre d’entrée. C’est pourquoi, si votre pilote est destiné à s’exécuter uniquement sur Windows Vista et les versions ultérieures de Windows, envisagez d’utiliser la structure LOOKASIDE_LIST_EX au lieu de PAGED_LOOKASIDE_LIST pour vos listes lookaside. Les routines suivantes fournies par le système prennent en charge les listes lookaside décrites par une structure PAGED_LOOKASIDE_LIST :

ExAllocateFromPagedLookasideList

ExDeletePagedLookasideList

ExFreeToPagedLookasideList

ExInitializePagedLookasideList

À partir de Windows 2000, la structure NPAGED_LOOKASIDE_LIST décrit une liste lookaside contenant des mémoires tampons non paginées. Si un pilote fournit des routines Allocate and Free personnalisées pour cette liste lookaside, ces dernières ne reçoivent pas de contexte privé en tant que paramètre d’entrée. À nouveau, si votre pilote est destiné à s’exécuter uniquement sur Windows Vista et les versions ultérieures de Windows, envisagez d’utiliser la structure LOOKASIDE_LIST_EX au lieu de NPAGED_LOOKASIDE_LIST pour vos listes lookaside. Les routines suivantes fournies par le système prennent en charge les listes lookaside décrites par une structure NPAGED_LOOKASIDE_LIST :

ExAllocateFromNPagedLookasideList

ExDeleteNPagedLookasideList

ExFreeToNPagedLookasideList

ExInitializeNPagedLookasideList

Instructions d’implémentation

Pour implémenter une liste lookaside qui utilise une structure LOOKASIDE_LIST_EX , suivez les instructions de conception ci-dessous :

  • Appelez ExInitializeLookasideListEx pour configurer une liste lookaside. Dans cet appel, spécifiez si les entrées de la liste lookaside doivent être des mémoires tampons paginées ou non paginées. Utilisez des tampons non paginés si le pilote lui-même ou tout autre pilote sous-jacent auquel il transmet ses entrées de la liste lookaside peut accéder à ces entrées dans IRQL >= DISPATCH_LEVEL. Utilisez des mémoires tampons paginées uniquement si les accès aux entrées de liste lookaside du pilote se produisent toujours dans IRQL <= APC_LEVEL.

  • La structure LOOKASIDE_LIST_EX de la liste lookaside doit toujours résider dans la mémoire système non paginée, que les entrées de la liste soient paginées ou non paginées.

  • Pour de meilleures performances, transmettez des pointeurs NULL pour les paramètres Allocate et Free à ExInitializeLookasideListEx, sauf si les routines d’allocation et de désallocation doivent faire plus que simplement allouer et libérer de la mémoire pour les entrées de la liste lookaside. Par exemple, ces routines peuvent enregistrer des informations sur l’utilisation par le pilote des mémoires tampons allouées dynamiquement.

  • Une routine Allocate fournie par le pilote peut transmettre directement les paramètres d’entrée (PoolType, Tag, et Size) qu’elle reçoit à la routine ExAllocatePoolWithTag ou ExAllocatePoolWithQuotaTag pour allouer une nouvelle mémoire tampon.

  • Pour chaque appel à ExAllocateFromLookasideListEx, effectuez l’appel réciproque à ExFreeToLookasideListEx dès que possible chaque fois qu’une entrée précédemment allouée n’est plus utilisée.

Fournir des routine Allocate and Free qui ne font rien de plus que d’appeler ExAllocatePoolWithTag et ExFreePool, respectivement, constitue un gaspillage de cycles de processeur. ExAllocateFromLookasideListEx effectue les appels nécessaires à ExAllocatePoolWithTag et ExFreePool automatiquement lorsqu’un pilote transmet des pointeurs NULL Allocate et Free à ExInitializeLookasideListEx.

Toute routine Allocate fournie par le pilote ne doit pas allouer de mémoire pour qu’une entrée du pool paginé soit conservée dans une liste lookaside non paginée ou vice versa. Elle doit également allouer des entrées de taille fixe, car tout appel de pilote ultérieur à ExAllocateFromLookasideListEx renvoie la première entrée actuellement conservée dans la liste lookaside, sauf si elle est vide. Autrement dit, un appel à ExAllocateFromLookasideListEx provoque un appel à la routine Allocate fournie par le pilote uniquement si la liste lookaside donnée est actuellement vide. Par conséquent, lors de chaque appel à ExAllocateFromLookasideListEx, l’entrée renvoyée aura exactement la taille dont le pilote a besoin, uniquement si toutes les entrées de la liste lookaside ont une taille fixe. Une routine Allocate fournie par le pilote ne doit pas non plus modifier la valeur de Tag que le pilote a initialement transmise à ExInitializeLookasideListEx, car des modifications de la valeur pool-tag rendraient le débogage et le suivi de l’utilisation de la mémoire par le pilote plus difficiles.

Les appels à ExFreeToLookasideListEx stockent des entrées précédemment allouées dans la liste lookaside, sauf si celle-ci est déjà pleine (c’est-à-dire que la liste contient le nombre maximum d’entrées déterminé par le système). Pour de meilleures performances, un pilote doit effectuer un appel réciproque à ExFreeToLookasideListEx aussi rapidement que possible pour chaque appel qu’il effectue à ExAllocateFromLookasideListEx. Lorsqu’un pilote libère rapidement les entrées dans sa liste lookaside, son prochain appel à ExAllocateFromLookasideListEx est beaucoup moins susceptible d’être pénalisé en termes de performances par l’allocation dynamique de mémoire pour une nouvelle entrée.

Des règles similaires s’appliquent à une liste lookaside qui utilise une structure PAGED_LOOKASIDE_LIST ou NPAGED_LOOKASIDE_LIST.