Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O ciclo de vida de um buffer de memória abrange o tempo desde quando o buffer é criado até quando ele é excluído. Este tópico descreve os cenários de uso do buffer e como eles afetam quando o buffer é excluído.
Na estrutura de controladores de modo kernel (KMDF), um objeto de solicitação representa um pedido de E/S. Cada objeto de solicitação é associado a um ou mais objetos de memória, e cada objeto de memória representa um buffer que é usado para entrada ou saída na solicitação.
Quando a estrutura cria objetos de solicitação e memória para representar uma solicitação de E/S de entrada, ela define o objeto de solicitação como o pai dos objetos de memória associados. Portanto, o objeto de memória não pode persistir mais do que o tempo de vida do objeto de solicitação. Quando o driver baseado em estrutura conclui a solicitação de E/S, a estrutura exclui o objeto de solicitação e o objeto de memória, de modo que as alças para esses dois objetos se tornam inválidas.
No entanto, o buffer subjacente é diferente. Dependendo de qual componente criou o buffer e como ele criou o buffer, o buffer pode ter uma contagem de referência e pode ser de propriedade do objeto de memória — ou não. Se o objeto de memória possui o buffer, então o buffer tem uma contagem de referência e seu tempo de vida é limitado ao do objeto de memória. Se algum outro componente criou o buffer, os tempos de vida do buffer e do objeto de memória não estão relacionados.
Um driver baseado em framework também pode criar os seus próprios objetos de solicitação para enviar aos destinos de E/S. Uma solicitação criada pelo driver pode reutilizar um objeto de memória existente que o driver recebeu em uma solicitação de E/S. Um driver que frequentemente envia solicitações para destinos de E/S pode reutilizar os objetos de solicitação que ele cria.
Compreender os ciclos de vida do objeto de solicitação, do objeto de memória e do buffer subjacente é importante para garantir que o seu driver não tente fazer referência a um identificador ou ponteiro de buffer inválido.
Considere os seguintes cenários de uso:
- Cenário 1: O driver recebe uma solicitação de E/S do KMDF, manipula-a e a completa.
- Cenário 2: O driver recebe uma solicitação de E/S do KMDF e a encaminha para um destino de E/S.
- Cenário 3: O driver emite uma solicitação de E/S que usa um objeto de memória existente.
- Cenário 4: O driver emite uma solicitação de E/S que usa um novo objeto de memória.
- Cenário 5: O driver reutiliza um objeto de solicitação que ele criou.
Cenário 1: O driver recebe uma solicitação de E/S do KMDF, manipula-a e a completa.
No cenário mais simples, o KMDF despacha uma solicitação para o driver, que executa E/S e conclui a solicitação. Nesse caso, o buffer subjacente pode ter sido criado por um aplicativo de modo de usuário, por outro driver ou pelo próprio sistema operacional. Para obter informações sobre como acessar buffers, consulte Acessando buffers de dados em drivers Framework-Based.
Quando o driver conclui a solicitação, a estrutura exclui o objeto de memória. O ponteiro do buffer é então inválido.
Cenário 2: O driver recebe uma solicitação de E/S do KMDF e a encaminha para um destino de E/S.
Nesse cenário, o driver encaminha a solicitação para um destino de E/S. O código de exemplo a seguir mostra como um driver recupera um identificador para o objeto de memória de um objeto de solicitação de entrada, formata a solicitação para enviar ao destino de E/S e envia a solicitação:
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 o destino de E/S tiver concluído a solicitação, o framework chamará o callback de conclusão definido pelo driver para a solicitação. O código a seguir mostra um retorno de chamada de conclusão simples:
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 o driver chama WdfRequestComplete de seu retorno de chamada de conclusão, a estrutura exclui o objeto de memória. O identificador de objeto de memória que o driver recuperou agora é inválido.
Cenário 3: O driver emite uma solicitação de E/S que usa um objeto de memória existente.
Alguns drivers emitem suas próprias solicitações de E/S e as enviam para destinos de E/S, que são representados por objetos de destino de E/S. O driver pode criar seu próprio objeto de solicitação ou reutilizar um objeto de solicitação criado pela estrutura. Usando qualquer uma das técnicas, um driver pode reutilizar um objeto de memória de uma solicitação anterior. O driver não deve alterar o buffer subjacente, mas pode passar um deslocamento do buffer quando formata a nova solicitação de E/S.
Para obter informações sobre como formatar uma nova solicitação de E/S que usa um objeto de memória existente, consulte Enviando solicitações de E/S para destinos gerais de E/S.
Quando a estrutura formata a solicitação para enviar ao alvo de E/S, ela estabelece uma referência ao objeto de memória reciclada em representação do objeto alvo de E/S. O objeto de destino de E/S retém essa referência até que uma das seguintes ações ocorra:
- O pedido foi concluído.
- O driver reformata o objeto de solicitação novamente chamando um dos métodos WdfIoTargetFormatRequestXxx ou WdfIoTargetSendXxxSynchronously . Para obter mais informações sobre esses métodos, consulte Framework I/O Target Object Methods.
- O driver chama WdfRequestReuse.
Quando a nova solicitação de E/S é concluída, a estrutura chama o retorno de chamada de conclusão de E/S que o driver definiu para essa solicitação. Neste ponto, o objeto de destino de E/S ainda mantém uma referência no objeto de memória. Portanto, no callback de conclusão de E/S, o driver deve chamar WdfRequestReuse no objeto de solicitação criado pelo driver antes de finalizar a solicitação original da qual recuperou o objeto de memória. Se o driver não chamar WdfRequestReuse, ocorrerá uma verificação de erros devido à referência extra.
Cenário 4: O driver emite uma solicitação de E/S que usa um novo objeto de memória.
A estrutura fornece três maneiras para os drivers criarem novos objetos de memória, dependendo da origem do buffer subjacente. Para obter mais informações, consulte Usando buffers de memória.
Se o buffer for alocado pela estrutura ou de uma lista lookaside criada pelo driver, o objeto de memória será proprietário do buffer, portanto, o ponteiro do buffer permanecerá válido enquanto o objeto de memória existir. Os drivers que emitem solicitações de E/S assíncronas devem sempre usar buffers pertencentes a objetos de memória para que a estrutura possa garantir que os buffers persistam até que a solicitação de E/S seja concluída de volta ao driver emissor.
Se o driver atribui um buffer alocado anteriormente a um novo objeto de memória chamando WdfMemoryCreatePreallocated, o objeto de memória não possui o buffer. Nesse caso, o tempo de vida do objeto de memória e o tempo de vida do buffer subjacente não estão relacionados. O driver deve gerenciar o tempo de vida do buffer e não deve tentar usar um ponteiro de buffer inválido.
Cenário 5: O driver reutiliza um objeto de solicitação que ele criou.
Um driver pode reutilizar os objetos de solicitação que cria, mas deve reinicializar cada objeto chamando WdfRequestReuse antes de cada reutilização. Para obter mais informações, consulte Reutilizando objetos de solicitação do Framework.
Para obter o código de exemplo que reinicializa um objeto de solicitação, consulte os exemplos Toaster e NdisEdge fornecidos com a versão KMDF.