Présentation des objets de répartiteur de noyau
Le noyau définit un ensemble de types d’objets appelés objets de répartiteur de noyau, ou simplement des objets de répartiteur. Les objets dispatcher incluent les objets minuteur, les objets d’événement, les objets de sémaphore, les objets mutex et les objets thread.
Les pilotes peuvent utiliser des objets de répartiteur comme mécanismes de synchronisation dans un contexte de thread non linéaire lors de l’exécution à l’irQL égal à PASSIVE_LEVEL.
États de l’objet Dispatcher
Chaque type d’objet dispatcher défini par le noyau a un état qui est défini sur Signaled ou sur Not-Signaled.
Un groupe de threads peut synchroniser leurs opérations si un ou plusieurs threads appellent KeWaitForSingleObject, KeWaitForMutexObjects ou KeWaitForMultipleObjects. Ces fonctions prennent des pointeurs d’objets de répartiteur en tant qu’entrée et attendent qu’une autre routine ou thread définisse un ou plusieurs objets de répartiteur à l’état Signaled.
Lorsqu’un thread appelle KeWaitForSingleObject pour attendre un objet de répartiteur (ou KeWaitForMutexObject pour un mutex), le thread est placé dans un état d’attente jusqu’à ce que l’objet répartiteur soit défini sur l’état Signaled. Un thread peut appeler KeWaitForMultipleObjects pour attendre que tout ou partie d’un ensemble d’objets de répartiteur soit défini sur Signaled.
Chaque fois qu’un objet de répartiteur est défini sur l’état Signaled, le noyau change l’état de n’importe quel thread qui attend que cet objet soit prêt. (Les minuteurs de synchronisation et les événements de synchronisation sont des exceptions à cette règle ; lorsqu’un événement ou un minuteur de synchronisation est signalé, un seul thread d’attente est défini à l’état prêt. Pour plus d’informations, consultez Timer Objects and DPCs and Event Objects.) Un thread à l’état prêt sera planifié pour s’exécuter en fonction de sa priorité de thread d’exécution actuelle et de la disponibilité actuelle des processeurs pour tout thread ayant cette priorité.
Quand les pilotes peuvent-ils attendre des objets dispatcher ?
En général, les pilotes peuvent attendre que les objets de répartiteur soient définis uniquement si au moins une des circonstances suivantes est vraie :
Le pilote s’exécute dans un contexte de thread non linéaire.
Autrement dit, vous pouvez identifier le thread qui entrera dans un état d’attente. Dans la pratique, les seules routines de pilotes qui s’exécutent dans un contexte de thread non linéaire sont les routines DriverEntry, AddDevice, Reinitialize et Unload de n’importe quel pilote, ainsi que les routines de répartition des pilotes de niveau supérieur. Toutes ces routines sont appelées directement par le système.
Le pilote effectue une demande d’E/S entièrement synchrone.
Autrement dit, aucun pilote ne met en file d’attente les opérations lors de la gestion de la demande d’E/S et aucun pilote ne retourne tant que le pilote en dessous n’a pas terminé de gérer la demande.
En outre, un pilote ne peut pas entrer dans un état d’attente s’il s’exécute à la valeur IRQL égale ou supérieure à DISPATCH_LEVEL.
En fonction de ces limitations, vous devez utiliser les règles suivantes :
Les routines DriverEntry, AddDevice, Reinitialize et Unload de n’importe quel pilote peuvent attendre des objets de répartiteur.
Les routines de répartition d’un pilote de niveau supérieur peuvent attendre les objets de répartiteur.
Les routines de répartition des pilotes de niveau inférieur peuvent attendre des objets de répartition, si l’opération d’E/S est synchrone, comme les opérations de création, de vidage, d’arrêt et de fermeture, certaines opérations de contrôle d’E/S d’appareil et certaines opérations PnP et d’alimentation.
Les routines de répartition des pilotes de niveau inférieur ne peuvent pas attendre qu’un objet de répartiteur soit terminé des opérations d’E/S asynchrones.
Une routine de pilote qui s’exécute à un DISPATCH_LEVEL IRQL ou au-dessus ne doit pas attendre qu’un objet de répartiteur soit défini sur l’état Signaled.
Un pilote ne doit pas tenter d’attendre qu’un objet de répartiteur soit défini à l’état Signaled pour l’achèvement d’une opération de transfert vers ou à partir d’un périphérique de pagination.
Les routines de répartition des pilotes ne peuvent généralement pas attendre qu’un objet de répartiteur soit défini sur l’état Signaled.
Une routine de répartition pour une demande de contrôle d’E/S d’appareil peut attendre qu’un objet de répartiteur soit défini sur l’état Signaled uniquement si le type de transfert pour le code de contrôle d’E/S est METHOD_BUFFERED.
Les pilotes miniports SCSI ne doivent pas utiliser d’objets de répartiteur de noyau. Les pilotes miniports SCSI doivent appeler uniquement les routines de bibliothèque de ports SCSI.
Toutes les autres routines de pilote standard s’exécutent dans un contexte de thread arbitraire : celui de n’importe quel thread qui se trouve être actif lorsque la routine de pilote est appelée pour traiter une opération en file d’attente ou pour gérer une interruption d’appareil. En outre, la plupart des routines de pilotes standard sont exécutées à un NIVEAU DIRQL élevé, soit à DISPATCH_LEVEL, soit pour les pilotes de périphérique.
Si nécessaire, un pilote peut créer un thread dédié à l’appareil, qui peut attendre que les autres routines du pilote (à l’exception d’une routine ISR ou SynchCritSection ) définissent un objet répartiteur à l’état Signaled et réinitialisent l’état Not-Signaled.
En règle générale, si vous vous attendez à ce que votre nouveau pilote de périphérique ait souvent besoin de caler pendant plus de 50 microsecondes pendant qu’il attend les changements d’état de l’appareil pendant les opérations d’E/S, envisagez d’implémenter un pilote avec un thread dédié à l’appareil. Si le pilote de périphérique est également un pilote de niveau supérieur, envisagez d’utiliser des threads de travail système et d’implémenter une ou plusieurs routines de rappel de threads de travail. Consultez PsCreateSystemThread et Gestion des files d’attente verrouillées avec un thread Driver-Created.