Partager via


Utilisation d’une routine IoTimer

Alors que le minuteur de l’objet d’appareil associé est activé, la routine IoTimer est appelée environ une fois par seconde. Toutefois, étant donné que les intervalles auxquels chaque routine IoTimer est appelée dépendent de la résolution de l’horloge système, ne supposez pas qu’une routine IoTimer sera appelée précisément sur une limite d’une seconde.

Note Une routine IoTimer , comme toutes les routines DPC, est appelée dans IRQL = DISPATCH_LEVEL. Pendant qu’une routine DPC s’exécute, tous les threads ne peuvent pas s’exécuter sur le même processeur. Les développeurs de pilotes doivent concevoir soigneusement leurs routines IoTimer pour qu’elles s’exécutent aussi brièvement que possible.

L’utilisation la plus courante d’une routine IoTimer est peut-être d’expirer les opérations d’E/S de l’appareil pour une IRP. Envisagez le scénario suivant pour l’utilisation d’une routine IoTimer comme minuteur en cours d’exécution dans un pilote de périphérique :

  1. Lorsqu’il démarre l’appareil, le pilote initialise un compteur de minuteur dans l’extension de l’appareil sur -1, indiquant qu’aucune opération d’E/S d’appareil n’est en cours et appelle IoStartTimer juste avant qu’il ne retourne STATUS_SUCCESS.

    Chaque fois que la routine IoTimer est appelée, elle vérifie si le compteur du minuteur est -1 et, si c’est le cas, retourne le contrôle.

  2. La routine StartIo du pilote initialise le compteur du minuteur dans l’extension de l’appareil à une limite supérieure, plus une seconde supplémentaire au cas où la routine IoTimer vient d’être exécutée. Il utilise ensuite KeSynchronizeExecution pour appeler une routine SynchCritSection_1 , qui programme l’appareil physique pour l’opération demandée par l’IRP actuel.

  3. L’ISR du pilote réinitialise le compteur du minuteur à -1 avant de mettre en file d’attente la routine DpcForIsr du pilote ou une routine CustomDpc .

  4. Chaque fois que la routine IoTimer est appelée, elle vérifie si le compteur du minuteur a été réinitialisé par l’ISR à -1 et, si c’est le cas, retourne le contrôle. Si ce n’est pas le cas, la routine IoTimer utilise KeSynchronizeExecution pour appeler une SynchCritSection_2 routine, qui ajuste le compteur du minuteur selon un nombre de secondes déterminé par le pilote.

  5. La routine SynchCritSection_2 retourne TRUE à la routine IoTimer tant que la requête actuelle n’a pas encore expiré. Si le compteur du minuteur passe à zéro, la routine SynchCritSection_2 réinitialise le compteur du minuteur à une valeur de reset-timeout déterminée par le pilote, définit un indicateur de réinitialisation attendue pour lui-même (et pour DpcForIsr) dans sa zone de contexte, tente de réinitialiser l’appareil et retourne TRUE.

    La routine SynchCritSection_2 est appelée à nouveau si son opération de réinitialisation expire également sur l’appareil, lorsqu’elle retourne FALSE. Si sa réinitialisation réussit, la routine DpcForIsr détermine que l’appareil a été réinitialisé à partir de l’indicateur de réinitialisation attendue et tente à nouveau la requête, en répétant les actions de la routine StartIo , comme décrit à l’étape 2.

  6. Si la routine SynchCritSection_2 retourne FALSE, la routine IoTimer suppose que l’appareil physique est dans un état inconnu, car une tentative de réinitialisation a déjà échoué. Dans ces circonstances, la routine IoTimer met en file d’attente une routine CustomDpc et retourne. Cette routine CustomDpc journalise une erreur d’E/S d’appareil, appelle IoStartNextPacket, échoue à l’IRP actuel et retourne.

Si l’ISR de ce pilote de périphérique réinitialise le compteur du minuteur partagé à -1, comme décrit à l’étape 3, la routine DpcForIsr du pilote termine le traitement des E/S pilotées par interruption de l’IRP actuelle. Le compteur du minuteur de réinitialisation indique que cette opération d’E/S d’appareil n’a pas expiré, de sorte que la routine IoTimer n’a pas besoin de modifier le compteur du minuteur.

Dans la plupart des cas, la routine SynchCritSection_2 précédente décrémente simplement le compteur du minuteur. La routine SynchCritSection_2 tente de réinitialiser l’appareil uniquement si l’opération d’E/S en cours a expiré, ce qui est indiqué lorsque le compteur du minuteur passe à zéro. Et ce n’est que si une tentative de réinitialisation de l’appareil a déjà échoué que la routine SynchCritSection_2 retourne FALSE à la routine IoTimer .

Par conséquent, l’exécution de la routine IoTimer précédente et de son assistance SynchCritSection_2 routine prend très peu de temps dans des circonstances normales. En utilisant une routine IoTimer de cette manière, un pilote de périphérique garantit que chaque demande d’E/S d’appareil valide peut être retentée, si nécessaire, et qu’une routine CustomDpc échouera à une IRP uniquement si une défaillance matérielle non correctable empêche l’IRP d’être satisfaite. En outre, le pilote fournit cette fonctionnalité à un coût très faible dans le temps d’exécution.

La simplicité du scénario précédent dépend d’un appareil qui effectue une seule opération à la fois et d’un pilote qui ne chevauche normalement pas les opérations d’E/S. Un pilote qui effectue des opérations d’E/S d’appareil qui se chevauchent, ou un pilote de niveau supérieur qui utilise une routine IoTimer pour expirer un ensemble d’IRP alloués par le pilote envoyés à plusieurs chaînes de pilotes inférieurs, aurait des scénarios d’expiration plus complexes à gérer.