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.
Le cycle de vie d’un tampon mémoire s’étend de sa création à sa suppression. Cette rubrique décrit les scénarios d’utilisation des mémoires tampons et leur impact sur la suppression de la mémoire tampon.
Dans l’infrastructure de pilote en mode noyau (KMDF), un objet de requête représente une requête d’E/S. Chaque objet de requête est associé à un ou plusieurs objets mémoire, et chaque objet mémoire représente une mémoire tampon utilisée pour l’entrée ou la sortie dans la requête.
Lorsque l’infrastructure crée des objets de requête et de mémoire pour représenter une requête d’E/S entrante, elle définit l’objet de requête comme parent des objets mémoire associés. Par conséquent, l’objet mémoire ne peut conserver plus que la durée de vie de l’objet de requête. Lorsque le pilote basé sur l’infrastructure termine la requête d’E/S, l’infrastructure supprime l’objet de requête et l’objet mémoire, de sorte que les handles de ces deux objets deviennent non valides.
Toutefois, la mémoire tampon sous-jacente est différente. Selon le composant qui a créé la mémoire tampon et la façon dont il a créé la mémoire tampon, la mémoire tampon peut avoir un nombre de références et peut être détenue par l’objet mémoire, ou non. Si l’objet mémoire possède la mémoire tampon, la mémoire tampon a un nombre de références et sa durée de vie est limitée à celle de l’objet mémoire. Si un autre composant a créé la mémoire tampon, les durées de vie de la mémoire tampon et l’objet mémoire ne sont pas associées.
Un pilote basé sur l’infrastructure peut également créer ses propres objets de requête à envoyer à des cibles d’E/S. Une demande créée par un pilote peut réutiliser un objet mémoire existant reçu par le pilote dans une requête d’E/S. Un pilote qui envoie fréquemment des requêtes à des cibles d’E/S peut réutiliser les objets de requête qu’il crée.
Comprendre les durées de vie de l’objet de requête, l’objet mémoire et la mémoire tampon sous-jacente est important pour vous assurer que votre pilote ne tente pas de référencer un handle ou un pointeur de mémoire tampon non valide.
Tenez compte des scénarios d’utilisation suivants :
- Scénario 1 : Le pilote reçoit une requête d’E/S à partir de KMDF, la gère et la termine.
- Scénario 2 : Le pilote reçoit une requête d’E/S de KMDF et le transfère à une cible d’E/S.
- Scénario 3 : Le pilote émet une requête d’E/S qui utilise un objet mémoire existant.
- Scénario 4 : Le pilote émet une requête d’E/S qui utilise un nouvel objet mémoire.
- Scénario 5 : Le pilote réutilise un objet de requête qu’il a créé.
Scénario 1 : Le pilote reçoit une requête d’E/S à partir de KMDF, la gère et la termine.
Dans le scénario le plus simple, KMDF distribue une requête au pilote, qui effectue des E/S et termine la requête. Dans ce cas, la mémoire tampon sous-jacente peut avoir été créée par une application en mode utilisateur, par un autre pilote ou par le système d’exploitation lui-même. Pour plus d’informations sur l’accès aux mémoires tampons, consultez Accès aux mémoires tampons de données dans Framework-Based Pilotes.
Lorsque le pilote termine la requête, l’infrastructure supprime l’objet mémoire. Le pointeur de la mémoire tampon devient alors invalide.
Scénario 2 : Le pilote reçoit une requête d’E/S de KMDF et le transfère à une cible d’E/S.
Dans ce scénario, le pilote transfère la requête à une cible d’E/S. L’exemple de code suivant montre comment un pilote récupère un handle à l’objet mémoire à partir d’un objet de requête entrant, met en forme la requête à envoyer à la cible d’E/S et envoie la requête :
VOID
EvtIoRead(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
{
NTSTATUS status;
WDFMEMORY memory;
WDFIOTARGET ioTarget;
BOOLEAN ret;
ioTarget = WdfDeviceGetIoTarget(WdfIoQueueGetDevice(Queue));
status = WdfRequestRetrieveOutputMemory(Request, &memory);
if (!NT_SUCCESS(status)) {
goto End;
}
status = WdfIoTargetFormatRequestForRead(ioTarget,
Request,
memory,
NULL,
NULL);
if (!NT_SUCCESS(status)) {
goto End;
}
WdfRequestSetCompletionRoutine(Request,
RequestCompletionRoutine,
WDF_NO_CONTEXT);
ret = WdfRequestSend (Request, ioTarget, WDF_NO_SEND_OPTIONS);
if (!ret) {
status = WdfRequestGetStatus (Request);
goto End;
}
return;
End:
WdfRequestComplete(Request, status);
return;
}
Lorsque la cible d’E/S a terminé la requête, le cadre appelle le rappel d’achèvement défini par le pilote pour la requête. Le code suivant montre un rappel de complétion simple :
VOID
RequestCompletionRoutine(
IN WDFREQUEST Request,
IN WDFIOTARGET Target,
PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,
IN WDFCONTEXT Context
)
{
UNREFERENCED_PARAMETER(Target);
UNREFERENCED_PARAMETER(Context);
WdfRequestComplete(Request, CompletionParams->IoStatus.Status);
return;
}
Lorsque le pilote appelle WdfRequestComplete depuis son rappel d’achèvement, le cadre supprime l’objet mémoire. Le handle d’objet mémoire récupéré par le pilote n’est plus valide.
Scénario 3 : Le pilote émet une requête d’E/S qui utilise un objet mémoire existant.
Certains pilotes émettent leurs propres demandes d’E/S et les envoient à des cibles d’E/S, qui sont représentées par des objets cibles d’E/S. Le pilote peut créer son propre objet de requête ou réutiliser un objet de requête créé par l’infrastructure. À l’aide de l’une ou l’autre technique, un pilote peut réutiliser un objet mémoire à partir d’une requête précédente. Le pilote ne doit pas modifier la mémoire tampon sous-jacente, mais il peut passer un décalage de mémoire tampon lorsqu’il met en forme la nouvelle requête d’E/S.
Pour plus d’informations sur la mise en forme d’une nouvelle requête d’E/S qui utilise un objet mémoire existant, consultez Envoi de requêtes d’E/S à des cibles d’E/S générales.
Lorsque l’infrastructure met en forme la requête à envoyer à la cible d’E/S, elle retire une référence sur l’objet mémoire recyclé au nom de l’objet cible d’E/S. L’objet cible d’E/S conserve cette référence jusqu’à ce que l’une des actions suivantes se produise :
- La demande a été terminée.
- Le pilote réforme l’objet de requête en appelant l’une des méthodes WdfIoTargetFormatRequestXxx ou WdfIoTargetSendXxxSynchronously . Pour plus d’informations sur ces méthodes, consultez Méthodes d’objet cible d’infrastructure d’E/S.
- Le pilote appelle WdfRequestReuse.
Une fois la nouvelle requête d’E/S terminée, le framework appelle le rappel d’achèvement d’E/S défini par le pilote pour cette demande. À ce stade, l’objet cible d’E/S contient toujours une référence sur l’objet mémoire. Par conséquent, dans le rappel d’achèvement d’E/S, le pilote doit appeler WdfRequestReuse sur l’objet de requête créé par le pilote avant de terminer la requête d’origine à partir de laquelle il a récupéré l’objet mémoire. Si le pilote n’appelle pas WdfRequestReuse, une vérification de bogue se produit en raison de la référence supplémentaire.
Scénario 4 : Le pilote émet une requête d’E/S qui utilise un nouvel objet mémoire.
L’infrastructure fournit trois façons aux pilotes de créer de nouveaux objets mémoire, en fonction de la source de la mémoire tampon sous-jacente. Pour plus d’informations, consultez Utilisation des mémoires tampons.
Si la mémoire tampon est allouée par l’infrastructure ou à partir d’une liste lookaside créée par le pilote, l’objet mémoire possède la mémoire tampon, de sorte que le pointeur de la mémoire tampon reste valide tant que l’objet mémoire existe. Les pilotes qui émettent des requêtes d’E/S asynchrones doivent toujours utiliser des mémoires tampons appartenant à des objets mémoire afin que l’infrastructure puisse s’assurer que les mémoires tampons persistent jusqu’à ce que la demande d’E/S soit rétablie au pilote émettrice.
Si le pilote affecte une mémoire tampon allouée précédemment à un nouvel objet mémoire en appelant WdfMemoryCreatePreallocated, l’objet mémoire ne possède pas la mémoire tampon. Dans ce cas, la durée de vie de l’objet mémoire et la durée de vie de la mémoire tampon sous-jacente ne sont pas liées. Le pilote doit gérer la durée de vie de la mémoire tampon et ne doit pas tenter d’utiliser un pointeur de mémoire tampon non valide.
Scénario 5 : Le pilote réutilise un objet de requête qu’il a créé.
Un pilote peut réutiliser les objets de requête qu’il crée, mais il doit réinitialiser chaque objet de ce type en appelant WdfRequestReuse avant chaque réutilisation. Pour plus d’informations, consultez Réutilisez les objets de requête d’infrastructure.
Pour obtenir un exemple de code qui réinitialise un objet de requête, consultez les exemples Grille-pain et NdisEdge fournis avec la version KMDF.