Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Specifika vývoje ovladačů 3

V minulém dílu Specifika vývoje ovladačů 2 jsme se zaměřili na paměť. V tomto díle miniseriálu o různých aspektech vývoje ovladačů se budeme zabývat pouze jedním tématem, které prostupuje celým jádrem a každý vývojář ovladačů by s ním měl být dobře seznámen. Jedná se o mechanismus hardwarových priorit.

Na rozdíl od plánovací priority vláken (a potažmo procesů), hardwarová priorita vlákna neudává, jak často mu bude přidělen procesor, ale jaké úkony může vykonávat. Přitom platí, že kód běžící s hardwarovou prioritou X může být přerušen (přeplánován) pouze kódem s hardwarovou prioritou Y > X. Čím vyšší hardwarovou prioritou vlákno disponuje, tím méně věcí může provádět, ale tím menší množství událostí může přerušit jeho běh. Termín hardwarová priorita je mnou vymyšlený český ekvivalent sousloví interrupt request level (IRQL), jež se používá v dokumentaci.

Existuje 32 různých hardwarových priorit pro 32bitová a 16 pro 64bitová Windows. Nejdůležitější hodnoty jsou 0 (PASSIVE_LEVEL), 1 (APC_LEVEL), 2 (DISPATCH_LEVEL) a 31 (resp. 15) (HIGH_LEVEL). Tabulka 1 popisuje jaká omezení tyto priority kladou na vykonávaný kód.

Tabulka 1: Přehled nejdůležitějších IRQL a jejich omezení

  PASSIVE_LEVEL APC_LEVEL DISPATCH_LEVEL HIGH_LEVEL
Pasivní čekání ANO ANO NE NE
Aktivní čekání ANO ANO ANO ANO
Stránkovaná paměť ANO ANO NE NE
Alokace paměti ANO ANO ANO* NE
API ANO NE NE NE

Vlákno pasivně čeká, pokud není naplánováno na procesoru a zároveň pro jeho možný běh je třeba splnit nějakou další podmínku, například dokončit čtení dat z disku. Pasivní čekání je nutnou podmínkou pro téměř všechny nevýpočetní činnosti a samozřejmě pro samotný plánovač vláken. Jeho nedostupnost od DISPATCH_LEVEL výše velmi omezuje možnosti, které vývojář ovladače na dané hardwarové prioritě má.

Při Aktivním čekání vlákno běží na procesoru a neustále testuje, zda je určitá podmínka splněna či stále ještě ne. Jelikož tento druh čekání nevyžaduje žádnou podporu od operačního systému, je možné jej provádět na libovolné IRQL.

Jak bylo řečeno v minulém dílu, stránkovaná paměť může být systémem odložena na disk a odtud načtena až v okamžiku potřeby. Jelikož pro takový úkon je potřeba na načtení dat (pasivně) počkat, ke stránkované paměti nelze přistupovat a ani ji (de)alokovat na IRQL >= DISPATCH_LEVEL.

Do oblasti nestránkované paměti (případně stránkované paměti, které bylo zakázáno odebrat se na disk) je možné přistupovat na libovolné HW prioritě. Jediné omezení platí pro její (de)alokaci, tyto činnosti je nutné provádět maximálně na APC_LEVEL (DISPATCH_LEVEL pro nestránkovanou).

Na úrovni DISPATCH_LEVEL je vykonávána většina rutin plánovače. Díky tomu je možné například přeplánovat vlákno běžící na PASSIVE_LEVEL jiným vláknem na stejné hardwarové prioritě, ač to poučka uvedená výše zdánlivě zakazuje. Trik spočívá v tom, že plánovač IRQL zvýší na DISPATCH_LEVEL, provede vlastní přeplánování a následně ji sníží na úroveň nově naplánovaného vlákna. Dočasné zvýšení IRQL patří mezi legitimní kroky, nedochází tedy k porušení žádného jaderného zákona.

Obrázek níže ilustruje situaci popsanou v předchozím odstavci. Na procesoru nejprve běží vlákno A na IRQL APC_LEVEL. Po určité době plánovač usoudí, že nastal čas na změnu; IRQL se zvýší na DISPATCH_LEVEL a dojde k naplánování vlákna B. Plánovač pak svoji intervenci ukončí a nechá běžet vlákno B. IRQL klesne na poslední známou hodnotu pro vlákno B, což je v tomto případě PASSIVE_LEVEL. Díky dočasnému zvýšení na DISPATCH_LEVEL nedošlo k porušení žádného jaderného pravidla.

Zdánlivé porušení pravidla o hardwarových prioritách - Pokročilé postupy pro Windows

Z předchozího odstavce také vyplývá, že pokud vlákno zvedne HW prioritu nad APC_LEVEL, nemůže jej z aktuálního procesoru nikdo "vyštípat". Může být krátkodobě přerušeno jinými událostmi nastávajícími na vyšších IRQL (hardwarová přerušení, časovač, meziprocesorová komunikace...), ty jej ale nemohou přeplánovat. Z tohoto důvodu na vyšších IRQL nedává příliš smysl mluvit o vláknech, ale jen o procesorech.

Vzhledem k výše popsaným omezením je cílem každého ovladače vykonávat maximum kódu na IRQL PASSIVE_LEVEL (přinejhorším na APC_LEVEL). Pro sestoupení z vyšších IRQL na nižší existují dokumentované postupy, jenž spočívají v tom, že ovladač naplánuje operaci, kterou potřebuje vykonat na nízké IRQL, na pozdější dobu a vrátí řízení jádru systému. Na provedení operace nemůže počkat, neb služby plánovače nejsou na vyšších IRQL dostupné. Tyto mechanismy se nazývají odložené volání procedury a pracovní vlákna.

Odložené volání procedury (Deferred Procedure Call – DPC) slouží k snížení hodnoty IRQL na DISPATCH_LEVEL. Nejčastější použití nalezneme v obslužných rutinách přerušení. Například stisknutí klávesy na notebookové klávesnici vyvolá hardwarové přerušení, které zpracovává ovladač i8042prt.sys. Jeho obslužná rutina je, jak to u přerušení bývá, volána na IRQL > DISPATCH_LEVEL, a tak jsou její možnosti velmi omezené. Ovladač tedy pouze zjistí, k jaké události klávesnice došlo (včetně toho, jaká klávesa byla stisknuta) a požádá systém, aby, až IRQL dostatečně klesne, zavolal určitou funkci a předal jí zjištěné informace v parametrech. Tím vlastně odloží zpracování informací na příhodnější dobu. Bezesporu není bez zajímavosti, že si ovladač může vybrat procesor, na kterém má být odložená procedura vykonána.

Pokud při zpracování informací ovladač usoudí, že úroveň DISPATCH_LEVEL je pro něj stále příliš vysoká, může požádat o pomoc některé z tzv. pracovních vláken (worker threads) – množiny vláken běžících na IRQL PASSIVE_LEVEL a vykonávajících práci, kterou jim zadá libovolná komponenta jádra. Práce v tomto případě znamená volání funkce se zadaným parametrem. Mechanismus je tedy navenek značně podobný DPC. Jakmile se ovladač dostane na PASSIVE_LEVEL, může například provádět zápisy do registru či do souboru, což jsou operace na vyšších IRQL zakázané.

Systém se ovladače pro vykonávání maxima kódu na nízkých IRQL snaží donutit také tím, že omezuje časový interval, který lze na vyšších úrovních strávit. Pokud jej ovladač překročí, dochází k modré obrazovce smrti. Vzhledem k tomu, že ovladače jsou vlastně DLL knihovny, které systém zavolá, když je potřeba, splnění tohoto požadavku obvykle nepředstavuje velký problém – ovladač udělá, co musí, a v případě potřeby použije mechanismus pro snížení IRQL a předá řízení zpět volajícímu.

Časový limit pro běh kódu na IRQL >= DISPATCH_LEVEL má svůj význam, protože na procesorech s tímto IRQL nefunguje plánovač, což narušuje iluzi současného vykonávání mnoha úkolů.


 

Všechny články v sekci
Pokročilé postupy pro Windows
Článek pro vás napsal Martin Dráb
Avatar
Uživatelské hodnocení:
1 hlasů
Autor se věnuje studiu obecné teorie operačních systémů, vnitřnímu uspořádání jádra OS Windows, trochu také matematice a šifrování
Aktivity