Uso de listas Lookaside
Los controladores que deben asignar búferes de tamaño fijo dinámicamente para realizar operaciones de E/S a petición pueden usar las rutinas de soporte ExXxxLookasideListEx o ExXxxLookasideList. Después de que este controlador inicialice su lista lookaside, el sistema operativo contendrá algún número de búferes asignados dinámicamente del tamaño especificado en la lista lookaside del controlador, reservando eficazmente un conjunto de búferes reutilizables de tamaño fijo para el controlador. El formato y el contenido de los búferes de tamaño fijo de un controlador (también conocidos como entradas) en su lista lookaside están determinados por el controlador.
Por ejemplo, los controladores de clase de almacenamiento que deben configurar bloques de solicitudes SCSI (SRB) para los controladores de puerto o minipuerto SCSI subyacentes usan listas lookaside. Este controlador de clase asigna búferes para SRB según sea necesario a partir de su lista lookaside y libera cada búfer SRB de reserva a la lista lookaside de la lista lookaside para reutilizar cada vez que se devuelve un SRB al controlador de clase en un IRP completado. Dado que un controlador de clase de almacenamiento no puede predeterminar cuántos SRB tiene que usar en cualquier momento porque la demanda de E/S en el controlador aumenta y cae, una lista lookaside es una manera cómoda y económica de administrar la asignación y desasignación de búferes para SRB de tamaño fijo en este controlador.
El sistema operativo mantiene el estado de todas las listas de búsqueda paginadas y no paginadas que se están usando actualmente, realizando un seguimiento dinámico de la demanda de asignaciones y desasignaciones de entradas en todas las listas y el grupo de sistemas disponible para las nuevas entradas. Cuando la demanda de asignaciones es alta, el sistema operativo aumenta el número de entradas que contiene en cada lista de búsqueda. Cuando la demanda cae de nuevo, libera entradas de lookaside sobrantes al grupo del sistema.
Las listas lookaside son seguras para subprocesos. Una lista lookaside tiene sincronización integrada para habilitar varios subprocesos que se ejecutan simultáneamente en un controlador para compartir una lista lookaside. Estos subprocesos pueden asignar búferes de forma segura desde la lista lookaside compartida y liberar estos búferes a la lista sin necesidad de que el controlador sincronice explícitamente estas operaciones. Sin embargo, para evitar posibles pérdidas y daños en los datos, un conjunto de subprocesos que comparten una lista lookaside debe sincronizar explícitamente la inicialización y eliminación de la lista.
Interfaces de lista lookaside
A partir de Windows Vista, la estructura LOOKASIDE_LIST_EX describe una lista lookaside que puede contener búferes paginados o no paginados. Si un controlador proporciona rutinas de asignación y liberación personalizadas para esta lista lookaside, estas rutinas reciben un contexto privado como parámetro de entrada. Un controlador puede usar este contexto para recopilar datos privados de la lista lookaside. Por ejemplo, el contexto puede usarse para contar el número de entradas de lista que la lista asigna y libera dinámicamente. Para obtener un ejemplo de código que muestre cómo usar un contexto de esta manera, consulte ExInitializeLookasideListEx.
Las siguientes rutinas proporcionadas por el sistema admiten listas lookaside que se describen mediante una estructura LOOKASIDE_LIST_EX:
A partir de Windows 2000, la estructura PAGED_LOOKASIDE_LIST describe una lista lookaside que contiene búferes paginados. Si un controlador proporciona rutinas de asignación y liberación personalizadas para esta lista lookaside, estas rutinas no reciben un contexto privado como parámetro de entrada. Por este motivo, si el controlador está pensado para ejecutarse solo en Windows Vista y versiones posteriores de Windows, considere la posibilidad de usar la estructura LOOKASIDE_LIST_EX en lugar de la estructura PAGED_LOOKASIDE_LIST para las listas lookaside. Las siguientes rutinas proporcionadas por el sistema admiten listas lookaside que se describen mediante una estructura PAGED_LOOKASIDE_LIST:
ExAllocateFromPagedLookasideList
ExInitializePagedLookasideList
A partir de Windows 2000, la estructura NPAGED_LOOKASIDE_LIST describe una lista lookaside que contiene búferes no paginados. Si un controlador proporciona rutinas de asignación y liberación personalizadas para esta lista lookaside, estas rutinas no reciben un contexto privado como parámetro de entrada. De nuevo, si el controlador está pensado para ejecutarse solo en Windows Vista y versiones posteriores de Windows, considere la posibilidad de usar la estructura LOOKASIDE_LIST_EX en lugar de la estructura NPAGED_LOOKASIDE_LIST para las listas lookaside. Las siguientes rutinas proporcionadas por el sistema admiten listas lookaside que se describen mediante una estructura NPAGED_LOOKASIDE_LIST:
ExAllocateFromNPagedLookasideList
ExInitializeNPagedLookasideList
Guías de implementación
Para implementar una lista lookaside que use una estructura LOOKASIDE_LIST_EX, siga estas directrices de diseño:
Llame a ExInitializeLookasideListEx para configurar una lista lookaside. En esta llamada, especifique si las entradas de la lista lookaside deben ser búferes paginados o no paginados. Use búferes no paginados si el propio controlador o cualquier controlador subyacente al que pasa sus entradas de lista lookaside podría tener acceso a estas entradas en IRQL >= DISPATCH_LEVEL. Use búferes paginados solo si los accesos a las entradas de la lista lookaside del controlador siempre se producen en IRQL <= APC_LEVEL.
La estructura LOOKASIDE_LIST_EX de la lista lookaside siempre debe residir en la memoria del sistema no paginada, independientemente de si las entradas de la lista están paginadas o no paginadas.
Para mejorar el rendimiento, pase punteros NULL para los parámetros Allocate y Free a ExInitializeLookasideListEx a menos que las rutinas de asignación y desasignación deban hace algo más que asignar y liberar memoria para entradas de lista lookaside. Por ejemplo, estas rutinas pueden registrar información sobre el uso del controlador de búferes asignados dinámicamente.
Una rutina de asignación proporcionada por el controlador puede pasar los parámetros de entrada (PoolType, Tag y Size) que recibe directamente a la rutina ExAllocatePoolWithTag o ExAllocatePoolWithQuotaTagpara asignar un nuevo búfer.
Para cada llamada a ExAllocateFromLookasideListEx, realice la llamada recíproca a ExFreeToLookasideListEx lo antes posible siempre que ya no se use una entrada asignada previamente.
Suministrar rutinas Allocate y Free que no hacen más que llamar a ExAllocatePoolWithTag y ExFreePool, respectivamente, desperdicia ciclos de procesador. ExAllocateFromLookasideListEx realiza las llamadas necesarias a ExAllocatePoolWithTag y ExFreePool automáticamente cuando un controlador pasa punteros NULL Allocate y Free a ExInitializeLookasideListEx.
Cualquier rutina Allocate proporcionada por el controlador no debe asignar memoria para que una entrada del grupo paginado se mantenga en una lista lookaside no paginada o viceversa. También debe asignar entradas de tamaño fijo, ya que cualquier llamada de controlador posterior a ExAllocateFromLookasideListEx devuelve la primera entrada que se mantiene actualmente en la lista lookaside a menos que la lista esté vacía. Es decir, una llamada a ExAllocateFromLookasideListEx provoca una llamada a la rutina Allocate proporcionada por el controlador solo si la lista lookaside especificada está vacía actualmente. Por lo tanto, en cada llamada a ExAllocateFromLookasideListEx, la entrada devuelta será exactamente el tamaño que el controlador necesita solo si todas las entradas de la lista lookaside tienen un tamaño fijo. Una rutina Allocate proporcionada por el controlador tampoco debe cambiar el valor Tag que el controlador pasó originalmente a ExInitializeLookasideListEx, ya que los cambios en el valor de etiqueta de grupo harían que la depuración y el seguimiento del uso de memoria del controlador sea más difícil.
Las llamadas a ExFreeToLookasideListEx almacenan entradas asignadas previamente en la lista lookaside, a menos que la lista ya esté llena (es decir, la lista contiene el número máximo de entradas determinado por el sistema). Para mejorar el rendimiento, un controlador debe realizar una llamada recíproca a ExFreeToLookasideListEx lo más rápido posible para cada llamada que realiza a ExAllocateFromLookasideListEx. Cuando un controlador libera las entradas a su lista lookaside rápidamente, la siguiente llamada del controlador a ExAllocateFromLookasideListEx es mucho menos probable que incurra en la penalización del rendimiento de asignar memoria dinámicamente para una nueva entrada.
Se aplican instrucciones similares a una lista lookaside que usa una estructura PAGED_LOOKASIDE_LIST o NPAGED_LOOKASIDE_LIST structure.