Úvod k objektům dispečera jádra
Jádro definuje sadu typů objektů označovaných jako objekty dispečera jádranebo pouze objekty dispečera. Objekty dispečeru zahrnují objekty časovače, objekty událostí, objekty semaphore, objekty mutex a objekty vlákna.
Ovladače mohou používat dispečerské objekty jako synchronizační mechanismy v neomezeném kontextu vlákna při provádění na úrovni IRQL rovné PASSIVE_LEVEL.
Stavy objektů dispečeru
Každý typ objektu dispečera definovaný jádrem má stav, který je buď nastaven na Signaled, nebo nastaven na Not-Signaled.
Skupina vláken může synchronizovat své operace, pokud jedno nebo více vláken volá KeWaitForSingleObject, KeWaitForMutexObjectnebo KeWaitForMultipleObjects. Tyto funkce přebírají ukazatele na objekt dispečera jako vstup a čekají, dokud jiná rutina nebo vlákno nenastaví jeden nebo více objektů dispečera do signalizačního stavu.
Když vlákno volá KeWaitForSingleObject čekat na objekt dispečera (nebo KeWaitForMutexObject pro mutex), vlákno se vloží do čekání stav, dokud objekt dispečera není nastaven na signalovaný stav. Vlákno může volat KeWaitForMultipleObjects, aby čekalo buď na libovolný, nebo na všechny objekty dispečera, které mají být nastaveny na Signaled.
Kdykoli je objekt dispečera nastaven na signalovaný stav, jádro změní stav jakéhokoli vlákna čekající na tento objekt připraveno. (Synchronizační časovače a synchronizační události jsou výjimkami tohoto pravidla; pokud je signalován synchronizační událost nebo časovač, je v připraveném stavu nastaveno pouze jedno čekající vlákno. Další informace najdete v tématu Objekty časovače a dpcs a objekty událostí.) Vlákno v připraveném stavu bude naplánováno tak, aby se spustilo podle aktuálního priority vlákna a aktuální dostupnost procesorů pro jakékoli vlákno s danou prioritou.
Kdy mohou ovladače čekat na objekty dispečera?
Obecně platí, že ovladače mohou čekat na nastavení objektů dispečera pouze v případě, že platí alespoň jedna z následujících okolností:
Ovladač se spouští v kontextu nenáhodného vlákna.
To znamená, že můžete identifikovat vlákno, které přejde do stavu čekání. V praxi jsou jedinými rutinami ovladačů, které se spouštějí v nenáhodném kontextu vlákna, rutiny DriverEntry, AddDevice, Reinitializea Unload u každého ovladače, plus dispečerské rutiny ovladačů nejvyšší úrovně. Všechny tyto rutiny jsou volány přímo systémem.
Ovladač provádí zcela synchronní vstupně-výstupní požadavek.
To znamená, že žádný ovladač nezařadí žádné operace do fronty při zpracování V/V požadavku a žádný ovladač se nevrátí, dokud ovladač pod ním nedokončí zpracování požadavku.
Kromě toho ovladač nemůže vstoupit do stavu čekání, pokud je spuštěn na úrovni IRQL rovnající se nebo vyšší než DISPATCH_LEVEL.
Na základě těchto omezení musíte použít následující pravidla:
Rutiny DriverEntry, AddDevice, Reinitializea Unload rutiny jakéhokoli ovladače mohou čekat na objekty dispečera.
Rutiny pro odesílání u ovladače nejvyšší úrovně mohou čekat na objekty dispečera.
Dispečerské rutiny ovladačů nižší úrovně mohou čekat na dispečerské objekty, pokud je vstupně-výstupní operace synchronní, například při operacích vytvoření, vyprázdnění, vypnutí a zavření, při některých řízení vstupně-výstupních operací zařízení a při některých operacích PnP a napájení.
Rutiny odesílání ovladačů nižší úrovně nemohou čekat na objekt dispečera na dokončení asynchronních vstupně-výstupních operací.
Rutina ovladače, která se spouští v DISPATCH_LEVEL IRQL nebo nad ní, nesmí čekat, než se objekt dispečera nastaví na stav Signaled.
Ovladač se nesmí pokoušet čekat na nastavení objektu dispečera na signalovaný stav pro dokončení operace přenosu do nebo ze stránkovacího zařízení.
Rutiny odesílání ovladačů obsluhující žádosti o čtení a zápis obecně nemohou čekat, až bude objekt dispečera nastaven na signalizovaný stav.
Rutina dispečeru pro požadavek na řízení vstupně-výstupních operací zařízení může čekat, až se objekt dispečera nastaví do signalizačního stavu pouze v případě, že typ přenosu pro kód řízení vstupně-výstupních operací je METHOD_BUFFERED.
Ovladače miniportu SCSI by neměly používat objekty dispečeru jádra. Ovladače miniportu SCSI by měly volat pouze rutiny knihovny portů SCSI.
Každá druhá standardní rutina ovladače se spouští v libovolném kontextu vlákna: v kontextu toho vlákna, které je právě aktuální, když je rutina ovladače volána ke zpracování zařazené operace nebo ke zpracování přerušení zařízení. Většina standardních rutin ovladačů se navíc spouští na vyvýšeném prostředí IRQL, a to buď v DISPATCH_LEVEL, nebo pro ovladače zařízení v DIRQL.
V případě potřeby může ovladač vytvořit vlákno speciálně určené pro zařízení, které může čekat na další rutiny ovladače (s výjimkou ISR nebo SynchCritSection rutina), aby nastavily objekt dispečera do stavu Signaled a resetovaly ho do stavu Not-Signaled.
Obecně platí, že pokud očekáváte, že váš nový ovladač zařízení bude často muset zastavit déle než 50 mikrosekund, zatímco čeká na změny stavu zařízení během vstupně-výstupních operací, zvažte implementaci ovladače s vláknem vyhrazeným zařízením. Pokud je ovladač zařízení také ovladač nejvyšší úrovně, zvažte použití systémových pracovních vláken a implementaci jedné nebo více rutin zpětného volání pracovních vláken. Viz PsCreateSystemThread a Správa vzájemně zablokovaných front pomocí Driver-Created vlákna.