Synchronisation du code d’interruption

Les facteurs suivants compliquent le code du pilote qui gère les interruptions matérielles sur les systèmes multiprocesseurs :

  • Chaque fois qu’un appareil s’interrompt, il fournit des informations spécifiques aux interruptions qui sont volatiles, car elles peuvent être remplacées la prochaine fois que l’appareil s’interrompt.

  • Les appareils s’interrompent à des IRQL relativement élevés et leurs routines de service d’interruption (ISR) peuvent interrompre l’exécution d’autres codes de pilote.

  • Pour les interruptions DIRQL, l’ISR doit s’exécuter sur DIRQL tout en conservant un verrou de rotation fourni par le pilote, afin que l’ISR puisse empêcher d’autres interruptions pendant qu’il enregistre des informations volatiles. Le DIRQL empêche l’interruption par le processeur actuel, et le verrouillage de rotation empêche l’interruption par un autre processeur.

  • L’ISR doit s’exécuter rapidement, car l’appareil ne peut pas s’interrompre pendant l’exécution de l’ISR. Des temps d’exécution ISR longs peuvent ralentir le système ou éventuellement entraîner une perte de données.

  • L’ISR et la routine d’appel de procédure différée (DPC) doivent généralement accéder à une zone de stockage dans laquelle l’ISR stocke les données volatiles de l’appareil. Ces routines doivent se synchroniser les unes avec les autres afin qu’elles n’accèdent pas à la zone de stockage en même temps.

En raison de tous ces facteurs, vous devez utiliser les règles suivantes lors de l’écriture de code de pilote qui gère les interruptions :

  • Seule la fonction de rappel EvtInterruptIsr accède aux données d’interruption volatiles, telles que les registres d’appareils qui contiennent des informations d’interruption.

    La fonction de rappel EvtInterruptIsr doit déplacer les données volatiles vers une mémoire tampon de données d’interruption définie par le pilote à laquelle la fonction de rappel EvtInterruptDpc du pilote, la fonction de rappel EvtInterruptWorkItem ou plusieurs fonctions de rappel EvtDpcFunc peuvent accéder.

    Si votre pilote fournit des fonctions de rappel EvtInterruptDpc ou EvtInterruptWorkItem pour ses objets d’interruption, le meilleur endroit pour stocker les données d’interruption est l’espace contextuel de l’objet d’interruption. Les fonctions de rappel de l’objet d’interruption peuvent accéder à l’espace contextuel de l’objet à l’aide du handle d’objet qu’ils reçoivent.

    Si votre pilote fournit plusieurs fonctions de rappel EvtDpcFunc pour chaque fonction de rappel EvtInterruptIsr , vous pouvez stocker les données d’interruption dans l’espace contextuel de chaque objet DPC.

  • Tout le code de pilote qui accède à la mémoire tampon des données d’interruption doit être synchronisé afin qu’une seule routine accède aux données à la fois.

    Pour les objets d’interruption DIRQL, la fonction de rappel EvtInterruptIsr accède à cette mémoire tampon de données à IRQL = DIRQL tout en conservant le verrou de rotation fourni par le pilote de l’objet d’interruption. Par conséquent, toutes les routines qui accèdent à la mémoire tampon doivent également s’exécuter au niveau de DIRQL tout en maintenant le verrou de rotation. (En règle générale, la fonction de rappel EvtInterruptDpc ou EvtDpcFunc de l’interruption est la seule autre routine qui doit accéder à la mémoire tampon.)

    Toutes les routines qui accèdent à une mémoire tampon de données d’interruption, à l’exception de la fonction de rappel EvtInterruptIsr , doivent effectuer l’une des opérations suivantes :

    Ces deux techniques permettent à la fonction EvtInterruptDpc ou EvtDpcFunc d’accéder aux données d’interruption au niveau de DIRQL tout en conservant le verrou de rotation de l’interruption. Le DIRQL empêche l’interruption par le processeur actuel, et le verrouillage de rotation empêche l’interruption par un autre processeur.

    Si votre appareil prend en charge plusieurs vecteurs d’interruption ou messages, et si vous souhaitez synchroniser la gestion de ces interruptions par votre pilote, vous pouvez affecter un verrou de rotation unique à plusieurs objets d’interruption DIRQL. L’infrastructure détermine le DIRQL le plus élevé du jeu d’interruptions, et il acquiert toujours le verrou de rotation au niveau de ce DIRQL afin que le code synchronisé ne puisse pas être interrompu par des vecteurs d’interruption ou des messages dans le jeu.

    Pour les objets d’interruption de niveau passif, l’infrastructure acquiert le verrou d’interruption de niveau passif avant d’appeler la fonction de rappel EvtInterruptIsr du pilote à IRQL = PASSIVE_LEVEL. Par conséquent, toutes les routines qui accèdent à la mémoire tampon doivent acquérir le verrou d’interruption ou synchroniser en interne l’accès à la mémoire tampon. En règle générale, la fonction de rappel EvtInterruptWorkItem de l’interruption est la seule autre routine qui accède à la mémoire tampon. Pour plus d’informations sur l’acquisition du verrou d’interruption à partir d’une fonction de rappel EvtInterruptWorkItem , consultez la section Remarques de cette page.

    Vous pouvez également synchroniser la gestion de plusieurs vecteurs d’interruption par votre pilote en affectant un verrou d’attente unique à plusieurs objets d’interruption de niveau passif.

  • Si une partie de votre code qui gère les interruptions DIRQL doit s’exécuter à IRQL = PASSIVE_LEVEL, votre fonction de rappel EvtInterruptDpc ou EvtDpcFunc peut créer un ou plusieurs éléments de travail afin que le code s’exécute en tant que fonctions de rappel EvtWorkItem .

    Dans les versions KMDF 1.11 et ultérieures, le pilote peut également demander un élément de travail d’interruption en appelant WdfInterruptQueueWorkItemForIsr. (Rappelez-vous que la fonction de rappel EvtInterruptIsr d’un pilote peut appeler WdfInterruptQueueWorkItemForIsr ou WdfInterruptQueueDpcForIsr, mais pas les deux.)

  • S’il est important de synchroniser les fonctions de rappel EvtInterruptDpc et EvtDpcFunc d’un pilote entre elles et avec d’autres fonctions de rappel associées à un appareil, votre pilote peut définir le membre AutomaticSerialization sur TRUE dans la structure WDF_INTERRUPT_CONFIG de l’interruption et la structure WDF_DPC_CONFIG de l’objet DPC. Le pilote peut également utiliser des verrous de rotation de l’infrastructure. (La définition du membre AutomaticSerialization sur TRUE ne synchronise pas une fonction de rappel EvtInterruptIsr avec d’autres fonctions de rappel. Utilisez WdfInterruptSynchronize ou WdfInterruptAcquireLock pour synchroniser une fonction de rappel EvtInterruptIsr , comme décrit précédemment dans cette rubrique.)

Pour plus d’informations sur la synchronisation des routines de pilotes, consultez Techniques de synchronisation pour les pilotes Framework-Based.