Mengelola Antrean Yang Saling Diblokir dengan Utas Driver-Created

Driver baru harus menggunakan kerangka kerja antrean IRP yang aman untuk membatalkan preferensi metode yang diuraikan di bagian ini.

Seperti driver pengontrol floppy sistem, driver dengan utas khusus perangkat, daripada rutinitas StartIo , biasanya mengelola antrean runtime integrasinya sendiri dalam antrean yang saling terhubung dua kali lipat. Utas driver menarik IRP dari antreannya yang saling mengunci ketika ada pekerjaan yang harus dilakukan pada perangkat.

Secara umum, driver harus mengelola sinkronisasi dengan utasnya ke sumber daya apa pun yang dibagikan antara utas dan rutinitas driver lainnya. Driver juga harus memiliki beberapa cara untuk memberi tahu utas yang dibuat driver bahwa IRP diantrekan. Biasanya, utas menunggu pada objek dispatcher, disimpan dalam ekstensi perangkat, sampai rutinitas Pengiriman driver mengatur objek dispatcher ke status Sinyal setelah memasukkan IRP ke dalam antrean yang saling dikunci.

Ketika rutinitas Pengiriman driver dipanggil, masing-masing memeriksa parameter di lokasi tumpukan I/O dari IRP input dan, jika valid, mengantre permintaan untuk diproses lebih lanjut. Untuk setiap IRP yang diantrekan ke utas khusus driver, rutinitas pengiriman harus mengatur konteks apa pun yang diperlukan utasnya untuk memproses IRP tersebut sebelum memanggil ExInterlockedInsertXxxList. Lokasi tumpukan I/O driver di setiap IRP memberikan akses utas driver ke ekstensi perangkat objek perangkat target, di mana driver dapat berbagi informasi konteks dengan utasnya, karena utas menghapus setiap IRP dari antrean.

Driver yang mengantre IRP yang dapat dibatalkan harus menerapkan rutinitas Batalkan . Karena RUN dibatalkan secara asinkron, Anda harus memastikan bahwa pembalap Anda menghindari kondisi balapan yang dapat dihasilkan. Lihat Menyinkronkan Pembatalan IRP Untuk informasi selengkapnya tentang kondisi balapan yang terkait dengan pembatalan RUNP dan teknik untuk menghindarinya.

Setiap utas yang dibuat driver berjalan di IRQL = PASSIVE_LEVEL dan pada prioritas run-time dasar yang sebelumnya diatur ketika driver yang disebut PsCreateSystemThread. Panggilan utas ke ExInterlockedRemoveHeadList untuk sementara meningkatkan IRQL ke DISPATCH_LEVEL pada prosesor saat ini saat IRP sedang dihapus dari antrean internal driver. IRQL asli dipulihkan ke PASSIVE_LEVEL saat kembali dari panggilan ini.

Setiap utas driver (atau panggilan balik alur pekerja yang disediakan driver) harus mengelola IRQL dengan hati-hati di mana ia berjalan. Misalnya, pertimbangkan hal berikut:

  • Karena rangkaian sistem umumnya berjalan di IRQL = PASSIVE_LEVEL, dimungkinkan bagi utas driver untuk menunggu objek dispatcher yang ditentukan kernel diatur ke status bersinyali.

    Misalnya, utas khusus perangkat mungkin menunggu driver lain untuk memenuhi suatu peristiwa dan menyelesaikan beberapa IRP transfer parsial yang disiapkan utas dengan IoBuildSynchronousFsdRequest.

  • Namun, utas khusus perangkat tersebut harus menaikkan IRQL pada prosesor saat ini sebelum memanggil rutinitas dukungan tertentu.

    Misalnya, jika driver menggunakan DMA, utas khusus perangkatnya harus menumpuk panggilannya ke AllocateAdapterChannel dan FreeAdapterChannel antara panggilan ke KeRaiseIrql dan KeLowerIrql karena rutinitas ini dan rutinitas dukungan tertentu lainnya untuk operasi DMA harus dipanggil di IRQL = DISPATCH_LEVEL.

    Ingatlah bahwa rutinitas StartIo dijalankan pada DISPATCH_LEVEL, sehingga driver yang menggunakan DMA tidak perlu melakukan panggilan ke rutinitas KeXxxIrql dari rutinitas StartIo mereka.

  • Utas yang dibuat driver dapat mengakses memori yang dapat di-pageable karena berjalan dalam konteks utas nonarbitrer (sendiri) di IRQL = PASSIVE_LEVEL, tetapi banyak rutinitas driver standar lainnya berjalan di IRQL >= DISPATCH_LEVEL. Jika utas yang dibuat driver mengalokasikan memori yang dapat diakses oleh rutinitas seperti itu, alur tersebut harus mengalokasikan memori dari kumpulan yang tidak di-pembayaran. Misalnya, jika utas khusus perangkat mengalokasikan buffer apa pun yang akan diakses nanti oleh ISR atau SynchCritSection driver, AdapterControl, AdapterListControl, ControllerControl, DpcForIsr, CustomDpc, IoTimer, CustomTimerDpc, atau, dalam driver tingkat yang lebih tinggi, rutinitas IoCompletion , memori yang dialokasikan utas tidak dapat di-pageable.

  • Jika driver mempertahankan informasi status bersama atau sumber daya dalam ekstensi perangkat, utas driver (seperti rutinitas StartIo ) harus menyinkronkan aksesnya ke perangkat fisik dan ke data bersama dengan rutinitas lain driver yang mengakses perangkat, lokasi memori, atau sumber daya yang sama.

    Jika utas berbagi perangkat atau status dengan ISR, utas harus menggunakan KeSynchronizeExecution untuk memanggil rutinitas SynchCritSection yang disediakan driver untuk memprogram perangkat atau untuk mengakses status bersama. Lihat Menggunakan Bagian Penting.

    Jika utas berbagi status atau sumber daya dengan rutinitas selain ISR, driver harus melindungi status bersama atau sumber daya dengan kunci putar eksekutif yang diinisialisasi driver yang drivernya menyediakan penyimpanan. Untuk informasi selengkapnya, lihat Kunci Putar.

Untuk informasi selengkapnya tentang tradeoff desain menggunakan utas driver untuk perangkat yang lambat, lihat Polling Perangkat. Lihat juga Mengelola Prioritas Perangkat Keras. Untuk informasi spesifik tentang IRQL untuk rutinitas dukungan tertentu, lihat halaman referensi rutinitas.