Utilisation d’éléments de travail Framework

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 façon asynchrone, au niveau IRQL = PASSIVE_LEVEL, dans le contexte d’un thread de travail système.

Les pilotes basés sur un Framework utilisent couramment des éléments de travail si une fonction EvtInterruptDpc ou EvtDpcFunc , qui s’exécute à l’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 à l’IRQL = DISPATCH_LEVEL doit appeler une fonction qui ne peut être appelée qu’à l’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 des éléments de travail du système. Par la suite, un thread de travail système défile 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 un Framework qui utilisent des éléments de travail sont 1394, AMCC5933, PCIDRV et toaster.

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. Stocker des informations sur l’élément de travail.

    En règle générale, les pilotes utilisent la mémoire de contexte de l’objet d’é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 de contexte. Pour plus d’informations sur l’allocation et l’accès à la mémoire de contexte, consultez espace de contexte de l' objet Framework.

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

    Votre pilote appelle WdfWorkItemEnqueue, qui ajoute l’élément de travail du pilote à la file d’attente des é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 qui sont associés à l’objet. L’objet d’é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 cycle de vie d’un objet Framework.

Utilisation de la fonction de rappel Work-Item

Une fois que l’élément de travail a été ajouté à la file d’attente des éléments de travail, il reste dans la file d’attente jusqu’à ce qu’un thread de travail 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 d’élément de travail en tant qu’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 de contexte de l’objet d’é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 d’élément de travail ou, si le pilote remettra en file d’attente l’élément de travail, indique que le handle de l’élément de travail peut désormais être réutilisé.

La tâche que chaque fonction de rappel de l’élément de travail exécute doit être relativement brève. Le système d’exploitation fournit un nombre limité de threads de travail système. par conséquent, votre pilote peut entraver les performances du système s’il utilise des fonctions de rappel d’élément de travail pour effectuer des tâches qui prennent du temps.

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 :

  • Utiliser chaque élément de travail une fois : créez l’élément de travail lorsque vous en avez besoin et supprimez-le immédiatement après l’avoir utilisé.

    Cette technique est utile pour les pilotes qui requièrent une utilisation peu fréquente (moins souvent qu’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 que la fonction de rappel EvtInterruptDpc reçoit une valeur de retour de STATUS_INSUFFICIENT_RESOURCES de WdfWorkItemCreate, le pilote doit pouvoir reporter le travail requis jusqu’à ce que les ressources système (en général la mémoire) soient disponibles.

  • Créez un ou plusieurs éléments de travail que votre pilote repasse 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 de travail à un élément de travail tant que le pilote n’a pas appelé WdfWorkItemEnqueue. Par conséquent, bien que les threads de travail système soient une ressource limitée, la création d’éléments de travail pendant 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 effectue 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 à jour uniquement 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 la file d’attente ou l’appareil 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 doivent peut-être appeler WdfWorkItemFlush pour vider leurs éléments de travail à partir de la file d’attente des é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ésultat
Créé mais pas mis en file d’attente L’élément de travail est immédiatement nettoyé.
mis en file d'attente L’appel à WdfObjectDelete attend la fin de l’exécution de l’élément de travail, puis l’élément de travail est nettoyé
En cours d'exécution Si le pilote appelle WdfObjectDelete à partir de EvtWorkItem (sur le même thread), WdfObjectDelete retourne immédiatement. Une fois EvtWorkItem terminé, l’élément de travail est nettoyé. Sinon, WdfObjectDelete attend que EvtWorkItem se termine.