Not
Åtkomst till denna sida kräver auktorisation. Du kan prova att logga in eller byta katalog.
Åtkomst till denna sida kräver auktorisation. Du kan prova att byta katalog.
En minnesbufferts livscykel sträcker sig över tiden från när bufferten skapas till när den tas bort. I det här avsnittet beskrivs scenarier för buffertanvändning och hur de påverkar när bufferten tas bort.
I drivrutinsramverket i kernelläge (KMDF) representerar ett begärandeobjekt en I/O-begäran. Varje begärandeobjekt är associerat med ett eller flera minnesobjekt, och varje minnesobjekt representerar en buffert som används för in- eller utdata i begäran.
När ramverket skapar begärande- och minnesobjekt för att representera en inkommande I/O-begäran, anger det begärandeobjektet som överordnat för de associerade minnesobjekten. Minnesobjektet kan därför inte bevaras längre än begärandeobjektets livslängd. När den ramverksbaserade drivrutinen slutför I/O-begäran tar ramverket bort begärandeobjektet och minnesobjektet, så handtagen till dessa två objekt blir ogiltiga.
Den underliggande bufferten är dock annorlunda. Beroende på vilken komponent som skapade bufferten och hur bufferten skapades kan bufferten ha ett referensantal och ägas av minnesobjektet, eller så kanske den inte. Om minnesobjektet äger bufferten har bufferten ett referensantal och dess livslängd är begränsad till minnesobjektets. Om någon annan komponent skapade bufferten är livslängden för bufferten och minnesobjektet inte relaterade.
En ramverksbaserad drivrutin kan också skapa egna begärandeobjekt som ska skickas till I/O-mål. En begäran som skapats av drivrutinen kan återanvända ett befintligt minnesobjekt som drivrutinen tog emot i en I/O-begäran. En drivrutin som ofta skickar begäranden till I/O-mål kan återanvända de begärandeobjekt som skapas.
Att förstå livslängden för begärandeobjektet, minnesobjektet och den underliggande bufferten är viktigt för att säkerställa att drivrutinen inte försöker referera till en ogiltig referens eller buffertpekare.
Tänk på följande användningsscenarier:
- Scenario 1: Drivrutinen tar emot en I/O-begäran från KMDF, hanterar den och slutför den.
- Scenario 2: Drivrutinen tar emot en I/O-begäran från KMDF och skickar den vidare till ett I/O-mål.
- Scenario 3: Drivrutinen gör en I/O-begäran som använder ett befintligt minnesobjekt.
- Scenario 4: Drivrutinen utfärdar en I/O-begäran som använder ett nytt minnesobjekt.
- Scenario 5: Drivrutinen återanvänder ett begärandeobjekt som den skapade.
Scenario 1: Drivrutin tar emot en I/O-begäran från KMDF, hanterar den och slutför den.
I det enklaste scenariot skickar KMDF en begäran till drivrutinen, som utför I/O och slutför begäran. I det här fallet kan den underliggande bufferten ha skapats av ett användarlägesprogram, av en annan drivrutin eller av själva operativsystemet. Information om hur du kommer åt buffertar finns i Komma åt databuffertar i Framework-Based drivrutiner.
När drivrutinen slutför begäran tar ramverket bort minnesobjektet. Buffertpekaren är sedan ogiltig.
Scenario 2: Drivrutinen tar emot en I/O-begäran från KMDF och vidarebefordrar den till ett I/O-mål.
I det här scenariot skickar drivrutinen vidare begäran till ett I/O-mål. Följande exempelkod visar hur en drivrutin hämtar en referens till minnesobjektet från ett inkommande begärandeobjekt, formaterar begäran om att skicka till I/O-målet och skickar begäran:
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;
}
När I/O-målet har slutfört begäran, anropar ramverket den slutföringsåterkoppling som drivrutinen angav för begäran. Följande kod visar en enkel completion callback-funktion:
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;
}
När drivrutinen anropar WdfRequestComplete från sitt slutföringsåteranrop tar ramverket bort minnesobjektet. Handtaget till minnesobjektet som drivrutinen hämtade är nu ogiltigt.
Scenario 3: Drivrutinen utfärdar en I/O-begäran som använder ett befintligt minnesobjekt.
Vissa drivrutiner utfärdar sina egna I/O-begäranden och skickar dem till I/O-mål, som representeras av I/O-målobjekt. Drivrutinen kan antingen skapa ett eget begärandeobjekt eller återanvända ett ramverksskapad begärandeobjekt. Med någon av teknikerna kan en drivrutin återanvända ett minnesobjekt från en tidigare begäran. Drivrutinen får inte ändra den underliggande bufferten, men den kan skicka en buffertförskjutning när den formaterar den nya I/O-begäran.
Information om hur du formaterar en ny I/O-begäran som använder ett befintligt minnesobjekt finns i Skicka I/O-begäranden till allmänna I/O-mål.
När ramverket formaterar begäran om att skicka till I/O-målet tar det fram en referens för det återvunna minnesobjektet för I/O-målobjektets räkning. I/O-målobjektet behåller den här referensen tills någon av följande åtgärder inträffar:
- Begäran har slutförts.
- Drivrutinen formaterar om begärandeobjektet igen genom att anropa någon av metoderna WdfIoTargetFormatRequestXxx eller WdfIoTargetSendXxxSynchronously . Mer information om dessa metoder finns i Ramverks-I/O-målobjektmetoder.
- Drivrutinen anropar WdfRequestReuse.
När den nya I/O-begäran är slutförd kallar ramverket på den återanropsfunktion för I/O-slutförande som drivrutinen har angivit för denna begäran. I det här läget innehåller I/O-målobjektet fortfarande en referens för minnesobjektet. I återanropet för I/O-slutförande måste drivrutinen därför anropa WdfRequestReuse på det drivrutinsskapade begärandeobjektet innan den slutför den ursprungliga begäran som det hämtade minnesobjektet från. Om drivrutinen inte anropar WdfRequestReuse, inträffar en felkontroll på grund av den extra referensen.
Scenario 4: Drivrutinen utfärdar en I/O-begäran som använder ett nytt minnesobjekt.
Ramverket ger tre sätt för drivrutiner att skapa nya minnesobjekt, beroende på källan till den underliggande bufferten. Mer information finns i Använda minnesbuffertar.
Om bufferten allokeras av ramverket eller från en drivrutinsskapad lookaside-lista äger minnesobjektet bufferten, så buffertpekaren förblir giltig så länge minnesobjektet finns. Drivrutiner som utfärdar asynkrona I/O-begäranden bör alltid använda buffertar som ägs av minnesobjekt så att ramverket kan se till att buffertarna bevaras tills I/O-begäran har slutförts tillbaka till den utfärdande drivrutinen.
Om drivrutinen tilldelar en tidigare allokerad buffert till ett nytt minnesobjekt genom att anropa WdfMemoryCreatePreallocated äger minnesobjektet inte bufferten. I det här fallet är livslängden för minnesobjektet och livslängden för den underliggande bufferten inte relaterade. Drivrutinen måste hantera buffertens livslängd och får inte försöka använda en ogiltig buffertpekare.
Scenario 5: Drivrutinen återanvänder ett begärandeobjekt som den skapade.
En drivrutin kan återanvända de begärandeobjekt som skapas, men den måste initiera om varje sådant objekt genom att anropa WdfRequestReuse innan varje återanvändning. Mer information finns i Återanvända ramverksbegärandeobjekt.
Exempelkod som startar om ett begärandeobjekt finns i exemplen Toaster och NdisEdge som medföljer KMDF-versionen.