Bagikan melalui


Mendaftarkan Rutinitas IoCompletion

Untuk mendaftarkan rutinitas IoCompletion , rutinitas pengiriman memanggil IoSetCompletionRoutine, menyediakan alamat rutin IoCompletion dan IRP yang kemudian akan diteruskan ke driver yang lebih rendah menggunakan IoCallDriver.

Ketika memanggil IoSetCompletionRoutine, rutinitas pengiriman menentukan keadaan di mana manajer I/O harus memanggil rutinitas IoCompletion yang ditentukan. Anda dapat memilih untuk memiliki rutinitas IoCompletion yang dipanggil jika driver tingkat yang lebih rendah berhasil menyelesaikan IRP (InvokeOnSuccess), menyelesaikan IRP dengan nilai status kesalahan (InvokeOnError), atau membatalkan IRP (InvokeOnCancel), dalam kombinasi apa pun.

Tujuan dari rutinitas IoCompletion adalah untuk memantau apa yang dilakukan driver tingkat bawah dengan IRP dan untuk melakukan pemrosesan penyelesaian tambahan, jika perlu. Secara khusus, penggunaan paling umum untuk rutinitas IoCompletion driver adalah sebagai berikut:

  • Untuk membuang IRP yang dialokasikan driver dengan IoAllocateIrp atau IoBuildAsynchronousFsdRequest

    Setiap driver tingkat lebih tinggi yang mengalokasikan IRP menggunakan salah satu rutinitas dukungan ini harus menyediakan rutinitas IoCompletion untuk IRP tersebut. Rutinitas IoCompletion harus memanggil IoFreeIrp untuk membuang IRP yang dialokasikan driver.

  • Untuk menggunakan kembali IRP masuk untuk meminta agar driver yang lebih rendah menyelesaikan beberapa operasi, seperti transfer parsial, hingga permintaan asli dapat dipenuhi dan diselesaikan oleh rutinitas IoCompletion

  • Untuk mencoba kembali permintaan bahwa driver yang lebih rendah selesai dengan kesalahan

    Driver tingkat tertinggi, seperti sistem file, lebih mungkin memiliki rutinitas IoCompletion yang mencoba mencoba kembali permintaan daripada driver perantara, kecuali mungkin driver kelas yang berlapis di atas driver port yang digabungkan erat. Namun, setiap driver perantara menggunakan rutinitas IoCompletion untuk mencoba kembali permintaan.

Sementara rutinitas DispatchReadWrite driver tingkat tertinggi atau menengah kemungkinan besar akan memproses IRP yang memerlukan rutinitas IoCompletion , setiap pengiriman rutin pada driver apa pun yang melewati RUN ke driver yang lebih rendah dapat mendaftarkan rutinitas IoCompletion .

Untuk IRP yang dialokasikan driver dan IRP yang digunakan kembali, rutinitas pengiriman harus memanggil IoSetCompletionRoutine dengan parameter Boolean berikut:

  • InvokeOnSuccess diatur ke TRUE

  • InvokeOnError diatur ke TRUE

  • InvokeOnCancel diatur ke TRUE jika ada driver yang lebih rendah dalam rantai yang mungkin menangani IRP yang dapat dibatalkan

    Biasanya, InvokeOnCancel diatur ke TRUE, terlepas dari apakah IRP mungkin dikembalikan dengan STATUS_CANCELLED, untuk memastikan bahwa IoCompletion rutin membebaskan setiap IRP yang dialokasikan driver atau memeriksa status penyelesaian setiap penggunaan kembali IRP.

Rutinitas pengiriman yang mengalokasikan IRP untuk driver yang lebih rendah menggunakan IoAllocateIrp atau IoBuildAsynchronousFsdRequestharus mengatur rutinitas IoCompletion untuk setiap IRP yang dialokasikan driver.

  • Rutinitas pengiriman harus mengatur status tentang IRP asli dan IRP yang dialokasikan untuk digunakan oleh rutinitas IoCompletion . Minimal, rutinitas IoCompletion membutuhkan akses ke IRP asli dan hitungan berapa banyak IRP tambahan yang dialokasikan.

  • Rutinitas pengiriman harus memanggil IoSetCompletionRoutine dengan semua parameter InvokeOnXxx diatur ke TRUE untuk IRP yang dialokasikannya.

Rutinitas pengiriman yang menggunakan kembali IRP untuk urutan operasi, atau yang mencoba kembali operasi I/O, harus memanggil IoSetCompletionRoutine untuk setiap IRP yang akan digunakan kembali atau dicoba kembali.

  • Rutinitas pengiriman harus menyimpan informasi status IRP asli, untuk penggunaan berikutnya oleh rutinitas IoCompletion .

    Misalnya, rutinitas DispatchReadWrite harus menyimpan parameter transfer yang relevan dari IRP input untuk rutinitas IoCompletion sebelum menyiapkan transfer parsial untuk driver berikutnya yang lebih rendah di IRP tersebut. Menyimpan parameter sangat penting jika Rutinitas DispatchReadWrite memodifikasi parameter apa pun yang perlu ditentukan oleh rutinitas IoCompletion ketika permintaan asli telah terpenuhi.

  • Jika rutinitas IoCompletion dapat mencoba kembali permintaan, rutinitas pengiriman harus menyiapkan batas atas yang ditentukan driver untuk jumlah percobaan ulang rutinitas IoCompletion-nya harus mencoba sebelum menyelesaikan IRP asli dengan kesalahan.

  • Jika IRP akan digunakan kembali, rutinitas pengiriman harus memanggil IoSetCompletionRoutine dengan semua parameter InvokeOnXxx diatur ke TRUE.

  • Untuk permintaan asinkron, rutinitas pengiriman driver perantara harus memanggil IoMarkIrpPending untuk IRP asli. Kemudian harus mengembalikan STATUS_PENDING setelah mengirim IRP ke driver yang lebih rendah.