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 threads diferentes ao mesmo tempo. Ao criar 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 altera dados globais ou de objeto de arquivo, ele deve usar um bloqueio ou uma sequência interconectada para evitar condições de corrida.

Encontrando uma condição de corrida ao referenciar dados globais ou específicos do objeto de arquivo

No snippet 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 driver 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 nenhum bloqueio, duas solicitações para o mesmo objeto de arquivo podem entrar nessa 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 colocadas em um bloqueio de rotação.