Compartilhar via


Erros em um ambiente multiprocessador

No sistema operacional baseado em NT, os drivers são multiencadeados; eles podem receber várias solicitações de E/S de threads diferentes ao mesmo tempo. Ao projetar um driver, você deve assumir que ele será executado em um sistema SMP e tomar as medidas apropriadas para garantir a integridade dos dados.

Especificamente, sempre que um driver modifica dados globais ou de objetos de arquivo, ele deve empregar um bloqueio ou uma sequência intertravada para prevenir condições de corrida.

Encontrando uma condição de corrida crítica ao referenciar dados globais ou específicos de um objeto de arquivo.

No trecho de código a seguir, uma condição de corrida pode ocorrer quando o driver acessa os dados globais em 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);

Vários threads que inserem esse código como resultado de uma chamada IOCTL podem causar um vazamento de memória à medida que o ponteiro é substituído. Para evitar esse problema, o driver deve usar as rotinas Xxx ExInterlocked ou algum tipo de bloqueio ao alterar os dados globais. Os requisitos do controlador determinam os tipos aceitáveis de bloqueios. Para obter mais informações, consulte Spin Locks, Kernel Dispatcher Objects e ExAcquireResourceSharedLite.

O exemplo a seguir tenta realocar um buffer específico do arquivo (Endpoint-LocalAddress>) para manter o endereço do ponto de extremidade:

   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);
   }

Neste exemplo, uma condição de corrida pode ocorrer com acessos ao objeto de arquivo. Como o driver não mantém bloqueios, duas solicitações para o mesmo objeto de arquivo podem inserir essa função. O resultado pode ser referências à memória liberada, várias tentativas de liberar a mesma memória ou vazamentos de memória. Para evitar esses erros, as duas instruções if devem ser fechadas em um spin lock.