Ugrás a tartalomhoz

Operációs rendszerek mérnöki megközelítésben

Benyó Balázs, Fék Márk, Kiss István, Kóczy Annamária, Kondorosi Károly, Mészáros Tamás, Román Gyula, Szeberényi Imre, Sziray József

Panem Kiadó

6.3. A Windows NT belső mechanizmusai

6.3. A Windows NT belső mechanizmusai

A Windows NT számos olyan mechanizmussal rendelkezik, amelyeket a kernel módú komponensek, mint az executive, valamint a device driverek használnak. Ebben a részben a következő rendszermechanizmusokat mutatjuk be:

  • megszakítás- és kivételkezelés,

  • executive objektumkezelés,

  • szinkronizáció,

  • lokális eljárás hívás (Local Procedure Calls -LPC’s).

6.3.1. Megszakítás- és kivételkezelés

A megszakítások (IT: interrupt) és a kivételek (exception) olyan események az operációs rendszerben, amelyek a CPU-t eltérítik az utasítások normál végrehajtási sorrendjétől. A megszakításokat és a kivételeket detektálhatják a rendszer hardver, és szoftver komponensei egyaránt.

Az NT-hez kapcsolódó szóhasználatban a trap (csapda) fogalom a processzor azon mechanizmusát jelöli, amelynek segítségével az egy végrehajtás alatt levő szálat állít meg egy megszakítás, vagy egy kivétel hatására. A trap mechanizmus a processzort felhasználói módról kernel módra kapcsolja át, és a vezérlést az operációs rendszer egy fix helyére, a trapkezelő rutinra adja át. A trapkezelő eldönti, melyik operációs rendszer komponens képes a megszakítást, vagy kivételt kiváltó eseményt lekezelni. A teljes képhez hozzátartozik, hogy a trapkezelő aktivizálódik a rendszer hívások végrehajtásakor is, amikor a megszakítások és kivételek kezeléséhez hasonlóan a rendszernek kernel módba kell váltania. A trapkezelő és az általa megvalósított funkciók összefoglalását a 6.4. ábrán láthatjuk.

6. 4. ábra. ábra - A trapkezelő működése

A trapkezelő működése


Bár általában igaz az, hogy a megszakítást hardveregység, a kivételt pedig szoftverkomponens idézi elő, ez nem feltétlenül igaz minden esetben. Hardver eredetű kivételre példa a buszhiba által kiváltott kivétel melynek forrása hardver meghibásodás. Szoftver által generált megszakításra is találunk bőségesen példát az NT-ben. Az NT kernel szoftvermegszakításokkal kezeli néhány esetben a futó szál váltását, az időzített óra lejárását, illetve néhány szinkron B/K-folyamatot.

6.3.1.1. A megszakítások típusa és prioritása

A különböző processzorok különböző számú és típusú megszakítást képesek felismerni. A megszakításokhoz prioritási szinteket (ún. IRQL: Interrupt Request Level) rendel az operációs rendszer. A párhuzamosan érkező megszakítások kiszolgálása a prioritási szinteknek megfelelően történik. A magasabb prioritású IT megszakítja az alacsonyabb prioritású IT kiszolgálását. A 6.5. ábra a DEC Alpha processzorhoz tartozó megszakítási szintek tábláját (IRQL-táblát) mutatja be, a 6.6. ábra pedig az Intel x86-os processzorokhoz tartozót.

6.5. ábra. ábra - IRQL tábla az Alpha processzornál

IRQL tábla az Alpha processzornál


6.6. ábra. ábra - IRQL tábla az Intel x86 processzoroknál

IRQL tábla az Intel x86 processzoroknál


A megszakítások felső szintjei a hardver-megszakításokra vannak fenntartva. Az 1-es és 2-es szintek mindkét táblázatban a szoftver-megszakítások. A késleltetett eljáráshívást eredményező IT-re egyes szálak biztonságos végrehajtása érdekében van szükség. Az aszinkron eljáráshívások a felhasználói programok, illetve rendszerprogramok számára biztosítanak lehetőséget, hogy egy másik felhasználói szálon hajthassanak végre (hívjanak meg) egy eljárást.

A legalsó, nullás szint a normál szálvégrehajtáshoz tartozik. Ezen a szinten minden IT engedélyezett.

6.3.1.2. Kivételkezelés

A bármikor fellépő megszakításokkal ellentétben a kivételek olyan feltételek, amelyek egy futásban levő program végrehajtása következtében jönnek létre. A kivételeket egy speciális kernelmodul, a kivétel-felügyelő (exception dis­patcher) dolgozza fel. A kivétel-felügyelő elsődleges feladata az aktuális kivétel azonosítása: memória-túlcímzés, nullával való osztás, egész-túlcsordulás, lebegőpontos kivételek, a nyomkövető töréspontjai stb. Ezek mindegyike architektúrafüggetlen eset.

Amikor egy kivétel lép fel, a kernelben egy eseményláncolat indul el. A CPU a vezérlést a kernel trapkezelőjének adja át. Ez egy ún. trapkeretet állít elő, amely mindazt az információt tartalmazza, ami a kivételkezelés befejezése utáni visszatéréshez (újrakezdéshez) szükséges az operációs rendszer számára. A trapkezelő ezen kívül még előállít egy rekordot, ami a kivétel eredetét rögzíti, és más szükséges információt tartalmaz.

A nyomkövető programok töréspontjai rendszeresen kivétel­források. Emiatt a kivétel-felügyelő első teendője annak ellenőrzése, hogy a kivétel egy nyomkövető folyamattól származik-e.

6.3.2. Objektumkezelés

A Windows NT-ben levő executive egyik komponense az objektumkezelő (object manager), amely az objektumok előállítására, törlésére, védelmére, és kezelésére szolgál. Az objektumkezelő összefogja az erőforrás-kezelő műveleteket, hogy azok ne legyenek szétszórva az operációs rendszer egyes komponenseibe.

Az objektumkezelőt a következő célok elérésére tervezték:

  • Egységes mechanizmust biztosítson a rendszer erőforrásainak elérésére, illetve használatára.

  • Az objektumok védelmét megvalósító kód egy helyre legyen összegyűjtve, a C2-es szintű biztonság elérése érdekében.

  • Lehetőséget biztosítson a folyamatok objektumhasználatának figyelésére, amivel korlátozható a rendszer erőforrásainak használata.

  • Olyan objektum-elnevezési módszert valósítson meg, ami lehetővé teszi a létező objektumcsoportok egyszerű megkülönböztetését.

  • Elégítse ki a különböző alrendszerek által támasztott követelményeket: például egy folyamat legyen képes erőforrásokat örökölni szülőjétől (erre szükség van a Win32-es és a POSIX alrendszernél), vagy lehessen kis- és nagybetűt megkülönböztető (case sensitive) neveket használni (ami a POSIX alrendszer követelménye).

  • Egységes szabályok szerint kezelje az objektumok „életben tartását”, vagyis egy objektum mindaddig álljon rendelkezésre, amíg az összes folyamat be nem fejezte használatát.

Belülről a Windows NT kétfajta objektummal rendelkezik: executive objektummal és kernel objektummal. Az executive objektumokat az executive réteg különböző komponensei hozzák létre, mint például a folyamatkezelő, memóriakezelő, B/K-alrendszer stb.

A kernel objektumok sokkal egyszerűbbek, mint az executive objektumok. Olyan alapvető funkciókat valósítanak meg, mint például a szinkronizáció, amely funkciókra az executive objektumok is épülnek. Az executive objektumok általában több kernel objektumból épülnek fel.

Amikor egy folyamat létrehoz és megnyit egy objektumot név szerint, akkor egy ún. handle-t kap vissza (a szó jelentése fogantyú, nyél, de a magyar elnevezést nem tartjuk megfelelőnek). A handle az objektumhoz való hozzáférési információt tartalmazza. Valójában nem más, mint egy összetett elérési cím, egy összetett pointer, aminek használatával jóval gyorsabban lehet elérni egy objektumot, mint a név szerinti kereséssel.

6.3.3. Szinkronizáció

A kölcsönös kizárás megvalósítása alapvető fontosságú az operációs rendszerekben elsősorban a nem osztott elérésű erőforrások használatának szabályozására (például akár a rendszer összetett adatszerkezetei esetén).

A kölcsönös kizárás különösen fontos a Windows NT esetében, amely támogatja a szorosan csatolt szimmetrikus-multiprocesszoros hardver architektúrát. Az egyes processzorok ugyanazt a rendszerkódot hajtják végre egy-idejűleg, bizonyos, közös memóriában tárolt adatstruktúrák megosztásával.

A Windows NT-ben a kernel feladata a több szál által is használt adatstruktúrák használatának összehangolása. A kernel ennek a feladatnak a megoldására a kölcsönös kizárást megvalósító alapmodulokat (ún. primitíveket) tartalmaz. Ezeket a primitíveket a kernelen kívül az executive réteg is használja a közös adatstruktúrák elérésének időbeli összehango­lása, szinkronizálása céljából.

6.3.3.1. Kernel szinkronizáció

A kernel kód végrehajtásának különböző fázisaiban a kernelnek garantálnia kell, hogy egy kritikus szakaszt kizárólag csak egyetlen processzor hajt végre. A kernelben a kritikus szakaszokban lévő kódrészek módosítják a globális adatstruktúrákat (például a késleltetett eljáráshívások várakozási sora vagy a kernel dispatcher adatbázisa).

A szinkronizáció során a legnagyobb gondot a megszakítások jelentik. Előfordulhat például, hogy a kernel egy globális adatstruktúrát módosít, amikor egy olyan IT lép fel, aminek a kezelő rutinja éppen ugyanazt a struktúrát módosítaná. Egy processzor esetén a Windows NT a következő mechanizmust alkalmazza.

A kernel a globális erőforrások használata előtt ideiglenesen letiltja azokat az IT-ket, amelyeknek az IT-kezelő programja ugyanazt az erőforrást használja. Ehhez fel kell emelnie a processzor futási szintjét a szóban forgó megszakítások közül a leg­magasabb szintjére.

Ez a megoldás azonban nem elégséges több processzor esetén. Ugyanis a futási szint megemelése egy processzornál még nem akadályozza meg egy megszakítás fellépését egy másik processzoron. A kernelnek azonban ilyenkor is garantálnia kell a kölcsönös kizárást az erőforrások használatakor. A kölcsönös kizárás megvalósítására a Windows NT ezért az egyedi lezárás (locking) módszerét alkalmazza. A kizárással használandó erőforrásokat – így a globális adatstruktúrákat – használatuk előtt az erőforrást használni kívánó szálnak le kell zárnia, meg kell szereznie az erőforráshoz tartozó ún. spin­lockot. Amíg ezt nem tudja megtenni, várakoznia kell. A rendszer az egyes hozzáférési igényeket sorba állítja, és a lezárás megszűnésekor mindig csak egy várakozót enged tovább.

6.3.3.2. Executive szinkronizáció

A multiprocesszoros környezetben az executive réteg komponenseinek is szinkronizálnia kell a globális adatstruktúrákhoz való hozzáférést. A kernel funkciók hívásakor az executive is használhatja a lezárás módszerét. Ez azonban csak részben oldja meg az executive réteg szinkronizációs igényeit. Mivel egy lezárás feloldására történő várakozás ténylegesen is várakoztatja az érintett CPU-t, a megoldás csak az alábbi korlátozásokkal alkalmazható:

  • a védett erőforrásnak gyorsan elérhetőnek kell lennie anélkül, hogy más kóddal komplikált kapcsolatban állna,

  • a kritikus szakaszok nem lapozhatók ki a memóriából, nem hívhatnak külső eljárásokat (rendszerszolgáltatást sem), továbbá nem generálhatnak megszakítást vagy kivételt.

A fenti szigorú korlátozások sajnos nem tarthatók be minden esetben. Ráadásul az executive réteg különböző működéseinek szinkronizációja nemcsak a kölcsönös kizárást, hanem más típusú szinkronizációt (előidejűség, egyidejűség) is igényelnek. Ezen felül szinkronizációs lehetőséget kell biztosítani a felhasználói alkalmazások számára is.

Mindezeket a feladatokat speciális szinkronizációs objektumok kezelésével valósítja meg a Windows NT. Ezeket az objektumokat együttesen diszpécser objektumoknak (dispatcher object) nevezzük. A rendszer biztosít megfelelő függvényhívásokat (WaitForSingleObject, WaitForMultipleObject), me­lyek meghívásakor az ütemező az adott szálat várakozó (waiting) állapotba viszi és berakja a megnevezett objektum várakozási sorába. Az objektum felszabadulásakor a rendszer az objektum típusától függően egy vagy több várakozó folyamatot futásra kész (ready) állapotba tesz.

A dispatcher objectek között létezik például a kölcsönos kizárást megvalósító ún. mutex objektum, mely esetén mindig csak egy várakozó szál lesz futásra kész, de van olyan, mint például a semaphore, ahol – a semaphore ini­cializálási értékétől függően – akár több is lehet. Sőt létezik olyan dis­patcher object is – a timer –, ami szabaddá válása (lejárása) esetén minden, az objektumra várakozó szál átkerül a ready állapotba. Így az executive rétegben lehetőség van bonyolult szinkronizációs feladatok megoldására is.

A dispatcher objectek és azokat kezelő hívások egy része a Win32 API-n keresztül is elérhető, lehetővé téve a szinkronizációt a felhasználói alkalmazások számára is.

6.3.4. Lokális eljáráshívás

A lokális eljáráshívás (LPC: Local Procedure Call) a folyamatok közötti kommunikációra ad lehetőséget, nagysebességű üzenettovábbítás formájában. Ez a belső mechanizmus csak a Windows NT operációs rendszer komponensei számára áll rendelkezésre, a Win32 API-n keresztül nem érhető el. Két példa az LPC-k használatára:

  • Távoli eljáráshívások (Remote Procedure Call) LPC-t használnak akkor, ha a kommunikáló folyamatok ugyanazon a rendszeren belül vannak.

  • A felhasználói bejelentkezéseket kezelő WinLogon processz LPC-hívásokat használ arra, hogy kommunikáljon helyi biztonsági jogosultság ellenőrző szerverrel (LSASS).

Az LPC-kommunikációt leggyakrabban az NT szolgáltatásait megvalósító szerver folyamatok használják a kliens folyamatokkal történő kapcsolattartásra. LPC-kapcsolat létrehozható két felhasználói módú folyamat között, vagy egy kernel módú komponens és egy felhasználói módú folyamat között.

Az LPC az üzenetváltás három különböző formáját teszi lehetővé:

  • A 256 bájtnál rövidebb üzenet úgy küldhető el, hogy az LPC-üzenet küldésekor közvetlenül megadjuk egy pufferben az üzenetet. Az üzenetet a rendszer a híváskor átmásolja a saját címtartományába, majd onnan a hívott folyamat címtartományába.

  • Ha egy kliens és egy szerver 256 bájtnál több adatot szeretne továbbítani, akkor mindketten meg kell hogy nyissanak egy osztott elérésű memóriaterületet. A küldő az üzenetet eltárolja az osztott elérésű memóriába, majd egy rövid LPC-üzenetet (lásd első eset) küld a hí­vott folyamatnak, melyben egy pointert ad az üzenet kezdetére.

  • Ha egy szerver több adatot akar írni vagy olvasni, mint amennyi az osztott elérésű memórialapon elférne, akkor a szerver folyamat – megfelelő elérési tokenek megszerzése után – közvetlenül is elérheti a kliens címtartományát, ahonnan tud olvasni és oda írni. A üzenetváltás szinkronizálására megint csak rövid üzeneteket (lásd első eset) használhatnak a kommunikáló folyamatok.