Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il ciclo di vita di un buffer di memoria si estende nel tempo trascorso dal momento in cui viene creato il buffer quando viene eliminato. In questo argomento vengono descritti gli scenari di utilizzo del buffer e il modo in cui influiscono sull'eliminazione del buffer.
Nel framework del driver in modalità kernel (KMDF), un oggetto richiesta rappresenta una richiesta di I/O. Ogni oggetto richiesta è associato a uno o più oggetti memoria e ogni oggetto memoria rappresenta un buffer utilizzato per l'input o l'output nella richiesta.
Quando il framework crea oggetti richiesta e memoria per rappresentare una richiesta di I/O in ingresso, imposta l'oggetto richiesta come padre degli oggetti memoria associati. Pertanto, l'oggetto memoria può rimanere persistente non più della durata dell'oggetto richiesta. Quando il driver basato su framework completa la richiesta di I/O, il framework elimina l'oggetto richiesta e l'oggetto memoria, quindi gli handle a questi due oggetti diventano non validi.
Tuttavia, il buffer sottostante è diverso. A seconda del componente che ha creato il buffer e del modo in cui ha creato il buffer, il buffer potrebbe avere un conteggio dei riferimenti e potrebbe essere di proprietà dell'oggetto memoria oppure potrebbe non essere. Se l'oggetto memoria è proprietario del buffer, il buffer ha un conteggio dei riferimenti e la sua durata è limitata a quella dell'oggetto memoria. Se un altro componente ha creato il buffer, le durate del buffer e dell'oggetto memoria non sono correlate.
Un driver basato su framework può anche creare le proprie richieste da inviare alle destinazioni di I/O. Una richiesta creata dal driver può riutilizzare un oggetto memoria esistente ricevuto dal driver in una richiesta di I/O. Un driver che invia spesso richieste alle destinazioni di I/O può riutilizzare gli oggetti richiesta creati.
Comprendere la durata dell'oggetto della richiesta, dell'oggetto di memoria e del buffer sottostante è importante per assicurarsi che il driver non tenti di riferirsi a un handle o a un puntatore al buffer non valido.
Considerare gli scenari di utilizzo seguenti:
- Scenario 1: il driver riceve una richiesta di I/O da KMDF, la gestisce e la completa.
- Scenario 2: il driver riceve una richiesta di I/O da KMDF e la inoltra a una destinazione di I/O.
- Scenario 3: il driver genera una richiesta di I/O che usa un oggetto memoria esistente.
- Scenario 4: il driver invia una richiesta di I/O che usa un nuovo oggetto memoria.
- Scenario 5: il driver riutilizza un oggetto richiesta creato.
Scenario 1: il driver riceve una richiesta di I/O da KMDF, la gestisce e la completa.
Nello scenario più semplice, KMDF invia una richiesta al driver, che esegue l'I/O e completa la richiesta. In questo caso, il buffer sottostante potrebbe essere stato creato da un'applicazione in modalità utente, da un altro driver o dal sistema operativo stesso. Per informazioni su come accedere ai buffer, vedere Accesso ai buffer di dati nei driver Framework-Based.
Quando il driver completa la richiesta, il framework elimina l'oggetto memoria. Il puntatore del buffer non è quindi valido.
Scenario 2: il driver riceve una richiesta di I/O da KMDF e la inoltra a una destinazione di I/O.
In questo scenario, il driver inoltra la richiesta a una destinazione di I/O. Il codice di esempio seguente mostra come un driver recupera un handle per l'oggetto memoria da un oggetto richiesta in ingresso, formatta la richiesta da inviare alla destinazione di I/O e invia la richiesta:
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;
}
Quando la destinazione di I/O ha completato la richiesta, il framework chiama il callback di completamento impostato dal driver per la richiesta. Il codice seguente mostra un callback di completamento semplice:
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;
}
Quando il driver chiama WdfRequestComplete dal callback di completamento, il framework elimina l'oggetto di memoria. L'handle dell'oggetto di memoria recuperato dal driver ora non è valido.
Scenario 3: il driver genera una richiesta di I/O che usa un oggetto memoria esistente.
Alcuni driver eseguono richieste di I/O personalizzate e le inviano alle destinazioni di I/O, rappresentate da oggetti di destinazione di I/O. Il driver può creare un oggetto richiesta personalizzato o riutilizzare un oggetto richiesta creato dal framework. Usando una delle due tecniche, un driver può riutilizzare un oggetto memoria da una richiesta precedente. Il driver non deve modificare il buffer sottostante, ma può passare un offset del buffer quando formatta la nuova richiesta di I/O.
Per informazioni su come formattare una nuova richiesta di I/O che usa un oggetto memoria esistente, vedere Invio di richieste di I/O a destinazioni di I/O generali.
Quando il framework formatta la richiesta da inviare alla destinazione di I/O, acquisisce un riferimento sull'oggetto di memoria riciclata per conto dell'oggetto di destinazione I/O. L'oggetto di destinazione di I/O mantiene questo riferimento fino a quando non si verifica una delle azioni seguenti:
- La richiesta è stata completata.
- Il driver riformatta nuovamente l'oggetto richiesta chiamando uno dei metodi WdfIoTargetFormatRequestXxx o WdfIoTargetSendXxxSynchronously . Per altre informazioni su questi metodi, vedere Framework I/O Target Object Methods.
- Il driver chiama WdfRequestReuse.
Al completamento della nuova richiesta di I/O, il framework chiama il callback di completamento dell'I/O impostato per tale richiesta. A questo punto, l'oggetto di destinazione di I/O contiene ancora un riferimento sull'oggetto memoria. Pertanto, nel callback di completamento di I/O, il driver deve chiamare WdfRequestReuse sull'oggetto richiesta creato dal driver prima di completare la richiesta originale da cui ha recuperato l'oggetto memoria. Se il driver non chiama WdfRequestReuse, si verifica un controllo dei bug a causa del riferimento aggiuntivo.
Scenario 4: il driver invia una richiesta di I/O che usa un nuovo oggetto memoria.
Il framework offre tre modi per creare nuovi oggetti di memoria, a seconda dell'origine del buffer sottostante. Per altre informazioni, vedere Uso dei buffer di memoria.
Se il buffer viene allocato dal framework o da un elenco lookaside creato dal driver, l'oggetto memoria è proprietario del buffer, quindi il puntatore del buffer rimane valido finché l'oggetto memoria esiste. I driver che generano richieste di I/O asincrone devono usare sempre buffer di proprietà di oggetti memoria, in modo che il framework possa garantire che i buffer vengano mantenuti fino al completamento della richiesta di I/O al driver emittente.
Se il driver assegna un buffer allocato in precedenza a un nuovo oggetto memoria chiamando WdfMemoryCreatePreallocated, l'oggetto memoria non è proprietario del buffer. In questo caso, la durata dell'oggetto memoria e la durata del buffer sottostante non sono correlate. Il driver deve gestire la durata del buffer e non deve tentare di usare un puntatore del buffer non valido.
Scenario 5: Il driver riutilizza un oggetto di richiesta che ha creato.
Un driver può riutilizzare gli oggetti richiesta creati, ma deve reinizializzare ogni oggetto chiamando WdfRequestReuse prima di ogni riutilizzo. Per ulteriori informazioni, vedere Riutilizzo degli oggetti di richiesta del framework.
Per il codice di esempio per reinizializzare un oggetto richiesta, vedere gli esempi Toaster e NdisEdge forniti con la versione KMDF.