Utilisation d’éléments de travail d’infrastructure

Un élément de travail est une tâche qu’un pilote effectue dans une fonction de rappel d’événement EvtWorkItem . Ces fonctions s’exécutent de manière asynchrone, à IRQL = PASSIVE_LEVEL, dans le contexte d’un thread de travail système.

Les pilotes basés sur l’infrastructure utilisent généralement des éléments de travail si une fonction EvtInterruptDpc ou EvtDpcFunc , qui s’exécute à IRQL = DISPATCH_LEVEL, doit effectuer un traitement supplémentaire à IRQL = PASSIVE_LEVEL.

En d’autres termes, un pilote peut utiliser des éléments de travail si une fonction qui s’exécute à IRQL = DISPATCH_LEVEL doit appeler une fonction qui ne peut être appelée qu’à l’adresse IRQL = PASSIVE_LEVEL.

En règle générale, la fonction de rappel EvtInterruptDpc ou EvtDpcFunc d’un pilote crée un objet d’élément de travail et l’ajoute à la file d’attente d’éléments de travail du système. Par la suite, un thread de travail système fait la file d’attente de l’objet et appelle la fonction de rappel EvtWorkItem de l’élément de travail.

Exemples de pilotes qui utilisent des éléments de travail

Les exemples de pilotes basés sur l’infrastructure qui utilisent des éléments de travail incluent 1394, AMCC5933, PCIDRV et Grille-pain.

Configuration d’un élément de travail

Pour configurer un élément de travail, votre pilote doit :

  1. Créez l’élément de travail.

    Votre pilote appelle WdfWorkItemCreate pour créer un objet d’élément de travail et pour identifier une fonction de rappel EvtWorkItem qui traitera l’élément de travail.

  2. Stockez des informations sur l’élément de travail.

    En règle générale, les pilotes utilisent la mémoire contextuelle de l’objet élément de travail pour stocker des informations sur la tâche que la fonction de rappel EvtWorkItem doit effectuer. Lorsque la fonction de rappel EvtWorkItem est appelée, elle peut récupérer les informations en accédant à cette mémoire contextuelle. Pour plus d’informations sur l’allocation et l’accès à la mémoire contextuelle, consultez Espace de contexte d’objet Framework.

  3. Ajoutez l’élément de travail à la file d’attente d’éléments de travail du système.

    Votre pilote appelle WdfWorkItemEnqueue, ce qui ajoute l’élément de travail du pilote à la file d’attente d’éléments de travail.

Lorsque votre pilote appelle WdfWorkItemCreate, il doit fournir un handle à un objet d’appareil framework ou à un objet de file d’attente d’infrastructure. Lorsque le système supprime cet objet, il supprime également tous les éléments de travail existants associés à l’objet. L’objet élément de travail sera supprimé et son rappel d’élément de travail associé sera nettoyé avant l’appel du rappel EvtCleanupCallback de l’objet parent.

Pour plus d’informations sur les règles de nettoyage d’une hiérarchie d’objets framework, consultez Framework Object Life Cycle.

Utilisation de la fonction de rappel Work-Item

Une fois l’élément de travail ajouté à la file d’attente d’éléments de travail, il reste dans la file d’attente jusqu’à ce qu’un thread worker système soit disponible. Le thread de travail système supprime l’élément de travail de la file d’attente, puis appelle la fonction de rappel EvtWorkItem du pilote, en passant l’objet élément de travail comme entrée.

En règle générale, la fonction de rappel EvtWorkItem effectue les étapes suivantes :

  1. Obtient des informations fournies par le pilote sur l’élément de travail en accédant à la mémoire contextuelle de l’objet élément de travail.

  2. Exécute la tâche que vous avez spécifiée. Si nécessaire, la fonction de rappel peut appeler WdfWorkItemGetParentObject pour déterminer l’objet parent de l’élément de travail.

  3. Appelle WdfObjectDelete pour supprimer l’objet élément de travail ou, si le pilote met en file d’attente de nouveau l’élément de travail, indique que le handle de l’élément de travail est désormais disponible pour réutilisation.

La tâche effectuée par la fonction de rappel de chaque élément de travail doit être relativement courte. Le système d’exploitation fournit un nombre limité de threads de travail système, de sorte que votre pilote peut nuire aux performances du système s’il utilise des fonctions de rappel d’élément de travail pour effectuer des tâches chronophages.

Création et suppression d’éléments de travail

Les pilotes peuvent utiliser l’une des deux techniques suivantes pour créer et supprimer des éléments de travail :

  • Utilisez chaque élément de travail une fois : créez l’élément de travail quand vous en avez besoin et supprimez-le immédiatement après son utilisation.

    Cette technique est utile pour les pilotes qui nécessitent une utilisation peu fréquente (moins d’une fois par minute) d’un petit nombre d’éléments de travail.

    Par exemple, la fonction de rappel EvtInterruptDpc d’un pilote peut appeler WdfWorkItemCreate , puis WdfWorkItemEnqueue, et la fonction de rappel EvtWorkItem de l’élément de travail peut appeler WdfObjectDelete.

    Si votre pilote suit ce scénario et si sa fonction de rappel EvtInterruptDpc reçoit une valeur de retour STATUS_INSUFFICIENT_RESOURCES de WdfWorkItemCreate, le pilote doit être en mesure de reporter le travail requis jusqu’à ce que les ressources système (généralement la mémoire) soient disponibles.

  • Créez un ou plusieurs éléments de travail que votre pilote met en file d’attente si nécessaire.

    Cette technique est utile pour les pilotes qui utilisent fréquemment des éléments de travail (plus d’une fois par minute), ou si la fonction de rappel EvtInterruptDpc de votre pilote ne peut pas facilement gérer une valeur de retour STATUS_INSUFFICIENT_RESOURCES de WdfWorkItemCreate.

    Le système n’alloue pas de thread worker à un élément de travail tant que le pilote n’appelle pas WdfWorkItemEnqueue. Par conséquent, même si les threads de travail système sont une ressource limitée, la création d’éléments de travail lors de l’initialisation d’un appareil consomme une petite quantité de mémoire, mais n’affecte pas les performances du système.

    Les étapes suivantes décrivent un scénario possible :

    1. La fonction de rappel EvtDriverDeviceAdd d’un pilote appelle WdfWorkItemCreate pour obtenir un handle d’élément de travail.
    2. La fonction de rappel EvtInterruptDpc du pilote crée une liste d’actions que la fonction de rappel EvtWorkItem doit effectuer, puis appelle WdfWorkItemEnqueue, à l’aide du handle de l’étape 1.
    3. La fonction de rappel EvtWorkItem du pilote exécute la liste des actions et définit un indicateur pour indiquer que la fonction de rappel a été exécutée.

    Par la suite, chaque fois que la fonction de rappel EvtInterruptDpc du pilote est appelée, elle doit déterminer si la fonction de rappel EvtWorkItem a été exécutée. Si la fonction de rappel EvtWorkItem n’a pas été exécutée, la fonction de rappel EvtInterruptDpc n’appelle pas WdfWorkItemEnqueue, car l’élément de travail est toujours en file d’attente. Dans ce cas, la fonction de rappel EvtInterruptDpc met uniquement à jour la liste des actions pour la fonction de rappel EvtWorkItem .

    Chaque élément de travail est associé à un appareil ou à une file d’attente. Lorsque l’appareil ou la file d’attente associé est supprimé, l’infrastructure supprime tous les éléments de travail associés. Par conséquent, si vous utilisez cette technique, le pilote n’a pas besoin d’appeler WdfObjectDelete.

Certains pilotes peuvent avoir besoin d’appeler WdfWorkItemFlush pour vider leurs éléments de travail de la file d’attente d’éléments de travail. Pour obtenir un exemple d’utilisation de WdfWorkItemFlush, consultez la page de référence de la méthode.

Si le pilote appelle WdfObjectDelete sur un élément de travail en suspens, le résultat dépend de l’état de l’élément de travail :

État de l'élément de travail Résultats
Créé mais pas en file d’attente L’élément de travail est nettoyé immédiatement.
mis en file d'attente L’appel à WdfObjectDelete attend que l’élément de travail termine l’exécution, puis l’élément de travail est nettoyé
En cours d'exécution Si le pilote appelle WdfObjectDelete à partir d’EvtWorkItem (sur le même thread), WdfObjectDelete retourne immédiatement. Une fois EvtWorkItem terminé, l’élément de travail est nettoyé. Sinon, WdfObjectDelete attend la fin d’EvtWorkItem.