Siklus Hidup Buffer Memori

Siklus hidup buffer memori mencakup waktu dari kapan buffer dibuat saat dihapus. Topik ini menjelaskan skenario penggunaan buffer dan pengaruhnya saat buffer dihapus.

Dalam kerangka kerja driver mode kernel (KMDF), objek permintaan mewakili permintaan I/O. Setiap objek permintaan dikaitkan dengan satu atau beberapa objek memori, dan setiap objek memori mewakili buffer yang digunakan untuk input atau output dalam permintaan.

Ketika kerangka kerja membuat objek permintaan dan memori untuk mewakili permintaan I/O masuk, kerangka kerja menetapkan objek permintaan sebagai induk objek memori terkait. Oleh karena itu, objek memori dapat bertahan tidak lebih dari masa pakai objek permintaan. Ketika driver berbasis kerangka kerja menyelesaikan permintaan I/O, kerangka kerja menghapus objek permintaan dan objek memori, sehingga handel ke kedua objek ini menjadi tidak valid.

Namun, buffer yang mendasar berbeda. Bergantung pada komponen mana yang membuat buffer dan cara membuat buffer, buffer mungkin memiliki jumlah referensi dan mungkin dimiliki oleh objek memori—atau mungkin tidak. Jika objek memori memiliki buffer, maka buffer memiliki jumlah referensi dan masa pakainya terbatas pada objek memori. Jika beberapa komponen lain membuat buffer, maka masa pakai buffer dan objek memori tidak terkait.

Driver berbasis kerangka kerja juga dapat membuat objek permintaannya sendiri untuk dikirim ke target I/O. Permintaan yang dibuat driver dapat menggunakan kembali objek memori yang ada yang diterima driver dalam permintaan I/O. Driver yang sering mengirim permintaan ke target I/O dapat menggunakan kembali objek permintaan yang dibuatnya.

Memahami masa pakai objek permintaan, objek memori, dan buffer yang mendasarinya penting untuk memastikan bahwa driver Anda tidak mencoba mereferensikan handel atau penunjuk buffer yang tidak valid.

Pertimbangkan skenario penggunaan berikut:

Skenario 1: Driver menerima permintaan I/O dari KMDF, menanganinya, dan menyelesaikannya.

Dalam skenario paling sederhana, KMDF mengirimkan permintaan ke driver, yang melakukan I/O dan menyelesaikan permintaan. Dalam hal ini, buffer yang mendasar mungkin telah dibuat oleh aplikasi mode pengguna, oleh driver lain, atau oleh sistem operasi itu sendiri. Untuk informasi tentang cara mengakses buffer, lihat Mengakses Buffer Data di Driver Framework-Based.

Ketika driver menyelesaikan permintaan, kerangka kerja akan menghapus objek memori. Penunjuk buffer kemudian tidak valid.

Skenario 2: Driver menerima permintaan I/O dari KMDF dan meneruskannya ke target I/O.

Dalam skenario ini, driver meneruskan permintaan ke target I/O. Kode sampel berikut menunjukkan bagaimana driver mengambil handel ke objek memori dari objek permintaan masuk, memformat permintaan untuk dikirim ke target I/O, dan mengirim permintaan:

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;

}

Ketika target I/O telah menyelesaikan permintaan, kerangka kerja memanggil panggilan balik penyelesaian yang ditetapkan driver untuk permintaan tersebut. Kode berikut menunjukkan panggilan balik penyelesaian sederhana:

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;

}

Ketika driver memanggil WdfRequestComplete dari panggilan balik penyelesaiannya, kerangka kerja menghapus objek memori. Handel objek memori yang diambil driver sekarang tidak valid.

Skenario 3: Driver mengeluarkan permintaan I/O yang menggunakan objek memori yang ada.

Beberapa driver mengeluarkan permintaan I/O mereka sendiri dan mengirimkannya ke target I/O, yang diwakili oleh objek target I/O. Driver dapat membuat objek permintaannya sendiri atau menggunakan kembali objek permintaan yang dibuat kerangka kerja. Dengan menggunakan salah satu teknik, driver dapat menggunakan kembali objek memori dari permintaan sebelumnya. Driver tidak boleh mengubah buffer yang mendasar, tetapi dapat melewati offset buffer ketika memformat permintaan I/O baru.

Untuk informasi tentang cara memformat permintaan I/O baru yang menggunakan objek memori yang ada, lihat Mengirim Permintaan I/O ke Target I/O Umum.

Ketika kerangka kerja memformat permintaan untuk dikirim ke target I/O, itu mengeluarkan referensi pada objek memori daur ulang atas nama objek target I/O. Objek target I/O mempertahankan referensi ini hingga salah satu tindakan berikut terjadi:

  • Permintaan telah selesai.
  • Driver memformat ulang objek permintaan lagi dengan memanggil salah satu metode WdfIoTargetFormatRequestXxx atau WdfIoTargetSendXxxSynchronously . Untuk informasi selengkapnya tentang metode ini, lihat Metode Objek Target I/O Kerangka Kerja.
  • Driver memanggil WdfRequestReuse.

Ketika permintaan I/O baru selesai, kerangka kerja memanggil panggilan balik penyelesaian I/O yang ditetapkan driver untuk permintaan ini. Pada titik ini, objek target I/O masih menyimpan referensi pada objek memori. Oleh karena itu, dalam panggilan balik penyelesaian I/O, driver harus memanggil WdfRequestReuse pada objek permintaan yang dibuat driver sebelum menyelesaikan permintaan asli dari mana ia mengambil objek memori. Jika driver tidak memanggil WdfRequestReuse, pemeriksaan bug terjadi karena referensi tambahan.

Skenario 4: Driver mengeluarkan permintaan I/O yang menggunakan objek memori baru.

Kerangka kerja menyediakan tiga cara bagi driver untuk membuat objek memori baru, tergantung pada sumber buffer yang mendasar. Untuk informasi selengkapnya, lihat Menggunakan Buffer Memori.

Jika buffer dialokasikan oleh kerangka kerja atau dari daftar lookaside yang dibuat driver, objek memori memiliki buffer, sehingga penunjuk buffer tetap valid selama objek memori ada. Driver yang mengeluarkan permintaan I/O asinkron harus selalu menggunakan buffer yang dimiliki oleh objek memori sehingga kerangka kerja dapat memastikan bahwa buffer bertahan sampai permintaan I/O selesai kembali ke driver penerbit.

Jika driver menetapkan buffer yang dialokasikan sebelumnya ke objek memori baru dengan memanggil WdfMemoryCreatePreallocated, objek memori tidak memiliki buffer. Dalam hal ini, masa pakai objek memori dan masa pakai buffer yang mendasarinya tidak terkait. Driver harus mengelola masa pakai buffer dan tidak boleh mencoba menggunakan penunjuk buffer yang tidak valid.

Skenario 5: Driver menggunakan kembali objek permintaan yang dibuatnya.

Driver dapat menggunakan kembali objek permintaan yang dibuatnya, tetapi harus menginisialisasi ulang setiap objek tersebut dengan memanggil WdfRequestReuse sebelum setiap penggunaan kembali. Untuk informasi selengkapnya, lihat Menggunakan Kembali Objek Permintaan Kerangka Kerja.

Untuk kode sampel yang menginisialisasi ulang objek permintaan, lihat sampel Pemanggang Toaster dan NdisEdge yang disediakan dengan rilis KMDF.