記憶體緩衝區的生命週期跨越從建立緩衝區到刪除緩衝區的時間。 本主題說明緩衝區使用案例,以及它們在刪除緩衝區時如何影響。
在核心模式驅動程式架構 (KMDF) 中,要求物件代表 I/O 要求。 每個要求物件都與一或多個記憶體物件相關聯,而每一個記憶體物件代表一個緩衝區,用於要求中的輸入或輸出。
當架構建立要求和記憶體物件來代表傳入 I/O 要求時,它會將要求物件設定為相關聯記憶體物件的父項。 因此,記憶體物件的保存時間不得超過要求物件的存留期。 當架構型驅動程式完成 I/O 要求時,架構會刪除要求物件和記憶體物件,因此這兩個物件的控制碼會變成無效。
不過,基礎緩衝區是不同的。 視建立緩衝區的元件及其建立緩衝區的方式而定,緩衝區可能具有參考計數,而且可能由記憶體物件擁有,也可能沒有。 如果記憶體物件擁有緩衝區,則緩衝區具有參考計數,而且其存留期會限制為記憶體物件的存留期。 如果其他元件已建立緩衝區,則緩衝區與記憶體物件的存留期不相關。
架構型驅動程式也可以建立自己的要求物件,以傳送至 I/O 目標。 驅動程式建立的要求可以重複使用驅動程式在 I/O 要求中收到的現有記憶體物件。 經常將要求傳送至 I/O 目標的驅動程式可以重複使用它所建立 的要求物件 。
瞭解要求物件、記憶體物件和基礎緩衝區的存留期,請務必確保您的驅動程式不會嘗試參考無效的控制碼或緩衝區指標。
請考慮下列使用案例:
- 案例 1:驅動程式會從 KMDF 接收 I/O 要求、處理並完成。
- 案例 2: 驅動程式會從 KMDF 接收 I/O 要求,並將它轉送至 I/O 目標。
- 案例 3: 驅動程式發出使用現有記憶體物件的 I/O 要求。
- 案例 4: 驅動程式發出使用新記憶體物件的 I/O 要求。
- 案例 5: 驅動程式重複使用它建立的要求物件。
案例 1:驅動程式會從 KMDF 接收 I/O 要求、處理並完成。
在最簡單的案例中,KMDF 會將要求分派給驅動程式,以執行 I/O 並完成要求。 在此情況下,基礎緩衝區可能是由使用者模式應用程式、另一個驅動程式或作業系統本身所建立。 如需如何存取緩衝區的資訊,請參閱 存取 Framework-Based 驅動程式中的資料緩衝區。
當驅動程式 完成要求時,架構會刪除記憶體物件。 緩衝區指標則無效。
案例 2:驅動程式會從 KMDF 接收 I/O 要求,並將它轉送至 I/O 目標。
在此案例中,驅動程式 會將要求轉送 至 I/O 目標。 下列範例程式碼顯示驅動程式如何從傳入要求物件擷取記憶體物件的控制碼、格式化要求以傳送至 I/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;
}
當 I/O 目標完成要求時,架構會呼叫驅動程式針對要求設定的完成回呼。 下列程式碼顯示簡單的完成回呼:
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;
}
當驅動程式從其完成回呼呼叫 WdfRequestComplete 時,架構會刪除記憶體物件。 驅動程式擷取的記憶體物件控制碼現在無效。
案例 3:驅動程式發出使用現有記憶體物件的 I/O 要求。
某些驅動程式會發出自己的 I/O 要求,並將其傳送至 I/O 目標,這些目標是由 I/O 目標物件所代表。 驅動程式可以建立自己的要求物件,或 重複使用架構建立的要求物件。 使用任一技術,驅動程式可以重複使用先前要求中的記憶體物件。 驅動程式不得變更基礎緩衝區,但它可以在格式化新的 I/O 要求時傳遞緩衝區位移。
如需如何格式化使用現有記憶體物件的新 I/O 要求的相關資訊,請參閱 將 I/O 要求傳送至一般 I/O 目標。
當架構格式化要傳送至 I/O 目標的要求時,它會代表 I/O 目標物件取得回收記憶體物件的參考。 I/O 目標物件會保留此參照,直到發生下列其中一個動作為止:
- 請求已完成。
- 驅動程式會呼叫其中一個 WdfIoTargetFormatRequestXxx 或 WdfIoTargetSendXxxSynchronously 方法,以再次重新格式化要求物件。 如需這些方法的詳細資訊,請參閱 Framework I/O 目標物件方法。
- 驅動程式會呼叫 WdfRequestReuse。
當新的 I/O 要求完成時,架構會呼叫驅動程式為此要求設定的 I/O 完成回呼。 此時,I/O 目標物件仍會保留記憶體物件上的參考。 因此,在 I/O 完成回呼中,驅動程式必須先在驅動程式建立的要求物件上呼叫 WdfRequestReuse ,才能完成從中擷取記憶體物件的原始要求。 如果驅動程式未呼叫 WdfRequestReuse,則會因為額外的參考而發生錯誤檢查。
案例 4:驅動程式發出使用新記憶體物件的 I/O 要求。
架構提供三種方式讓驅動程式建立新的記憶體物件,視基礎緩衝區的來源而定。 如需詳細資訊,請參閱 使用記憶體緩衝區。
如果緩衝區是由架構或驅動程式建立的 監視清單配置,記憶體物件會擁有緩衝區,因此只要記憶體物件存在,緩衝區指標就會保持有效。 發出非同步 I/O 要求的驅動程式應該一律使用記憶體物件所擁有的緩衝區,讓架構可以確保緩衝區持續存在,直到 I/O 要求完成回發行驅動程式為止。
如果驅動程式藉由呼叫 WdfMemoryCreatePreallocated,將先前配置的緩衝區指派給新的記憶體物件,則記憶體物件不會擁有緩衝區。 在此情況下,記憶體物件的存留期與基礎緩衝區的存留期並不相關。 驅動程式必須管理緩衝區的存留期,而且不得嘗試使用無效的緩衝區指標。
案例 5:驅動程式重複使用它建立的要求物件。
驅動程式可以重複使用它所建立的要求物件,但必須在每次重複使用之前呼叫 WdfRequestReuse 來重新初始化每個這類物件。 如需詳細資訊,請參閱 重複使用 Framework 要求物件。