Partilhar via


Erros em um ambiente multiprocessador

No sistema operacional baseado em NT, os drivers são multithreaded; eles podem receber várias solicitações de E/S de diferentes threads 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 motorista altera dados globais ou de objeto de arquivo, ele deve usar um bloqueio ou uma sequência intertravada para evitar condições de corrida.

Encontrando uma condição de concorrência ao referenciar dados globais ou específicos a objetos de arquivo

No trecho de código a seguir, uma condição de corrida pode ocorrer quando o motorista 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 inserindo 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 ExInterlocked Xxx ou algum tipo de bloqueio quando ele altera os dados globais. Os requisitos do condutor determinam os tipos aceitáveis de fechaduras. Para obter mais informações, consulte Spin Locks, Kernel Dispatcher Objects e ExAcquireResourceSharedLite.

O exemplo a seguir tenta realocar um buffer específico de 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 nenhum bloqueio, duas solicitações para o mesmo objeto de arquivo podem entrar nessa função. O resultado pode ser referências a 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 incluídas em um bloqueio de rotação.