Sincronizando o acesso aos dados do dispositivo
Normalmente, as rotinas InterruptService ou InterruptMessageService (ISRs) de um driver devem compartilhar o acesso aos dados do driver e aos recursos de hardware com outras rotinas de driver. Como os ISRs são executados em um contexto de interrupção em um IRQL elevado e, como um sistema pode ter vários processadores, é importante sincronizar o acesso a dados e recursos compartilhados para que cada rotina possa ter acesso exclusivo a essas informações compartilhadas temporariamente, sem interrupção.
O sistema dá suporte a essa sincronização executando o ISR em uma seção crítica de interrupção. Uma interrupção tem um bloqueio de rotação atribuído, o bloqueio de rotação de interrupção e IRQL, o IRQL de sincronização de interrupção. O sistema garante que esse código seja executado na seção crítica acesso exclusivo a informações compartilhadas, elevando o IRQL do processador para o IRQL de sincronização de interrupção e adquirindo o bloqueio de rotação de interrupção antes de executar o código. O sistema sempre entra na seção crítica da interrupção antes de executar seu ISR. Diferentes interrupções podem compartilhar a mesma seção crítica compartilhando o bloqueio de rotação de interrupção e o IRQL de sincronização.
Os drivers podem implementar o código executado na seção crítica da interrupção fornecendo uma rotina SynchCritSection . Quando o driver usa KeSynchronizeExecution para chamar a rotina SynchCritSection , o sistema entra automaticamente na seção crítica para a interrupção especificada pelo parâmetro Interrupt .
Elevar o IRQL do processador para a IRQL de sincronização da interrupção impede que o processador atual seja interrompido, exceto por uma interrupção com um IRQL de sincronização mais alto. A aquisição de um bloqueio de rotação impede que outros processadores executem qualquer código de seção crítico associado a esse bloqueio de rotação.
O sistema atribui o IRQL de bloqueio de rotação de interrupção e sincronização para a interrupção quando o driver chama IoConnectInterruptEx. Na maioria das instâncias, o driver pode permitir que o sistema determine os dois valores:
Se o driver usar a versão CONNECT_LINE_BASED de IoConnectInterruptEx e especificar um bloqueio de rotação NULL , o sistema alocará um bloqueio de rotação para a linha de interrupção. O sistema também determina o valor do IRQL de sincronização (os drivers podem, opcionalmente, especificar um valor mais alto).
Se o driver usar a versão CONNECT_MESSAGE_BASED de IoConnectInterruptEx e especificar um bloqueio de rotação NULL , o sistema alocará um bloqueio de rotação para cada mensagem de interrupção. O sistema também determina o valor do IRQL de sincronização para cada mensagem (os drivers podem, opcionalmente, especificar um valor mais alto que será comum a todas as mensagens).
Um driver deve alocar seu próprio bloqueio de rotação somente ao usar a versão CONNECT_FULLY_SPECIFIED de IoConnectInterruptEx e quando ele tiver vários vetores de interrupção que devem compartilhar a mesma seção crítica. Um driver pode especificar seu próprio IRQL de bloqueio de rotação e sincronização usando os membros SpinLock e SynchronizeIrql de IO_CONNECT_INTERRUPT_PARAMETERS. Para obter mais informações, consulte IO_CONNECT_INTERRUPT_PARAMETERS.
Para obter informações sobre como escrever e inserir seções críticas, consulte Usando seções críticas.