Nem is akarok a közepébe vágni: hiszen ahelyett, hogy egyből elrettentenék minden tisztelt olvasót, inkább egy rövid elmélettel kezdeném. A teljesen kezdők ezt nevezhetik alapozásnak, a kicsit tapasztaltabbak ismétlésnek, a profik pedig a stílusommal való ismerkedésnek. Ezen alapozó-bevezető-ismétlő rész során igyekszek minden fontosabb elemre kitérni, de a cél az lenne, hogy egy modern mikrokernel megismeréséhez szükséges ismereteket tisztázzunk-vezessünk be. A cikkhez kapcsolódó fórumon természetesen tovább lehet boncolgatni egy-egy fogalmat - vagy ajánlom elolvasásra A.S. Tannenbaum és A.S. Woodhull könyvét, az Operációs rendszereket (Panem, 1999).

Induljunk el onnan, hogy valójában mit is nevezünk operációs rendszernek. Ha egy nyelvész felfogásán keresztül közelítjük meg, akkor ezt magyarul úgy is mondhatnánk, hogy "működtető rendszer" - így talán kicsit közelebb kerülünk a probléma megoldásához. Valójában azokat a szoftvereket van alapunk így nevezni, melyek egy adott hardvereszközt, vagy hardvereszközök együttesét működteti. Ebbe valójában nem tartozik bele semmi grafikus sallang és csillogás. Pedig ne feledjük el, hogy valakinek a működtető rendszert is működtetni kell - ez lesz az a fogalom, amit nyilván mindenki hallott már: a felhasználó. Tehát ezért nyugodtan állíthatjuk hogy egy OS, ami ad magára, rendelkezik olyan felülettel, amelyen keresztül bárki játszi könnyedséggel elérheti az adott rendszer képességeit. Itt az OS egy rövidítés, ami az "Operating System" szóból származik - a magyar szakmai zsargon is igen gyakran használja. Visszatérve a felülethez: ez az a grafikus sallang, amiről az előbb beszéltem.

Következtetés

Miután sikerült valami magyarázatot találni az "operációs rendszer"-ben az operációs szóra, akkor nézzük meg azt is, hogy mitől rendszer ez. Igen, újból helyeselnem kell, amennyiben az olvasó is bólogat: egy operációs rendszer bizony így magában csak egy fogalom, és nem egyetlen konkrét szoftver személyesíti meg, hanem több program - együttesen.

"A híd"

"Az operációs rendszer a híd az ember és a gép között" - Emlékszem, ezt mondtam, mikor egyszer papírra kellett vetnem, mit is értek az operációs rendszer fogalma alatt. Ha nagyon precíz akarnék lenni, természetesen hozzá kellene tennem, hogy nem feltétlenül csak az ember-gép kapcsolatot, hanem a gép-gép, program-program kommunikációját is lehetővé teszi egy OS. Viszont ebből a legtöbben mindig csak azt az oldalát tapasztálják, amikor mondjuk egy parancssort látnak villogó kurzorral, vagy egy "laza duplakattal" elindítják kedvenc stratégiai játékukat.

Ha már ennyire körüljártuk az operációs rendszert, mint fogalmat, nézzük meg egy informatikus szemszögéből is, hogy mit csinál! A szakirodalom szerint két nézet terjedt el: az egyikben egy erőforráskezelővel, a másikban pedig egy virtuális géppel állunk szemben. No, eddig volt egyetlen ködös fogalmunk, és most kaptunk helyette még kettőt. A következő fejezetekben ezeket bogozzuk ki.

Egy OS mint erőforráskezelő

"Röviden ebből a nézőpontból az operációs rendszer elsőrendű feladata, hogy nyilvántartsa, ki melyik erőforrást használja, hogy teljesítse az erőforráskéréseket, hogy mérje a használatot és hogy a különböző programok és felhasználók ellentmondásos kérdéseit egyeztesse."[0]

Ekkor tehát minden hardvereszközt (nyomtató, memória, videókártya, stb.) a számítógépünkben szépen nyilvántartásba veszünk, és ezentúl ezeket csak lengéden erőforrásoknak nevezzük. Bár szerintem ez nem éppen a legszerencsésebb fordítás, mert ha felütjük a szótárat a "resource" szónál - ennek a tükörfordítása az erőforrás - akkor találhatunk erre sokkal szebb szavakat is: ilyen például a "készlet". Amik használják az erőforrásokat, azok pedig a futtatott programok. Később még rendesen össze fogjuk zavarni a képet a programok terén is - most egyenlőre elégedjünk meg annyival, hogy ebben a szituációban folyamatoknak, processzeknek, vagy processzusoknak nevezzük őket hivatalosan. Általában minden ilyen processzus pályázik a processzorra - vagy ha több van, akkor azok egy részhalmazára - és igényel némi memóriát is. Ezeket így szinte minden esetben ki kell osztani, és fel kell jegyezni, hogy "kinél miből mennyi van". De ahhoz, hogy egy processzus használhasson egy erőforrást az alanyi jogon biztosított processzoridő és memóriaszelet mellé, bizony "külön kérvényt kell benyújtania" az operációs rendszer felé. Mielőtt szélsebesen száguldanánk tovább, megállnék itt egy kicsit. Szerintem vannak olyanok, akinek nem tiszta mit is nevezünk processzoridőnek. Napjaink OS-einek szinte mindegyike ún. időosztásos (time sharing) rendszerben működik. Ez azt jelenti, hogy a processzusok kapnak egy időmennyiséget - ezt kvantumnak nevezik - amely ideig a processzor csak ő rendelkezésükre áll. Ha letelik ez az idő, akkor egy másik processzus kap lehetőséget a "garázdálkodásra". Ezt a folyamatot gyorsan ismételgetve - másodpercenkét igen sokszor - egy egyszerre több feladatot végző számítógép illúzióját kapjuk. Most csak ennyit róla - időben erről is mesélek még. Visszatérve a korábbi témára: Az operációs rendszer - tudatában az összes erőforrás állapotának - mérlegeli a hozzá benyújtott kérvényeket (nincs-e már "valakinél oda", vagy "van-e még raktáron belőle"), és siker esetén az elfogadásra kerül - a processzus megkapja a hőn áhított erőforrást. Komolyabban ezzel a témával találkozunk még a holtpontok kezelésénél is.

Szemléltessük egy egyszerű, valós életből vett példán:

Egy irodában vagyunk, és szeretnénk valamilyen fontos információt feljegyezni egy papírra. Jelen pillanatban nem rendelkezünk sem papírral, sem tollal, de adva van a cél - vagyis egy program. Ahhoz, hogy ezt a célt véghez vigyük, megyünk és megkeressük az iroda vezetőjét, és írunk neki egy beadványt, hogy szeretnénk kérni egy tollat és egy papírt. Szépen szignózzuk, és odaadjuk neki. Õ ezt elveszi, majd átolvassa - miközben lapozgatja a noteszét. Ezek után kiböki, hogy rendben, ad egy lapot, de tollat sajnos most nem tud adni, mert már a kollégáink elvitték az összeset. Mivel mi még mindig le akarjuk írni a fejünkben kószáló - de el még nem felejtett :) - gondolatot, úgy döntünk, hogy megvárjuk, míg visszahoznak egy tollat. Tehát várunk egy kicsit, és megjelenik egy ismerősünk, aki visszahozott egy tollat. Ekkor a főnök morcosan a kezünkbe nyomja a tollat egy 'Nesze' felkiáltással, és most már írhatunk is.

Ebben a példában a toll és a papít voltak az erőforrások, az iroda vezetője az operációs rendszer kernele (erről ld. később!), az alkalmazottak pedig a processzusok.

Egy OS mint virtuális gép

"Ebből a nézőpontból az operációs rendszer feladata az, hogy a felhasználónak egy olyan egyenértékű kiterjesztett gépet vagy virtuális gépet nyújtson, amelyiket egyszerűbb programozni, mint a mögöttes hardvert."[1]

Ebben az esetben az operációs rendszert tekinthetjük egy egységes felületnek, vagy egy olyan számítógépnek, amely akár teljesen már paraméterekkel is rendelkezhet mint valójában. Minden processzus számára úgy viselkedik, mintha kizárólag csak az éppen futó processzus birtokolná a számítógépet, a kvázi párhuzamosan futó társairól ha nem akar, akkor nem is tud! A "virtuális" szót általában úgy szokták magyarázni, hogy "olyan, ami van, de mégsincs". Így átfogalmazva a virtuális gép egy olyan gép, ami nincs, de közben mégis van :)

A fentiekre példaként hozhatnánk ide a Windows® és elődjének, az MS-DOS®-nak a kapcsolatát. Ugyanis mikor Windows alatt futtatunk egy DOS-ban - és ezáltal DOS-ra - írt programo, akkor annak fogalma sincs arról, hogy nem DOS alatt fut. Természetesen léteznek módszerek, mellyel kideríthető a turpiszság, de most tekintsük az optimális esetet. Mivel a DOS nem volt nevezhető - a 4.0-ás verzió ellenére - multiprogramozott rendszernek, így a lehetőségeit követő programok joggal képzelhetik azt, hogy övék az egész számítógép. Itt a multiprogramozottság azt jelenti, hogy a korábban említett időosztásos módra fel van készítve az operációs rendszer.

További előnye a virtuális gépeknek, hogy többnek vagy éppen kevesebbnek tudnak látszani, mint "földhözragadt" társaik - ekkor valójában már kiterjesztett gépekről beszélünk. Segítségükkel tehát az operációs rendszer képes kiterjeszteni erőforrásokat. Ennek iskolapéldája a virtuális memória, vagyis a merevlemez tárkapacitásának egy részét a fizikai - a gépben lévő - memória kipótlására használjuk fel. De ugyanígy végig lehet gondolni akár a különböző kompatibilitási problémák feloldására szolgáló lehetőségeket, vagy a számtalan DVD/CD-olvasót szimuláló programot (DaemonTools, Virtual CD et al), RAM-diszkeket. A RAM-diszk esetében a virtuális memóriát visszafele játsszuk el: a fizikai memóriát a merevlemezhez hasonlóan adatok tárolására használjuk fel.

A virtuális gép egyben megteremti a felhasználók számára azt a lehetőséget, hogy bizonyos absztrakciók mentén használhassák és/vagy programozhassák a komputerüket. Ekkor ugyanis nem nekünk - a felhasználóknak - kell például megkeresnünk egy kijelölt állományt megkeresni a háttértáron és azt byte-onként beolvasni. Hiszen elég, ha csak közüljük az operációs rendszerrel, hogy a fájlrendszerben milyen néven nyilvántartott "akta" tartalmát kívánjuk elérni. Ehhez nem kell tudnunk se azt, hogy miképp működik a fájlrendszert (naplózott, titkosított), sem pedig azt, hogy az állomány fizikailag pontosan hol is található. Az operációs rendszerek terén a UNIX® jár az élen ebben a versenyben, hiszen nem csak egy filozófiát alapozott meg, hanem aránnyá vált a következő mondás is: "A UNIX-ban minden fájl." Ez arra utal, hogy minden erőforrás a rendszerben a fájlrendszeren keresztül is elérhető, általában a /dev könyvtárból.

Egy rendszer anatómiája

Minden operációs rendszer lelke és elmaradhatatlan kelléke a kernel. Megesik persze az is, hogy az egész erről kapja a nevét, de szerencsére a legtöbb esetben a többi komponensnek is van lehetősége kibontakozni mellette :) Tagadhatatlan, hogy a kernel adja a működőképesség igen nagy részét; mind az erőforrásokat kezeli, és a másik oldalról pedig támogatja a virtuális gépeket. De ne felejtsük el: önmagában nem képes működni! Olyan a kofa és a portékája: ha nincs kinek eladni, akkor lehet akármilyen jó minőségű is az.

A kernelek megvalósítására az idők folyamán több módszer is született, ezeket fogjuk most áttekinteni a következő fejezetekben. Ezt folytatóan még hozzáteszek valamennyit a rendszerkönyvtárakról és a rájuk épülő rendszerprogramokról is.

A klasszikus kernel

A klasszikus esetben a kernel nem más, mint egy halom rendszerhívás (system call). Elevenítsük fel, mi is a rendszerhívás. Nem más, mint egy alprogram (subroutine), amelyet az adott operációs rendszer alá készült programokból meghívhatunk (call, invoke). Akik egy cseppet is programoztak már, azoknak talán jelent valamit ez a két fogalom. Az alprogram lényegében a programunk egy darabja, ami mentén strukturáltuk azt. Minden alprogram valamilyen feladatot lát el, és általában paraméterezhető - az adott feladat több megoldását is tartalmazza. A meghívás pedig nem más, mint hivatkozás egy alprogramra, és ha vannak paraméterei, akkor azok megadása. Az alprogramokat ismertebb nevüken gyakran függvénynek és eljárásnak szokták szólítani. Egy rendszerhívás esetén a meghívás azt jelenti, hogy a program végrehajtása során a hívási ponttól átadjuk a vezérlést a kernelnek. Ha nagyon szigorúan vesszük, ekkor már nem is a processzusunk fut, hanem maga az operációs rendszer - a kernel által képviselve. Amint befejeződött a rendszerhívás tevékenysége (pl. sikerült megtudakolnia a számítógéptől a pontos időt), akkor mint minden alprogram esetében, visszatérhetünk a hívás helyére, vagyis a hívó programhoz. Ezt a szakkönyvek csapdázásnak (trapping) hívják, ezért a rendszerhívás előfordulhat kernel trap néven is. A végén azért szeretném tisztázni: a kernel csak a rendszerhívás kódját - programját - tartalmazza, de maga a hívás legtöbbször különböző rendszerkönyvtárakon keresztül, ellenőrzötten történik.

A "trap" a szakzsargonban a szoftveres megszakítás neve. Ha valaki találkozott már közelről operációs rendszerrel - itt a DOS is megteszi - akkor tudhatja, hogy a rendszerhívások általában megszakításon keresztül történnek. Ha valaki még emlékszik, akkor az volt a 21 hexadecimális kódú megszakítás (INT 21h), UNIX alatt a 80h. Egy ilyen megszakítás során több mint valószínű, hogy a processzor privilegizált módban fog futni; tehát ha kernel egy órási baklövést követ el - itt nem egy mezei laphibára gondolok - akkor nagyon gyakran pánik vagy kék halál az eredménye. Ezt a példát azért hoztam fel, hogy érzékeltessem, hogy mennyire fontos egy klasszikus kernel megírása során a programhibák kiküszöbölése. Viszont nem kerülhetjük el a használatát, mert kizárólag csak itt érhetőek el bizonyos gépi utasítások; ezek közé tartozik mondjuk a bemeneti/kimeneti kapuk (Input/Output port - I/O port) olvasása, írása. Tehát ha ilyet akarunk végrehajtatni egy programból, akkor ezt csak a kernelen keresztül tehetjük meg. Erre a védelemre azért van szükség, mert ez az egyike a korlátozottan rendelkezésre álló erőforrásoknak. Viszont a védelem kezelésével az OS markába nyomjuk az marshallbotot, és ő képessé válik kiterjeszteni, vagy megtöbbszörözni ezt az erőforrást.

Az ilyen típusú kernelek egyetlen óriási bináris állományt alkotnak, ez a szervezési mód egyike a legősibb struktúráknak. Előnye, hogy nagyon gyors, mert belsejében - amit kernel space-nek is neveznek - minden közvetlenül hozzáfér mindenhez. Hátránya, hogy nem - vagy csak kis mértékben, esetleg túlságosan költségesen - valósít még védelmet a különböző funkciók között, mert belsejében minden közvetlenül hozzáfér mindehez... Mellesleg nem elég rugalmas, mert az egész kernelt csak egyben lehet cserélni. Ezen próbáltak javítani a monolitikus kernelek modulárissá tételével. Ekkor a kernel bizonyos részeit fizikailag és logikai különválasztjuk egymástól, és az így keletkezett modulokat - melyek többnyire meghajtó programok (driver) - futási időben be lehet tölteni a memóriába vagy el lehet távolítani őket onnan. Memória- és méretspóroló megoldás - mely nagyon életképesnek bizonyult az idők során - még mindig nem ad akkora rugalmasságot, mint egy mikrokernel.

A rétegelt kernel

Ebben a modellben az operációs rendszert - így a kernelt is - rétegekből építjük fel, melyek egymás felé épülnek. Ezt az elvet a nemrégiben elhunyt E. W. Dijkstra ötlötte ki, és készített is egy ilyen rendszert T.H.E. néven. Bár a T.H.E. kötegelt rendszer volt, a szakma figyelmét nem kerülhette el. Később ezt a MULTICS - a UNIX őse - tökéletesítette, de ő már koncentrikus gyűrűkbe szerveződött, és a belső gyűrűi több, a külsők pedig kevesebb előjogot kaptak. Egy külső gyűrűből egy belső gyűrűbeli programot csak csapdázással lehetett meghívni. A hívás, és a hozzá kapcsolódó paraméterek külön le lettek ellenőrizve, mielőtt még az ténylegesen megtörtént volna. Így képes volt minden alprogramot védeni az illetéktelen írás, olvasás, netán végrehajtás ellen. Míg a T.H.E. esetében a rétegelés csak tervezési segítség volt - tehát a kernel maradt a szokásos megoldású - addig a MULTICS már futási időben építette fel a gyűrűit.

Egy régelt kernelben tehát csak a megfelelő ellenőrzés mellett hajtódhatott végre bármilyen előjoggal társított tevékenység. De ne hagyjuk ki itt azt sem, hogy az ellenőrzés mindig többletköltséget ró a rendszerünkre. Ez a struktúra mindenképpen biztonságosabb, mint az előző, de láthatóan lassabban is. Nyilván a MULTICS tervezői és programozói azért választották a gyűrűk dinamikus felépítését, mert ezzel megspóroltak némi ellenőrzési időt, de megkapták az igényelt biztonságot is. Az x86 architektúrán is lehetőségünk van rétegelni, bár hardveres szinten - a processzor által támogatva - csak négy szintet kapunk, ha többre van szükségünk, akkor azt már szoftveresen kell tovább osztani. Ennek ellenére nem állíthatom, hogy nagyon elterjedt volna ez a megoldás.

Rétegelt rendszerek: a.) A T.H.E. operációs rendszer struktúrája [2], b.) MULTICS-szerű gyűrűk: az (1) esetben a 3. szintről sikeresen meghívunk egy 0. szintű eljárást, míg a (2) során a 3. szintről sikertelen próbálunk elnérni egy 1. szintű adatot - a 2. szintről nem tudunk továbblépni.

Az exokernel

Az exokernelek fundamentumának a korábban már megpendített virtuális gépeket tekinthetjük. Az időosztásos rendszerek megvalósítására dolgozták ki a ennek a struktúrának a megalapozóját az IBM-nél, a CP/CMS-t - amely később a VM/370 nevet kapta. Ezzel érvényre jutott két fontos alapelv: megvalósult a multiprogramozás (a multiprogramozottság), és létrehött egy könnyen kezelhető kiterjesztett gép. A rendszer alapja a virtuális gép-monitor, amely közvetlenül a hardveren fut, és kezeli a multiprogramozást, illetve a virtuális gépeket futtatja: ezek viszont még nem kiterjesztett gépek, hanem a hardver pontos másolatai (ez fontos!), annak minden elemével együtt. Akkoriban tehát az időosztás úgy született meg - miközben törekedtek arra, hogy át lehessen menteni valamit a korábbi megoldásokból - hogy ezeken a virtuális gépeken futattak különböző operációs rendszereket, melyek lehettek kötegeltek (IBM OS/360), vagy egyfelhasználós interaktív rendszerek (CMS).

Mivel a VM/370 így akár saját magát is képes volt futtatni, ez az ötlet sem maradhatott észrevétlen az érdeklődő kutatók számára. Ugyanis ezt a struktúrát fejlesztették tovább az MIT (Massachusetts Institute of Technology) kutatói úgy, hogy a felhasználók a rendszerben a valódi gép egy változatát kapják meg, és az erőforrások egy részét. A legalsó a kernel módban futó exokernel. Ő rendeli hozzá az erőforrásokat a virtuális gépekhez, majd biztosítja, hogy azok ne tudják használni egymásét. Hasonlóan a VM/370-hez, a virtuális gépeken tetszőleges operációs rendszer futhat.
 

Virtuális gépek az operációs rendszerben: a.) régen [3] és b.) napjainkban

A mikrokernel

Amit eddig klasszikus kernelnek tekintettünk, kiderül, hogy tovább bontható: hiszen itt a kernel párhuzamosan fut az alkalmazásokkal. A vezérlés sem adódik át neki közvetlenül, hanem csak egy üzenetet küldünk: erre később válaszol a "kernel" - a válaszadás során pedig esetleg elvégez még további műveleteket. Talán felmerülhetett a kérdés, hogy mégis hogyan képes a kernel párhuzamosan futni a felette futó programokkal. A válasz a következő: vegyünk egy régi típusú, monolitikus kernelt. Fosszuk meg minden olyan szolgáltatásától, amely "felhozható" az alkalmazások szintjére - másképpen tartsuk meg azokat funkciókat, amelyek nem tolthatók feljebb (ütemezés, multiprogramozás, szálkezelés és így tovább). Ekkor kapunk egy minimális feladatú kernelt - innen a neve is; nem árt tudni, hogy egy mikrokernel ettől mikro, nem pedig a méretétől - ugyanígy el kell mondanom azt is, hogy a mikrokernelnek nem kell fizikailag feltétlenül elkülönülnie a szerverektől, mivel ez a szerkezet a futás idejére vonatkozik. A lekicsinyített kernelünk felé pedig helyezzük az ezúttal már programokra kivetített feladatokat. Ekkor kapjuk meg a szervereket. Ebből következik, hogy a mikrokernel és a felette futó szerverek képviselik azt, amit kernelnek neveztünk. Azért képes párhuzamosan futni tehát a kernel az alkalmazásokkal, mert a kivetített feladatok hasonló programok, mint amiket futtatunk. Röviden: a mikrokernel nem tesz különbséget szerver és alkalmazás között.

Természetesen mi - a rendszer elemzői - és az alkalmazások számára a szerverek megkülönböztetéssel bírnak. Azokat a processzusokat, amelyek valamilyen feladatot látnak el a mikrokernel felett, gyakran szerverprocesszusnak nevezzük, és akik igénybe veszik az általuk nyújtott szolgáltatásokat, azokat pedig kliensprocesszusoknak. Hasonlóan, mint ha az embereket osztanánk fel boltosokra (szerver) és vevőkre (kliens) - de nem kerülheti a figyelmenünket az se, hogy a boltos is vevő, és így a vevő is lehet boltos. A szerverprocesszusok esetén azért egyszerűbbnek látszik a helyzet: általában csak a saját feladatukkal törődnek, de néha előforul, hogy egymás szolgáltatásait is használják. A farigcsálás után a mikrokernelben - optimális esetben - csupán a legszükségesebben privilegizált utasítások maradnak, és az exokernelhez hasonló, primitív szerkezetet kapunk.

A mikrokernelek így szinte csak a kommunikációhoz szükséges eszközöket kellene tartalmaznia, de mi az előbb benne hagytunk még feljebb nem tolható, vagy csak költségesen tologatható funkciókat is. Amiatt viszont egyáltalán nem kell aggódnunk, hogy lassítaná a számítógépet az a rengeteg szerver, amely folyamatosan fut a többivel párhuzamosan, hiszen hasonlóan internetes unokatestvéreikhez, amíg nem kapnak üzenet, addig valójában processzoridőt sem kapnak - blokkolva vannak -, tehát a processzort sem használják, nem is ténylegesen, csak igény esetén. Meglepő, hogy ebből a másik irányú elméleti megközelítésből majdnem egy hasonló modellt kaptunk a monolitikus kernelekéhez! Viszont az Achilles-sarok itt az üzenetek: jóval több üzenetet váltanak - "beszélgetnek" egymással - a szerverek, mint a klasszikus rendszer processzusai. Tiszta lélekkel kijelenthetjük, hogy egy ilyen üzenetváltás sebessége és szervezése nagyon is kritikus. Ha valakinek mond valamit az, hogy Smalltalk, akkor gondoljon csak általa bevezetett üzenetalapúságra.

Bár a szerverek közvetlenül nem képesek elérni a hardvert, mégis sok szempontból előnyös ez a felépítés, mert kapunk egy teljesen moduláris, megfelelően elszigetelt komponensekkel rendelkező kernelt. Sőt, ha ez egyik ilyen komponens futásában valamilyen végzetes hiba történne - itt már megint nem laphibára gondolok - akkor az nem lesz hatással a rendszer többi részére. Szükség esetén a szerverek leállíthatóak, újraindíthatóak, vagy akár frissíthetőek futási időben. Ha mélyebben belegondolunk és a mikrokernel kommunikációját kiterjesztjük hálózatra is (LAN, MAN, WAN...), akkor rá kell döbbenünk, hogy a ezeknek a komponenseknek, moduloknak nem kell feltétlenül egyetlen számítógépen elhelyezkedni, sem pedig a moduloknak erről konkrétan tudniuk! Tökéletesen kialakítható ezen a módon egy elosztott rendszer (distributed system). A kernelt analóg módszerrel szét tudjuk osztani több processzoron is, mint különösebb erőfeszítés nélkül - egyedül csak a mikrokernelt kell felkészíteni erre, a szervereket nem.

Egy mikrokerneles rendszer szerkezete a.) unikomputeres, b.) multikomputeres környezetben (elosztott rendszer)

Rendszerkönyvtárak

A kernelben található rendszerhívások mindent nagyon szépen és remekül megvalósítanak, viszont egy átlagos ismeretekkel megáldott felhasználó vagy programozó számára közel sem tűnnek barátságosnak. Hiszen maga a kernel még nem képes a szükséges magas szintű műveletek elvégzésére, mivel nem közvetlenül nem áll kapcsolatban mással, csak az alatta dübörgő fémmel; mondhatnánk erre azt is, hogy "a felhasználóig már nem lát el". Így nagyon sok esetben a magra - ezt jelenti igazából a "kernel" szó - kerül még egy újabb réteg, amely valamivel emberibb módon teszi elérhetővé ezáltal a mag által felkínált lehetőségeket. Bevallhatjuk, hogy ez csak a programozók számára jelent megoldást, a többi felhasználót egyáltalán nem kápráztatják el a függvénykönyvtárakba zárt képességek. Mielőtt még az ő kedvünkben járnánk, időzzünk el a függvénykönyvtárak vendégségében!

Nagyon sok esetben a magasszintű programozási nyelvek gyakran használt elemeit találjuk összedobálva egy ilyen könyvtárban. Igen, itt a "könyvtár" megnevezés a pontos; csak ebben nem állományok, hanem - főleg az operációs rendszerek C nyelv szerinti szemlélete miatt - függvények (function) találhatóak benne. Konkrétan emlegethetjük a libc-t - a UNIX C fordítójának "beépített" függvényeit -, vagy az msvcrt-t - a Visual C++ RunTime alprogramjait felvonultató "képződményeket". A függvénykönyvtárak UNIX alatt többnyire az .so (shared object) vagy az .a (archive) kiterjesztést kapják.  A "shared object" osztott tárgyprogramot jelent, vagyis a függvényeket - kölcsönözhető formában. Egyik program sem tartalmazza ezeket, s ezzel memóriát és háttértárat takarítanak meg. Meghívásuk egy kicsit körülményes: mikor hivatkozik rájuk a program, akkor az operációs rendszernek  utána kell néznie, hogy be van-e már töltve a memóriába az adott könyvtár - ha nincs, akkor be kell töltenie - és ezután kerül csak át a vezérlés rájuk. Cserébe viszont egyrészt csak akkor kerül betöltésre, ha szükség van rá, és több program is használhatja őket. Windows esetében többek közt ezt a szerepet a .dll (dynamic link library) kiterjesztésű állományok játsszák el. Az "archive" ezzel szemben egy statikus függvénytárnak, archívumnak tekinhető, amely csak tárolja a függvényeket, és fordításkor azok bele is kerülnek a programunkba. Előnye, hogy picivel gyorsabb és nem igényeli a függvénykönyvtárak meglétét - viszont nagyobb lesz a keletkező program, és több memóriát is fog "enni".

Természetesen megint igaza van a szemfüles olvasónak: egyetlen rendszerhez sem köthetünk kötelező jeleggel komplett függvénykönyvtárakat: lehetnek azok akár eljáráskönyvtárak is, vagy egy kernelhez számos különböző típusú tartozhat. Szerencsére UNIX alatt a konvenciók szerint vagy a /libvagy a /usr/lib könyvtárban sorakoznak ilyen állományok. Windows alatt pedig sokszor a \Windows\System és System32 könyvtárakban lelhetünk függvénykönyvtárak garmadájára. Észrevétlenül ugyan, de mindannyiunk gépén ott lapulnak.

Rendszerprogramok

Az operációs rendszerhez szorosan, és gyakran elválaszthatatlanul kapcsolódnak a rendszerprogramok. Ide többségükben a különböző héj (shell) programok, vagyis parancsértelmezők és -feldolgozók, karbantartó-, vagy fordítóprogramok számítanak. Ezek nem válnak el a többi programtól, viszont szerepük a rendszer egészét tekintve létfontosságú. Korábban már említettem a felhasználóval való kapcsolattartást is - vehetjük úgy, hogy ők adják az arcot, amit nap mint nap látunk. Innen következöik a feladatuk is: egy felhasználó bal és jobb kezei, segítségükkel az önmagában igen durva kernel és függvénykönyvtár felett egy igen kellemesen kezelhető felülete kapunk. Azonban nem minden esetben található meg összes szokványos rendszerprogram kedvenc OS-ünkhöz. Példuál a Windows-nak nem szerves részei a fordítóprogramok, viszont egyetlen UNIX-ot sem tudunk nélküle elképzelni. Viszont a Windows alapfelszerelése a grafikus felület, ami viszont UNIX-ban nem tekinthető általánosnak.

Tömören összegezve ezek után kijelenthetjük, hogy ezen a szinten már nem tapasztalhatunk akkora összhangot, ami a rendszerprogramok tényleges funkcióját illeti. Ezek kaliberét, mennyiségét és minőségét erősen befolyásolja az, hogy a tervezői mire szánták az operációs rendszert.

Felhasznált irodalom

[0], [1], [2], [3] Andrew S. Tannenbaum - Albert S. Woodhull: Operációs rendszerek, Panem Könyvkiadó Kft. 1999.