Utilisation d’objets minuteur
La figure suivante illustre l’utilisation d’un minuteur de notification pour configurer un intervalle de délai d’expiration pour une opération, puis attendre que d’autres routines de pilote traitent une demande d’E/S.
Comme le montre la figure précédente, un pilote doit fournir un stockage pour l’objet minuteur, qui doit être initialisé par un appel à KeInitializeTimer avec un pointeur vers ce stockage. Un pilote effectue généralement cet appel à partir de sa routine AddDevice .
Dans le contexte d’un thread particulier, tel qu’un thread créé par un pilote ou un thread demandant une opération d’E/S synchrone, le pilote peut attendre son objet minuteur, comme illustré dans la figure précédente :
Le thread appelle KeSetTimer avec un pointeur vers l’objet minuteur et une valeur DueTime donnée, exprimée en unités de 100 nanosecondes. Une valeur positive pour DueTime spécifie une heure absolue à laquelle l’objet minuteur doit être supprimé de la file d’attente du minuteur du noyau et défini sur l’état Signaled. Une valeur négative pour DueTime spécifie un intervalle par rapport à l’heure système actuelle.
Notez que le thread (ou la routine de pilote s’exécutant dans un thread système) transmet un pointeur NULL pour l’objet DPC (illustré précédemment dans la figure illustrant l’utilisation d’objets minuteur et DPC pour une routine CustomTimerDpc) quand il appelle KeSetTimer s’il attend sur l’objet minuteur au lieu de mettre en file d’attente une routine CustomTimerDpc .
Le thread appelle KeWaitForSingleObject avec un pointeur vers l’objet minuteur, ce qui place le thread dans un état d’attente alors que l’objet minuteur se trouve dans la file d’attente du minuteur du noyau.
Le DueTime donné expire.
Le noyau met en file d’attente l’objet du minuteur, le définit à l’état Signaled et modifie l’état du thread d’attente à prêt.
Le noyau distribue le thread pour l’exécution dès qu’un processeur est disponible : autrement dit, aucun autre thread avec une priorité plus élevée n’est actuellement à l’état prêt et il n’existe aucune routine en mode noyau à exécuter à un IRQL plus élevé.
Les routines de pilote qui s’exécutent à IRQL >= DISPATCH_LEVEL peuvent expirer les demandes à l’aide d’un objet de minuteur avec un objet DPC associé pour mettre en file d’attente une routine CustomTimerDpc fournie par le pilote. Seules les routines de pilote qui s’exécutent dans un contexte de thread non linéaire peuvent attendre un intervalle différent de zéro sur un objet de minuteur, comme illustré dans la figure précédente.
Comme tout autre thread, un thread créé par un pilote est représenté par un objet thread de noyau, qui est également un objet répartiteur. Par conséquent, un pilote n’a pas besoin que son thread créé par le pilote utilise un objet minuteur pour se placer volontairement dans un état d’attente pour un intervalle donné. Au lieu de cela, le thread peut appeler KeDelayExecutionThread avec un intervalle fourni par l’appelant. Pour plus d’informations sur cette technique, consultez Interrogation d’un appareil.
Les routines DriverEntry, Reinitialize et Unload s’exécutent également dans un contexte de thread système, de sorte que les pilotes peuvent appeler KeWaitForSingleObject avec un objet de minuteur initialisé par le pilote ou KeDelayExecutionThread pendant l’initialisation ou le déchargement. Un pilote de périphérique peut appeler KeStallExecutionProcessor pendant un intervalle très court (de préférence inférieur à 50 microsecondes) s’il doit attendre que l’état de mise à jour de l’appareil pendant son initialisation.
Toutefois, les pilotes de niveau supérieur utilisent généralement un autre mécanisme de synchronisation dans leurs routines DriverEntry et Reinitialize au lieu d’utiliser un objet minuteur. Les pilotes de niveau supérieur doivent toujours être conçus pour se superposer sur n’importe quel pilote de niveau inférieur d’un type ou d’un type d’appareil particulier. Par conséquent, un pilote de niveau supérieur a tendance à être lent à charger s’il attend sur un objet minuteur ou appelle KeDelayExecutionThread , car un tel pilote doit attendre un intervalle suffisamment long pour prendre en charge le périphérique le plus lent possible. Notez également qu’un intervalle « sûr » mais minimal pour une telle attente est très difficile à déterminer.
De même, les pilotes PnP ne doivent pas attendre que d’autres actions se produisent, mais doivent utiliser le mécanisme de notification du gestionnaire PnP.