Menentukan dan Menggunakan Objek Peristiwa

Setiap driver yang menggunakan objek peristiwa harus memanggil KeInitializeEvent, IoCreateNotificationEvent, atau IoCreateSynchronizationEvent sebelum menunggu, mengatur, menghapus, atau mengatur ulang peristiwa. Gambar berikut menggambarkan bagaimana driver dengan utas dapat menggunakan objek peristiwa untuk sinkronisasi.

diagram yang mengilustrasikan menunggu objek peristiwa.

Seperti yang ditunjukkan oleh gambar sebelumnya, driver seperti itu harus menyediakan penyimpanan untuk objek peristiwa, yang harus merupakan residen. Driver dapat menggunakan ekstensi perangkat dari objek perangkat yang dibuat driver, ekstensi pengontrol jika menggunakan objek pengontrol, atau kumpulan yang tidak dialokasikan oleh driver.

Ketika driver memanggil KeInitializeEvent, driver harus meneruskan pointer ke penyimpanan residen driver untuk objek peristiwa. Selain itu, penelepon harus menentukan status awal (diberi sinyal atau tidak diberi sinyal) untuk objek peristiwa. Pemanggil juga harus menentukan jenis peristiwa, yang dapat berupa salah satu dari berikut ini:

  • SynchronizationEvent

    Ketika peristiwa sinkronisasi diatur ke status Sinyal, satu utas yang menunggu peristiwa direset ke Not-Signaled menjadi memenuhi syarat untuk dieksekusi dan status peristiwa secara otomatis diatur ulang ke Tidak Diberi Sinyal.

    Jenis peristiwa ini terkadang disebut peristiwa autoclearing, karena status Sinyalnya secara otomatis direset setiap kali penantian terpenuhi.

  • NotificationEvent

    Ketika peristiwa pemberitahuan diatur ke status Sinyal, semua utas yang menunggu peristiwa direset ke Not-Signaled memenuhi syarat untuk eksekusi dan peristiwa tetap dalam status Sinyal hingga reset eksplisit ke Not-Signaled terjadi: yaitu, ada panggilan ke KeClearEvent atau KeResetEvent dengan penunjuk Peristiwa yang diberikan.

Beberapa perangkat atau driver perantara memiliki satu utas khusus driver, apalagi satu set utas yang mungkin menyinkronkan operasi mereka dengan menunggu peristiwa yang melindungi sumber daya bersama.

Sebagian besar driver yang menggunakan objek peristiwa untuk menunggu penyelesaian operasi I/O mengatur Jenis input ke NotificationEvent saat mereka memanggil KeInitializeEvent. Objek peristiwa yang disiapkan untuk IRP yang dibuat driver dengan IoBuildSynchronousFsdRequest atau IoBuildDeviceIoControlRequest hampir selalu diinisialisasi sebagai NotificationEvent karena pemanggil akan menunggu peristiwa untuk pemberitahuan bahwa permintaannya telah dipenuhi oleh satu atau lebih driver tingkat bawah.

Setelah driver menginisialisasi dirinya sendiri, utas khusus drivernya, jika ada, dan rutinitas lainnya dapat menyinkronkan operasi mereka pada peristiwa tersebut. Misalnya, driver dengan utas yang mengelola antrean IRP, seperti driver pengontrol floppy sistem, mungkin menyinkronkan pemrosesan IRP pada peristiwa, seperti yang ditunjukkan pada gambar sebelumnya:

  1. Utas, yang telah menghapus antrean IRP untuk diproses pada perangkat, memanggil KeWaitForSingleObject dengan penunjuk ke penyimpanan yang disediakan driver untuk objek peristiwa yang diinisialisasi.

  2. Rutinitas driver lain melakukan operasi I/O perangkat yang diperlukan untuk memenuhi IRP dan, ketika operasi ini selesai, rutinitas DpcForIsr driver memanggil KeSetEvent dengan pointer ke objek peristiwa, peningkatan prioritas yang ditentukan driver untuk utas (Tahapan, seperti yang ditunjukkan pada gambar sebelumnya), dan Boolean Wait diatur keFALSE. Memanggil KeSetEvent mengatur objek peristiwa ke status Sinyal, sehingga mengubah status alur tunggu menjadi siap.

  3. Kernel mengirimkan utas untuk dieksekusi segera setelah prosesor tersedia: yaitu, tidak ada utas lain dengan prioritas yang lebih tinggi saat ini dalam keadaan siap dan tidak ada rutinitas mode kernel untuk dijalankan pada IRQL yang lebih tinggi.

    Utas sekarang dapat menyelesaikan IRP jika DpcForIsr belum memanggil IoCompleteRequest dengan IRP sudah, dan dapat menghapus antrean IRP lain untuk diproses pada perangkat.

Memanggil KeSetEvent dengan parameter Tunggu yang diatur ke TRUE menunjukkan niat pemanggil untuk segera memanggil KeWaitForSingleObject atau KeWaitForMultipleObjects mendukung rutinitas saat kembali dari KeSetEvent.

Pertimbangkan panduan berikut untuk mengatur parameter TunggukeKeSetEvent:

Utas yang dapat dipaginasi atau rutinitas driver yang dapat dipaginasi yang berjalan di IRQL < DISPATCH_LEVEL tidak boleh memanggil KeSetEvent dengan parameter Tunggu yang diatur ke TRUE. Panggilan seperti itu menyebabkan kesalahan halaman fatal jika pemanggil kebetulan di-page out antara panggilan ke KeSetEvent dan KeWaitForSingleObject atau KeWaitForMultipleObjects.

Setiap rutinitas driver standar yang berjalan pada IRQL = DISPATCH_LEVEL tidak dapat menunggu interval bukan nol pada objek dispatcher apa pun tanpa menurunkan sistem. Namun, rutinitas seperti itu dapat memanggil KeSetEvent saat berjalan di IRQL kurang dari atau sama dengan DISPATCH_LEVEL.

Untuk ringkasan IRQL di mana rutinitas driver standar berjalan, lihat Mengelola Prioritas Perangkat Keras.

KeResetEvent mengembalikan status sebelumnya dari Peristiwa tertentu: apakah itu diatur ke Signaled atau tidak ketika panggilan ke KeResetEvent terjadi. KeClearEvent hanya mengatur status Peristiwa yang diberikan menjadi Tidak Diberi Sinyal.

Pertimbangkan pedoman berikut kapan harus memanggil rutinitas dukungan sebelumnya:

Untuk performa yang lebih baik, setiap driver harus memanggil KeClearEvent kecuali penelepon membutuhkan informasi yang dikembalikan oleh KeResetEvent untuk menentukan apa yang harus dilakukan selanjutnya.