Bagikan melalui


Sinkronisasi Kode Interupsi

Faktor-faktor berikut mempersulit kode driver yang menangani gangguan perangkat keras pada sistem multiprosesor:

  • Setiap kali perangkat menginterupsi, ia memberikan informasi spesifik yang bersifat sementara karena dapat diganti saat perangkat menginterupsi berikutnya.

  • Perangkat menginterupsi pada tingkat IRQL yang relatif tinggi dan rutinitas layanan interupsi (ISR) dari perangkat tersebut dapat menginterupsi eksekusi kode driver lainnya.

  • Untuk gangguan DIRQL, ISR harus berjalan di DIRQL sambil memegang spin lock yang disediakan oleh driver, sehingga ISR dapat mencegah gangguan lebih lanjut saat menyimpan informasi volatil. DIRQL mencegah gangguan oleh prosesor saat ini, dan kunci spin mencegah gangguan oleh prosesor lain.

  • ISR harus berjalan dengan cepat karena perangkat tidak dapat mengganggu saat ISR sedang dijalankan. Waktu eksekusi ISR yang lama dapat memperlambat sistem atau mungkin menyebabkan kehilangan data.

  • Baik rutinitas ISR maupun panggilan prosedur yang ditangguhkan (DPC) biasanya harus mengakses area penyimpanan di mana ISR menyimpan data volatil perangkat. Rutinitas ini harus disinkronkan satu sama lain sehingga mereka tidak mengakses area penyimpanan secara bersamaan.

Karena semua faktor ini, Anda harus menggunakan aturan berikut saat menulis kode driver yang menangani gangguan:

  • Hanya fungsi panggilan balik EvtInterruptIsr yang mengakses data interupsi volatil, seperti register perangkat yang berisi informasi interupsi.

    Fungsi panggilan balik EvtInterruptIsr harus memindahkan data volatil ke buffer data interupsi yang ditentukan driver yang dapat diakses oleh fungsi panggilan balik EvtInterruptDpc driver, fungsi panggilan balik EvtInterruptWorkItem , atau beberapa fungsi panggilan balik EvtDpcFunc .

    Jika driver Anda menyediakan fungsi panggilan balik EvtInterruptDpc atau EvtInterruptWorkItem untuk objek interupsinya, tempat terbaik untuk menyimpan data interupsi adalah ruang konteks objek interupsi. Fungsi panggilan balik objek interupsi dapat mengakses ruang konteks objek dengan menggunakan handle objek yang mereka terima.

    Jika driver Anda menyediakan beberapa fungsi panggilan balik EvtDpcFunc untuk setiap fungsi panggilan balik EvtInterruptIsr , Anda mungkin menyimpan data interupsi di setiap ruang konteks objek DPC.

  • Semua kode driver yang mengakses buffer data interupsi harus disinkronkan sehingga hanya satu rutin mengakses data pada satu waktu.

    Untuk objek interupsi DIRQL, fungsi panggilan balik EvtInterruptIsr mengakses buffer data ini di IRQL = DIRQL sambil menahan kunci putar yang disediakan driver objek interupsi. Oleh karena itu, semua rutinitas yang mengakses buffer juga harus berjalan di DIRQL sambil memegang spin lock. (Biasanya, fungsi rutinitas panggilan balik EvtInterruptDpc atau EvtDpcFunc adalah satu-satunya yang harus mengakses buffer.)

    Semua rutinitas yang mengakses buffer data interupsi, kecuali fungsi panggilan balik EvtInterruptIsr, harus melakukan salah satu hal berikut:

    Kedua teknik ini memungkinkan fungsi EvtInterruptDpc atau EvtDpcFunc untuk mengakses data interupsi di DIRQL sambil menahan kunci putaran interupsi. DIRQL mencegah gangguan oleh prosesor saat ini, dan kunci putar mencegah gangguan oleh prosesor lain.

    Jika perangkat Anda mendukung beberapa vektor atau pesan interupsi, dan jika Anda ingin menyinkronkan penanganan driver terhadap interupsi ini, Anda dapat menetapkan satu kunci putar ke beberapa objek interupsi DIRQL. Kerangka kerja menentukan DIRQL tertinggi dari set gangguan, dan selalu memperoleh kunci putaran pada DIRQL tersebut sehingga kode yang disinkronkan tidak dapat diganggu oleh vektor atau pesan yang mengganggu dalam set.

    Untuk objek interupsi tingkat pasif, kerangka kerja memperoleh kunci interupsi tingkat pasif sebelum memanggil fungsi panggilan balik EvtInterruptIsr driver di IRQL = PASSIVE_LEVEL. Akibatnya, semua rutinitas yang mengakses buffer harus memperoleh kunci interupsi atau menyinkronkan akses buffer secara internal. Biasanya, fungsi callback EvtInterruptWorkItem milik interupsi adalah satu-satunya rutinitas lain yang mengakses buffer. Untuk informasi tentang memperoleh kunci interupsi dari fungsi panggilan balik EvtInterruptWorkItem , lihat bagian Keterangan dari halaman tersebut.

    Anda juga dapat menyinkronkan penanganan driver dari beberapa vektor interupsi dengan menetapkan satu kunci tunggu ke beberapa objek interupsi tingkat pasif.

  • Jika beberapa kode Anda yang menangani gangguan DIRQL harus berjalan di IRQL = PASSIVE_LEVEL, fungsi panggilan balik EvtInterruptDpc atau EvtDpcFunc Anda dapat membuat satu atau beberapa item kerja sehingga kode akan berjalan sebagai fungsi panggilan balik EvtWorkItem .

    Atau, di KMDF versi 1.11 dan yang lebih baru, driver dapat meminta item kerja interupsi dengan memanggil WdfInterruptQueueWorkItemForIsr. (Ingat bahwa fungsi panggilan balik EvtInterruptIsr driver dapat memanggil WdfInterruptQueueWorkItemForIsr atau WdfInterruptQueueDpcForIsr, tetapi tidak keduanya.)

  • Jika penting untuk menyinkronkan fungsi panggilan balik EvtInterruptDpc dan EvtDpcFunc driver satu sama lain dan dengan fungsi panggilan balik lain yang terkait dengan perangkat, driver Anda dapat mengatur anggota AutomaticSerialization ke TRUE dalam struktur WDF_INTERRUPT_CONFIG interupsi dan struktur WDF_DPC_CONFIG objek DPC. Atau, driver dapat menggunakan kunci putar kerangka kerja. (Mengatur anggota AutomaticSerialization ke TRUE tidak menyinkronkan fungsi panggilan balik EvtInterruptIsr dengan fungsi panggilan balik lainnya. Gunakan WdfInterruptSynchronize atau WdfInterruptAcquireLock untuk menyinkronkan fungsi panggilan balik EvtInterruptIsr , seperti yang dijelaskan sebelumnya dalam topik ini.)

Untuk informasi selengkapnya tentang menyinkronkan rutinitas driver, lihat Teknik Sinkronisasi untuk driver Framework-Based.