Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les exemples suivants illustrent ce qu’un minidriver doit faire en ce qui concerne la synchronisation et inclut des exemples de cas où la synchronisation ne doit pas être utilisée :
Exemple 1 : Minidriver avec un ISR fonctionnel
Si la synchronisation des classes de flux est activée, tous les points d'entrée du mini-pilote sont appelés à un niveau IRQL augmenté, en utilisant KeSynchronizeExecution, ce qui signifie que le niveau IRQ de l'adaptateur et tous les niveaux IRQ inférieurs sont masqués lorsque le mini-pilote exécute son code. Par conséquent, il est impératif que le minidriver n’effectue qu’une petite quantité de travail dans ce mode.
Le minidriver ne doit pas exécuter de code qui prend généralement plus de 10 à 20 microsecondes à un IRQL élevé. Si vous utilisez la build de débogage de stream.sys, la classe de flux enregistre le temps passé au niveau IRQL élevé et déclenche une alerte si le pilote passe trop de temps là-bas. Si le minidriver a simplement besoin de programmer des registres DMA matériels pour une demande, ou de lire simplement des ports dans son ISR, il est généralement acceptable d’effectuer tout son traitement à un niveau IRQL élevé.
Si le minidriver doit effectuer un traitement qui prend plus de quelques microsecondes, par exemple un minidriver qui transfère des données via piO, le minidriver doit utiliser StreamClassCallAtNewPriority pour planifier un rappel DISPATCH_LEVEL. Dans la fonction de rappel, le minidriver peut prendre jusqu’à environ 1/2 à 1 milliseconde pour effectuer son traitement. Une chose à retenir lorsque vous êtes dans ce mode est que le rappel DISPATCH_LEVEL n'est pas synchronisé avec l’ISR.
Ce manque de synchronisation n’est pas un problème si le matériel reste stable lorsque le minidriver accède aux ressources (par exemple, les ports ou une file d’attente) pendant le rappel ainsi que dans l’ISR. Toutefois, si l’instabilité peut être un problème, le minidriver doit utiliser StreamClassCallAtNewPriority pour planifier un rappel haute priorité où le rappel DISPATCH_LEVEL touche les ressources partagées avec les ressources utilisées par l’ISR.
Notez qu’un rappel haute priorité équivaut à appeler KeSynchronizeExecution. KeSynchronizeExecution nécessite que le minidriver référence plusieurs paramètres que StreamClassCallAtNewPriority ne fait pas, mais en général, les deux entraînent le même comportement.
Si le minidriver n’a besoin que occasionnellement d’exécuter du code qui prend plus de 1/2 à 1 milliseconde, ou doit parfois appeler des services à PASSIVE_LEVEL (par exemple au moment de l’initialisation), la définition de StreamClassCallAtNewPriority sur LOW priority peut être utilisée pour acquérir un thread de travail PASSIVE_LEVEL. Notez qu’un rappel de faible priorité n’est pas synchronisé avec n’importe quoi et que le minidriver peut recevoir de nouvelles demandes (en supposant que le paramètre ReadyForNextRequest NotificationType est en attente) ou un appel ISR lors de l’exécution d’un rappel de faible priorité.
Exemple 2 : Minidriver sans ISR
Si la synchronisation des classes de flux est activée, tous les points d’entrée du minidriver sont appelés au niveau DISPATCH_LEVEL. Le minidriver peut effectuer le traitement d’environ 1/2 à 1 millisecondes sans avoir besoin d’ajuster la priorité. Si le minidriver n’a besoin que occasionnellement d’exécuter du code qui prend plus de 1/2 millisecondes, ou doit parfois appeler des services à PASSIVE_LEVEL (par exemple au moment de l’initialisation), StreamClassCallAtNewPriority avec faible priorité peut être utilisé pour acquérir un thread de travail PASSIVE_LEVEL. Notez qu’un rappel de faible priorité n’est pas synchronisé avec n’importe quoi et que le minidriver peut recevoir de nouvelles demandes (en supposant que le paramètre ReadyForNextRequest NotificationType est en attente) lors de l’exécution d’un rappel de faible priorité.
Quand la synchronisation de classes de flux ne doitpasêtre utilisée
Voici des exemples de situations où la synchronisation de classes de flux ne doit pas être utilisée. Voici quelques-uns des éléments suivants :
Lorsque les pilotes fréquemment (plus de 20 % des demandes reçues par le minidriver) doivent effectuer le traitement qui prend plus de 1 milliseconde ou doivent appeler fréquemment des services PASSIVE_LEVEL, tels que les services Microsoft DirectDraw. Lors de l’utilisation de la version de débogage de stream.sys, la classe de flux déclare ces deux cas et s’arrête si elles sont détectées avec la synchronisation activée.
Lorsque le minidriver est un filtre sans matériel associé. Un tel minidriver doit s’exécuter à PASSIVE_LEVEL, car il n’existe aucun matériel sous-jacent à synchroniser avec et le minidriver effectue généralement beaucoup de traitement. Il est plus facile d’effectuer votre propre synchronisation dans ce cas que de gaspiller des ressources supplémentaires en utilisant la synchronisation des classes de synchronisation de flux. Si nécessaire, utilisez des mutex pour protéger vos files d’attente.
Les bogues dans le code de synchronisation peuvent souvent être difficiles à trouver et, dans certains environnements (tels que les systèmes d’exploitation basés sur NT s’exécutant sur des systèmes multiprocesseurs), les bogues peuvent apparaître uniquement après de nombreuses heures de stress. D'après l'expérience avec les fournisseurs, ce ne sont pas les types de questions que la plupart des fournisseurs souhaiteraient ou pourraient déboguer. Seuls les développeurs de pilotes familiarisés avec la rédaction de pilotes de périphériques WDM entièrement asynchrones doivent tenter d’effectuer leur propre synchronisation.
Lorsque le minidriver est un pilote de type bus-on-bus (par exemple, un pilote périphérique USB ou 1394) qui ne se préoccupe pas vraiment de la synchronisation du matériel réel, mais se contente de transmettre les requêtes à la couche suivante à PASSIVE_LEVEL et reçoit généralement des retours d'appel à DISPATCH_LEVEL.