Bevezetés a Kernel Dispatcher-objektumok használatába

A kernel egy kernel-diszpécserobjektumnak vagy csak kézbesítő objektumnak nevezett objektumtípus-készletet határoz meg. A diszpécserobjektumok közé tartoznak az időzítőobjektumok, az eseményobjektumok, a szemafor objektumok, a mutex objektumok és a szálobjektumok.

Az illesztőprogramok a diszpécserobjektumokat szinkronizálási mechanizmusként használhatják egy nem önkényes szál kontextusában, miközben a végrehajtás IRQL szinten PASSIVE_LEVEL-lel egyenlő.

A diszpécser objektumállapotai

Minden kernel által definiált diszpécserobjektum-típusnak van egy állapota, amely vagy a Jel, vagy a Not-Signaled értékre van állítva.

A szálak egy csoportja szinkronizálhatja a műveleteket, ha egy vagy több szál meghívja a KeWaitForSingleObject, a KeWaitForMutexObject vagy a KeWaitForMultipleObjects parancsot. Ezek a függvények bemenetként fogadják a diszpécser objektummutatóit, és várják meg, amíg egy másik rutin vagy szál beállít egy vagy több kézbesítő objektumot a Jeles állapotba.

Amikor egy szál meghívja a KeWaitForSingleObjectet , hogy várja meg a kézbesítő objektumot (vagy a KeWaitForMutexObject-et egy mutex esetén), a szál várakozási állapotba kerül, amíg a kézbesítő objektum a Jeles állapotra nem kerül. Egy szál meghívhatja a KeWaitForMultipleObjects függvényt, hogy várakozzon a diszpécserobjektumok bármelyikére vagy mindegyikére, amíg azok a Signaled állapotba nem kerülnek.

Amikor egy diszpécserobjektum a Jeles állapotra van állítva, a kernel módosítja az objektumra váró szálak állapotát. (A szabály alól kivételt képeznek a szinkronizálási időzítők és a szinkronizálási események; ha egy szinkronizálási esemény vagy időzítő van jelezve, csak egy várakozási szál áll készenlétre. További információ: Időzítőobjektumok, DPC-k és eseményobjektumok.) A kész állapotban lévő szál az aktuális futásidejű szál prioritásának és a processzorok aktuális rendelkezésre állásának megfelelően lesz ütemezve az adott prioritással rendelkező szálakhoz.

Mikor várakozhatnak az illesztőprogramok a diszpécserobjektumokra?

Általánosságban elmondható, hogy az illesztőprogramok csak akkor várhatják meg a kézbesítő objektumok beállítását, ha az alábbi körülmények közül legalább az egyik teljesül:

  • Az illesztőprogram nem önkényes szál kontextusában fut.

    Ez azt a szálat azonosítja, amely várakozási állapotba kerül. A gyakorlatban az egyetlen olyan illesztőprogram-rutin, amely nem önkényes szál kontextusában fut, a DriverEntry, az AddDevice, a Reinitialize és az Unload rutinja, valamint a legmagasabb szintű illesztőprogramok diszpécser rutinjai. Ezeket a rutinokat közvetlenül a rendszer hívja meg.

  • Az illesztőprogram egy teljesen szinkron I/O-kérést hajt végre.

    Ez azt jelzi, hogy az illesztőprogramok nem várnak el semmilyen műveletet az I/O-kérés kezelése közben, és egyetlen illesztőprogram sem tér vissza addig, amíg az alatta lévő illesztőprogram nem fejezte be a kérés kezelését.

Ezenkívül az illesztő nem tud várakozási állapotba lépni, ha olyan IRQL-en fut, amely egyenlő vagy magasabb a DISPATCH_LEVEL-nél.

Ezen korlátozások alapján a következő szabályokat kell használnia:

  • A DriverEntry, az AddDevice, az Reinitialize és a Unload rutinok bármelyik illesztőprogramban várakozhatnak a diszpécserobjektumokra.

  • A legmagasabb szintű illesztőprogram diszpécseri rutinjai diszpécser objektumokra várhatnak.

  • Az alacsonyabb szintű illesztőprogramok kézbesítési rutinjai megvárhatják a küldési objektumokat, ha az I/O-művelet szinkron, például létrehozási, kiürítési, leállítási és bezárási műveletek, néhány eszköz I/O-vezérlési művelete, valamint néhány PnP- és energiaművelet.

  • Az alacsonyabb szintű illesztőprogramok diszpécseri rutinjai nem tudnak várni egy diszpécserobjektumra az aszinkron I/O-műveletek végrehajtásához.

  • Az IRQL DISPATCH_LEVEL szinten vagy annál magasabban végrehajtó illesztőprogram-rutin nem várhatja meg, hogy egy kézbesítő objektum Jelzési állapotba kerüljön.

  • Egy meghajtó nem próbálhatja meg, hogy várakozzon arra, hogy egy kiszolgáló objektum a jelzett állapotba kerüljön a lapozóeszközre vagy onnan történő átvitel befejezéséhez.

  • Az olvasási/írási kéréseket kezelő illesztőprogram-küldési rutinok általában nem tudják megvárni, amíg a diszpécserobjektum a Jeles állapotra van állítva.

  • Az eszköz I/O-vezérlési kéréseinek végrehajtási rutinja csak akkor várhatja meg, hogy a kézbesítő objektum Jelzett állapotra legyen állítva, amennyiben az I/O-vezérlőkód átviteli módja METHOD_BUFFERED.

  • Az SCSI-miniportillesztők nem használhatnak kernel-diszpécserobjektumokat. Az SCSI-miniportillesztőknek csak az SCSI-portillesztők támogatási rutinjait kell meghívni.

Minden más szokásos illesztői rutin tetszőleges szálkörnyezetben fut: bármilyen szál is legyen aktuális, amikor a rendszer meghívja az illesztőprogram-rutint egy üzenetsoros művelet feldolgozására vagy egy eszköz megszakításának kezelésére. Ezenkívül a legtöbb standard illesztőprogram-rutin emelt IRQL szinten fut, akár DISPATCH_LEVEL-en, akár eszközillesztők esetén DIRQL szinten.

Szükség esetén az illesztőprogram létrehozhat egy dedikált eszközszálat, amely megvárhatja az illesztőprogram egyéb rutinjait (kivéve az ISR vagy a SynchCritSection rutint), hogy beállítson egy diszpécserobjektumot a jelzett állapotra, és visszaállítsa a Not-Signaled állapotot.

Általános útmutatóként, ha arra számít, hogy az új eszközillesztőnek gyakran 50 mikroszekundumnál hosszabb ideig kell elakadnia, amíg az I/O-műveletek során az eszközállapot-változásokra vár, fontolja meg egy eszköz által dedikált szálon futó illesztőprogram implementálását. Ha az eszközillesztő szintén legmagasabb szintű illesztőprogram, fontolja meg a rendszermunkaszálak használatát és egy vagy több feldolgozószálas visszahívási rutin implementálását. Lásd: PsCreateSystemThread és Az összefűzött üzenetsorok kezelése a Driver-Created szállal.