Detecção de deadlock

A Detecção de Deadlock monitora o uso de recursos do driver que precisam ser bloqueados – bloqueios de rotação, mutexes e mutexes rápidos. Essa opção verificador de driver detectará a lógica de código que tem o potencial de causar um deadlock em algum momento futuro.

A opção Detecção de Deadlock do Verificador de Driver, juntamente com a extensão do depurador de kernel !deadlock , é uma ferramenta eficaz para garantir que seu código evite o mau uso desses recursos.

A Detecção de Deadlock tem suporte apenas no Windows XP e em versões posteriores do Windows.

Causas de deadlocks

Um deadlock é causado quando dois ou mais threads entram em conflito sobre algum recurso, de modo que nenhuma execução seja possível.

A forma mais comum de deadlock ocorre quando dois ou mais threads esperam por um recurso que pertence ao outro thread. Isso é ilustrado da seguinte maneira:

Thread 1 Thread 2
Usa o bloqueio A Usa o bloqueio B
Bloqueio de Solicitações B Solicitações Bloquear A

Se ambas as sequências ocorrerem ao mesmo tempo, o Thread 1 nunca obterá o Bloqueio B porque pertence ao Thread 2 e o Thread 2 nunca obterá o Bloqueio A porque pertence ao Thread 1. Na melhor das hipóteses, isso faz com que os threads envolvidos interrompam e, na pior das hipóteses, faz com que o sistema pare de responder.

Os deadlocks não estão limitados a dois threads e dois recursos. Deadlocks de três vias entre três threads e três bloqueios são comuns e até mesmo deadlocks de cinco ou seis partes ocorrem ocasionalmente. Esses deadlocks exigem um certo grau de "má sorte", pois dependem de várias coisas acontecendo simultaneamente. No entanto, quanto mais distantes forem as aquisições de bloqueio, mais provável será que elas se tornem.

Deadlocks de thread único podem ocorrer quando um thread tenta obter um bloqueio que ele já possui.

O denominador comum entre todos os deadlocks é que a hierarquia de bloqueio não é respeitada. Sempre que for necessário ter mais de um bloqueio adquirido por vez, cada bloqueio deverá ter uma precedência clara. Se A for usado antes de B em um ponto e B antes de C em outro, a hierarquia será A-B-C. Isso significa que A nunca deve ser adquirido após B ou C, e B não deve ser adquirido após C.

A hierarquia de bloqueio deve ser seguida mesmo quando não há possibilidade de um deadlock, pois, no processo de manutenção do código, será fácil para um deadlock ser introduzido acidentalmente.

Recursos que podem causar deadlocks

Os deadlocks mais inequívocas são o resultado de recursos de propriedade . Isso inclui bloqueios de rotação, mutexes, mutexes rápidos e ERESOURCEs.

Recursos sinalizados em vez de adquiridos (como eventos e portas LPC) tendem a causar deadlocks muito mais ambíguos. É claro que é possível, e muito comum, que o código use indevidamente esses recursos de forma que dois threads acabem esperando indefinidamente que um ao outro seja concluído. No entanto, como esses recursos não pertencem realmente a nenhum thread, não é possível identificar o thread delinquente com qualquer grau de certeza.

A opção Detecção de Deadlock do Verificador de Driver procura possíveis deadlocks envolvendo bloqueios de rotação, mutexes e mutexes rápidos. Ele não monitora o uso de ERESOURCEs nem monitora o uso de recursos não proprietários.

Efeitos da detecção de deadlock

As rotinas de Detecção de Deadlock do Verificador de Driver encontram violações da hierarquia de bloqueio que não são necessariamente simultâneas. Na maioria das vezes, essas violações identificam caminhos de código que serão deadlock quando houver a chance.

Para encontrar possíveis deadlocks, o Verificador de Driver cria um grafo de ordem de aquisição de recursos e verifica loops. Se você criar um nó para cada recurso e desenhar uma seta sempre que um bloqueio for adquirido antes de outro, os loops de caminho representarão violações da hierarquia de bloqueio.

O Verificador de Driver emitirá um bug marcar quando uma dessas violações for descoberta. Isso acontecerá antes que ocorram deadlocks reais.

Observação

Mesmo que os caminhos de código conflitantes nunca possam acontecer simultaneamente, eles ainda deverão ser reescritos se envolverem violações de hierarquia de bloqueio. Esse código é um "deadlock aguardando para acontecer" que pode causar deadlocks reais se o código for reescrito ligeiramente.

Quando a Detecção de Deadlock encontrar uma violação, ela emitirá marcar 0xC4 de bugs. O primeiro parâmetro desse bug marcar indicará a violação exata. As possíveis violações incluem:

  • Dois ou mais threads envolvidos em uma violação da hierarquia de bloqueio

  • Um thread que tenta adquirir exclusivamente um recurso para o qual ele já é um proprietário compartilhado (recursos de propriedade exclusiva podem ser adquiridos compartilhados; recursos compartilhados não podem ser adquiridos exclusivamente).

  • Um thread que tenta adquirir o mesmo recurso duas vezes (um auto deadlock)

  • Um recurso que é liberado sem ter sido adquirido primeiro

  • Um recurso que é liberado por um thread diferente daquele que o adquiriu

  • Um recurso inicializado mais de uma vez ou não inicializado

  • Um thread que é excluído enquanto ainda possui recursos

  • A partir do Windows 7, o Verificador de Driver pode prever possíveis deadlocks. Por exemplo, tentar usar o mesmo KSPIN_LOCK estrutura de dados como um bloqueio de rotação regular e como um bloqueio de rotação na fila de pilha.

Consulte 0xC4 de Verificação de Bugs (DRIVER_VERIFIER_DETECTED_VIOLATION) para obter uma lista dos parâmetros de marcar de bugs.

Monitoramento da detecção de deadlock

Depois que a Detecção de Deadlock encontrar uma violação, a extensão do depurador de kernel !deadlock poderá ser usada para investigar exatamente o que ocorreu. Ele pode exibir a topologia de hierarquia de bloqueio, bem como as pilhas de chamadas para cada thread no momento em que os bloqueios foram adquiridos originalmente.

Há um exemplo detalhado da extensão !deadlock , bem como informações gerais sobre extensões do depurador, na documentação do pacote Ferramentas de Depuração para Windows. Consulte Depuração do Windows para obter detalhes.

Ativando essa opção

Observação

Essa opção é incompatível com o fuzzing de atraso de sincronização do kernel

Você pode ativar o recurso detecção de deadlock para um ou mais drivers usando o Gerenciador de Verificador de Driver ou a linha de comando Verifier.exe. Para obter detalhes, consulte Selecionando opções do verificador de driver.

  • Na linha de comando

    Na linha de comando, a opção Detecção de Deadlock é representada pelo Bit 5 (0x20). Para ativar a Detecção de Deadlock, use um valor de sinalizador de 0x20 ou adicione 0x20 ao valor do sinalizador. Por exemplo:

    verifier /flags 0x20 /driver MyDriver.sys
    

    O recurso estará ativo após a próxima inicialização.

    No Windows Vista e em versões posteriores do Windows, você também pode ativar e desativar a Detecção de Deadlock sem reinicializar o computador adicionando o parâmetro /volatile ao comando . Por exemplo:

    verifier /volatile /flags 0x20 /adddriver MyDriver.sys
    

    Essa configuração entra em vigor imediatamente, mas é perdida quando você desliga ou reinicializa o computador. Para obter detalhes, consulte Usando configurações voláteis.

    O recurso Detecção de Deadlock também está incluído nas configurações padrão. Por exemplo:

    verifier /standard /driver MyDriver.sys
    
  • Usando o Gerenciador de Verificador de Driver

    1. Selecione Criar configurações personalizadas (para desenvolvedores de código) e, em seguida, selecione Avançar.

    2. Selecione Selecionar configurações individuais em uma lista completa.

    3. Selecione (marcar) Detecção de deadlock.

O recurso Detecção de Deadlock também está incluído nas configurações padrão. Para usar esse recurso, no Gerenciador de Verificador de Driver, selecione Criar Configurações Padrão.