Compartir a través de


Errores en un entorno de varios procesadores

En el sistema operativo basado en NT, los controladores son multiproceso; pueden recibir varias solicitudes de E/S de diferentes subprocesos al mismo tiempo. Al diseñar un controlador, debe suponer que se ejecutará en un sistema SMP y tomar las medidas adecuadas para garantizar la integridad de los datos.

En concreto, cada vez que un controlador cambia los datos globales o de objetos de archivo, debe usar un bloqueo o una secuencia interbloqueada para evitar condiciones de carrera.

Encuentro de una condición de carrera al hacer referencia a datos globales o específicos del objeto de archivo

En el siguiente fragmento de código, se podría producir una condición de carrera cuando el controlador accede a los datos globales en Data.LpcInfo.

   PLPC_INFO pLpcInfo = &Data.LpcInfo; //Pointer to global data
   ...
   ...
   // This saved pointer may be overwritten by another thread.
   pLpcInfo->LpcPortName.Buffer = ExAllocatePool(
                                     PagedPool,
                                     arg->PortName.Length);

Varios subprocesos que acceden a este código como resultado de una llamada IOCTL podrían provocar una pérdida de memoria al sobrescribirse el puntero. Para evitar este problema, el controlador debe usar las rutinas ExInterlockedXxx o algún tipo de bloqueo cuando cambia los datos globales. Los requisitos del controlador determinan los tipos aceptables de bloqueos. Para obtener más información, vea Bloqueos de Spin, objetos de despacho del kernel y ExAcquireResourceSharedLite.

En el ejemplo siguiente se intenta reasignar un búfer específico del archivo (Endpoint-LocalAddress>) para contener la dirección del punto de conexión:

   Endpoint = FileObject->FsContext;

    if ( Endpoint->LocalAddress != NULL &&
         Endpoint->LocalAddressLength <
                   ListenEndpoint->LocalAddressLength ) {

      FREE_POOL (Endpoint->LocalAddress,
                 LOCAL_ADDRESS_POOL_TAG
                 );
      Endpoint->LocalAddress  = NULL;
   }

    if ( Endpoint->LocalAddress == NULL ) {
       Endpoint->LocalAddress =
            ALLOCATE_POOL (NonPagedPool,
                           ListenEndpoint->LocalAddressLength,
                           LOCAL_ADDRESS_POOL_TAG);
   }

En este ejemplo, podría ocurrir una condición de carrera al acceder al objeto de archivo. Dado que el controlador no contiene ningún bloqueo, dos solicitudes para el mismo objeto de archivo pueden escribir esta función. El resultado puede ser referencias a la memoria libre, varios intentos de liberar la misma memoria o pérdidas de memoria. Para evitar estos errores, las dos instrucciones if deben incluirse en un bloqueo de giro.