BAKOS TAMÁS - ZSADÁNYI PÁL
OPERÁCIÓS RENDSZEREK
Számítástechnika-alkalmazási Vállalat Budapest, 1989, 2001
Lektorálta: Kovács Ervin Supervised by Ervin Kovács
Copyright by Bakos Tamás - Zsadányi Pál, 1989 (első kiadás), 2001 (co memorial e-text)
ISBN 963 553 141 3
Kiadja a Számítástechnika-alkalmazási Vállalat Felelős kiadó: Havass Miklós vezérigazgató Felelős szerkesztő: Kardoss Zsuzsa Műszaki vezető: Kiss Ádám Műszaki szerkesztő: G. Müller Zsuzsa Olvasó szerkesztő: Gyömöre Mihályné, Lukács Erzsébet A (eredeti) rajzokat készítette: Dávidné Hujber Éva és Csermely Réka Megjelent: 17 (B/5) ív terjedelemben Készítette: FÜTI Nyomdaüzem, Azonossági szám: 89-149 Példányszám: 1500 Felelős vezető: Rédi Zoltánné Co memorial e-text supervised by Zsadányi Pál, 2000-2001
TARTALOMJEGYZÉK
OS!TV18.RTF,2001-04-23.ZSP; végleges állapot ELŐSZÓ.............................................................................................................................................1 1. BEVEZETÉS..............................................................................................................................3 1.1. Rendszerek és struktúrák........................................................................................................3 1.2. Számítógépes rendszerek.......................................................................................................7 1.3. Az operációs rendszer fogalma..............................................................................................9 1.4. Hardver alapfogalmak..........................................................................................................10 1.4.1. Processzorok........................................................................................................................10 1.4.2. Tárak....................................................................................................................................15 1.4.3. Háttértárak............................................................................................................................16 1.4.4. Egyéb perifériák...................................................................................................................17 1.5. Mintapéldák: hardverarchitektúrák......................................................................................18 1.5.1. IBM 360/370, ESZR-I/II/III sorozatok................................................................................18 1.5.2. PDP 11, MSZR I/II, VAX, MSZR III sorozatok..................................................................19 1.5.3. INTEL 8086/8088, 80286, 80386 mikroprocesszor család..................................................20 1.6. Gyakorlatok..........................................................................................................................22 2. AZ OPERÁCIÓS RENDSZEREK FUNKCIÓI.......................................................................23 2.1. Rendszeradminisztráció.......................................................................................................23 2.2. Programfejlesztési támogatás...............................................................................................24 2.2.1. A programozási munka részfeladatai..............................................................................25 2.2.2. Támogatások a problémaelemzéshez..............................................................................25 2.2.3. A programírás támogatása...............................................................................................25 2.2.4. Támogatás a programok belövéséhez..............................................................................28 2.2.5. A programintegrálás támogatása.....................................................................................30 2.2.6. A programfejlesztési támogatás fő funkcióinak összefoglalása......................................30 2.3. Alkalmazói támogatás..........................................................................................................30 2.3.1. Az operátori nyelvi rendszerek........................................................................................31 2.3.2. A munkavezérlő-nyelvi rendszerek.................................................................................31 2.3.3. A rendszerszolgáltatási funkciók.....................................................................................32 2.3.4. A segédprogram-készlet..................................................................................................32 2.3.5. Alkalmazói programcsomagok.......................................................................................32 2.4. Mintapéldák..........................................................................................................................32 2.4.1. Az IBM 360/370/30XX/43XX és az ESZR-I/II/III sorozat operációs rendszerei............................................................................................32 2.4.2. Az OS munkavezérlő nyelvének alapelemei...................................................................36 2.4.3. Az IBM PC operációs rendszerei....................................................................................41 2.4.4. Alapvető DOS parancsok................................................................................................44 2.5. Gyakorlatok..........................................................................................................................50
3. AZ OPERÁCIÓS RENDSZEREK OSZTÁLYOZÁSA...........................................................51 3.1. Osztályozási elvek................................................................................................................51 3.2. Egyfelhasználós rendszerek.................................................................................................54 3.3. A multiprogramozás alapelve...............................................................................................55 3.4. Multiprogramozott rendszerek.............................................................................................56 3.4.1. Spooling technika............................................................................................................56 3.4.2. Tárkezelési problémák.................................................................................................... 58 3.4.3. Központi egység elosztás................................................................................................ 60 3.4.4. A holtpontok problémája................................................................................................ 60 3.4.5. Védelmi kérdések............................................................................................................ 61 3.5. Kötegelt (batch) rendszerek................................................................................................61 3.6. Időosztásos rendszerek........................................................................................................62 3.7. Valós idejű rendszerek........................................................................................................ 63 3.8. Többprocesszoros rendszerek............................................................................................. 64 3.9. Hálózatok és elosztott rendszerek..................................................................................... 65 3.10. Mintapéldák.......................................................................................................................... 67 3.11. Gyakorlatok.......................................................................................................................... 70 4. MŰVELETI FÁZISOK............................................................................................................71 4.1. A feladat egysége: a munka..................................................................................................71 4.2. Munkafogadási fázis............................................................................................................72 4.3. Munkakiválasztás.................................................................................................................73 4.4. Programfordítás....................................................................................................................73 4.5. Programszerkesztés..............................................................................................................74 4.6. Programaktiválás és erőforrás hozzárendelés......................................................................76 4.7. Programbetöltés....................................................................................................................77 4.8. Programvégrehajtás..............................................................................................................77 4.9. Záró fázis..............................................................................................................................78 4.10. Rendszerfolyamatok.............................................................................................................78 4.11. Mintapéldák..........................................................................................................................78 4.12. Gyakorlatok..........................................................................................................................80 5. RENDSZERSZOLGÁLTATÁSOK..........................................................................................81 5.1. Alapkoncepció......................................................................................................................81 5.2. Vezérlőáram-kezelés............................................................................................................81 5.3. Tárkijelölés és programbetöltés...........................................................................................82 5.4. Szerkesztőmenet...................................................................................................................83 5.5. Magas szintű ütemezés.........................................................................................................83 5.6. Működésoptimalizálás..........................................................................................................84 5.7. Alrendszerek kezelése..........................................................................................................85 5.8. Mintapéldák..........................................................................................................................88 5.8.1 Az IBM OS TSO alrendszere..........................................................................................88 5.8.2 Nyilvános adatbázis szolgáltatások.................................................................................90 5.9. Gyakorlatok..........................................................................................................................92
6. BELSŐ ARCHITEKTÚRA......................................................................................................93 6.1. Rendszermag (kernel)..........................................................................................................93 6.1.1. A rendszermag szerepe....................................................................................................93 6.1.2. A rendszermag struktúrája...............................................................................................94 6.1.3 A T.H.E. architektúra......................................................................................................96 6.1.4. A szolgáltatáskérések formái.........................................................................................101 6.2. Megszakításkezelés............................................................................................................105 6.3. Alacsony szintű ütemezés..................................................................................................107 6.4. Tárkezelési funkciók..........................................................................................................110 6.5. Perifériakezelés..................................................................................................................112 6.5.1. B/K vezérlőprogram......................................................................................................112 6.5.2. A B/K--szolgáltatások hívása........................................................................................114 6.5.3. IBM 360/370 OS/MVT vezérlőtáblázatok....................................................................114 6.5.4. A B/K--szolgáltatások befejezése..................................................................................118 6.6. Egyéb magfunkciók............................................................................................................119 6.7. Mintapéldák........................................................................................................................120 6.8. Gyakorlatok........................................................................................................................122 7. RENDSZERHÍVÁSOK..........................................................................................................123 7.1. Rendszerprimitívek............................................................................................................123 7.2. Folyamatként futó rutinok..................................................................................................124 7.3. Mintapéldák........................................................................................................................126 7.3.1. Az IBM 360/370 OS rendszerhívásai............................................................................126 7.3.2. A UNIX kernel rendszerhívásai....................................................................................127 7.4. Gyakorlatok........................................................................................................................130 8. ERŐFORRÁS-KEZELÉS......................................................................................................131 8.1. Alapelvek...........................................................................................................................131 8.2. Gazdaságosság...................................................................................................................131 8.3. Az erőforrások lefoglalása.................................................................................................132 8.4. Holtpont..............................................................................................................................133 8.4.1. A holtpont megelőzése..................................................................................................134 8.4.2. A holtpont felismerése...................................................................................................136 8.5. Korlátok, kompromisszumok.............................................................................................137 8.6. Mintapéldák........................................................................................................................138 8.6.1. Megelőzési algoritmusok..............................................................................................138 8.6.2. Holtpontfelderítő algoritmus.........................................................................................139 8.7. Gyakorlatok........................................................................................................................140 9. PROCESSZORKEZELÉS......................................................................................................141 9.1. Alapfogalmak, az ütemezés eszközei.................................................................................141 9.2. Ütemezési szintek...............................................................................................................144 9.3. Ütemezési algoritmusok.....................................................................................................145 9.3.1. Előbb jött -- előbb fut....................................................................................................146 9.3.2. A legrövidebb előnyben................................................................................................147 9.3.3. Prioritás.........................................................................................................................147 9.3.4. Körben járás..................................................................................................................148 9.3.5. Többsoros ütemezés......................................................................................................149 9.4. Értékelési módszerek.........................................................................................................150 9.5. Gyakorlatok........................................................................................................................154
10. TÁRKEZELÉS.......................................................................................................................155 10.1. Abszolút címzésű rendszerek.............................................................................................155 10.2. Áthelyezhető címzésű rendszerek......................................................................................155 10.3. Particionált rendszerek.......................................................................................................156 10.3.1. Rögzített partíciók (MFT).............................................................................................158 10.3.2. Változó partíciók (MVT)..............................................................................................159 10.4. Tömörítés...........................................................................................................................159 10.5. Lapozás és szegmentálás....................................................................................................160 10.6. Virtuális tár.........................................................................................................................164 10.7. Lapozási stratégiák.............................................................................................................168 10.7.1. Lapcsere algoritmusok..................................................................................................168 10.7.2. Keretkiosztási algoritmusok..........................................................................................169 10.8. Tárvédelem.........................................................................................................................170 10.9. Mintapéldák........................................................................................................................172 10.9.1. Tömörítés, dinamikus relokáció....................................................................................172 10.9.2. Szegmenstáblák.............................................................................................................172 10.9.3. Kombinált megoldások.................................................................................................172 10.9.4. Az optimális lapozás közelítései...................................................................................174 10.9.5. Egyéb megfontolni valók..............................................................................................175 10.10. Gyakorlatok........................................................................................................................176 10.11. Appendix: A cc-NUMA, a VLMS és társai.......................................................................178 11. ÁLLOMÁNY- ÉS OBJEKTUMKEZELÉS...........................................................................179 11.1. Állományok és állományrendszerek..................................................................................179 11.2. Adatok, perifériák és folyamatok.......................................................................................180 11.2.1. Állományokon végezhető műveletek............................................................................181 11.2.2. Katalógusok és katalógusrendszerek.............................................................................182 11.2.3. Elérési módszerek.........................................................................................................184 11.2.4. Háttértár-kiosztási módszerek.......................................................................................185 11.3. Adatvédelmi rendszerek.....................................................................................................189 11.4. Háttértárak kezelése...........................................................................................................189 11.4.1. FCFS ütemezés..............................................................................................................190 11.4.2. Legközelebbi előnyben.................................................................................................190 11.4.3. A SCAN algoritmus......................................................................................................190 11.5. Mintapéldák........................................................................................................................191 11.6. Gyakorlatok........................................................................................................................192 12. KONKURENS FOLYAMATOK............................................................................................193 12.1. Párhuzamosság és szinkronizálás.......................................................................................193 12.2. Szoftver megoldások..........................................................................................................194 12.3. A folyamatok hierarchiája..................................................................................................196 12.4. A kritikus szakasz problémája............................................................................................199 12.5. Szemaforok........................................................................................................................204 12.6. Folyamatközi kommunikáció.............................................................................................206 12.7. Mintapéldák........................................................................................................................209 12.7.1. Termelő--fogyasztó probléma.......................................................................................209 12.7.2. Író--olvasó probléma.....................................................................................................210 12.7.3. Az Accent operációs rendszer.......................................................................................210 12.8. Gyakorlatok........................................................................................................................212 12.9. Appendix: Monitorok.........................................................................................................213
13. RENDSZERHATÁSFOK VEZÉRLÉS..................................................................................217 13.1. Az IBM SRM alapelvei......................................................................................................217 13.2. A szolgáltatás egysége........................................................................................................219 13.3. Terhelési szintek.................................................................................................................220 13.4. Terhelési sablonok és végrehajtási csoportok....................................................................220 13.5. Végrehajtási periódusok.....................................................................................................222 13.6. Intervallumokra bontott kiszolgálás...................................................................................222 13.7. Tartományok......................................................................................................................222 13.8. Rendszercélok és taktikák, rendszerhangolás....................................................................223 13.9. Gyakorlatok........................................................................................................................224 14. VIRTUÁLIS GÉPEK..............................................................................................................225 14.1. Több operációs rendszer egy gépen...................................................................................225 14.2. Megvalósítási kérdések......................................................................................................226 14.2.1. A hardver emuláció problémái......................................................................................226 14.2.2. Hypervisor funkciók......................................................................................................228 14.2.3. Működésoptimalizálás...................................................................................................229 14.3. Kapcsolat az elosztott rendszerekkel.................................................................................229 14.4. Mintapéldák........................................................................................................................230 14.4.1. Az IBM VM/CMS interaktív fejlesztő rendszer...........................................................230 14.4.2. Osztott hálózatok, mint virtuális gépek.........................................................................231 14.4.3. Emulátorok -- a gépszimulátorok..................................................................................231 14.5. Gyakorlatok........................................................................................................................232 IRODALOMJEGYZÉK................................................................................................................233 INDEX .........................................................................................................................................235 ÁBRAJEGYZÉK 1.1. ábra. 1.2. ábra. 1.3. ábra. 2.1. ábra. 2.2. ábra. 2.3. ábra. 3.1. ábra. 3.2. ábra. 3.3. ábra. 3.4. ábra. 3.5. ábra. 3.6. ábra. 3.7. ábra. 3.8. ábra. 3.9. ábra. 3.10. ábra. 3.11. ábra. 3.12. ábra. 3.13. ábra. 4.1. ábra. 4.2. ábra. 4.3. ábra. 4.4. ábra. 4.5. ábra.
A rendszerekkel kapcsolatos fogalmak szemléltetése..................................................4 A számítógépes rendszer rétegződése a problémamegoldáskor...................................7 A számítógépes rendszer rétegződése az üzemeltetésnél.............................................7 Az operációsrendszeri szoftver rétegződése...............................................................23 Szoftvermegszakítás...................................................................................................27 Az MS--DOS hierarchikus katalógusrendszere..........................................................43 Egyfelhasználós rendszer tárfelosztása......................................................................54 Spooling......................................................................................................................56 Az IBM OS/MFT tárkezelése.....................................................................................57 Az IBM OS/MVT ütemezési viszonyai......................................................................57 Lapkezelés..................................................................................................................59 Szegmensek................................................................................................................59 Folyamatállapot diagram............................................................................................60 Kötegelt rendszert vezérlő kártyacsomag...................................................................61 Teljes kapcsolású hálózat............................................................................................66 Részleges kapcsolású hálózat.....................................................................................66 Csillaghálózat.............................................................................................................66 Gyűrűs hálózatok. a) Egyszeres, b) Többszörös.........................................................67 Busszal rendelkező hálózat.........................................................................................67 Munkafogadás............................................................................................................72 Munkakiválasztás.......................................................................................................73 Programfordítás..........................................................................................................74 Programszerkesztés....................................................................................................74 Programaktiválás és erőforrás hozzárendelés.............................................................76
5.1. ábra. Alrendszeri rétegződés...............................................................................................85 5.2. ábra. Az alrendszer kiépítés elemzése.................................................................................86 5.3. ábra. Számítógépes rendszerek strukturálódása..................................................................87 6.1. ábra. A T.H.E. architektúra rétegei......................................................................................99 6.2. ábra. Round-Robin (körben forgó) ütemezés három programmal....................................107 6.3. ábra. Szabadlánc-struktúra az IBM OS/MVT-ben.............................................................113 6.4. ábra. Az IBM 360/370 OS/MVT vezérlőtáblázatai...........................................................116 7.1. ábra. Primitívként futó funkciók működése......................................................................124 7.2. ábra. Folyamatként futó funkciók működése....................................................................125 8.1. ábra. Biztonságos, bizonytalan és holtponti állapot..........................................................136 9.1. ábra. Folyamatállapotok....................................................................................................142 9.2. ábra. Átkapcsolás (context switch)....................................................................................142 9.3. ábra. Várakozó sorok és láncolt listák...............................................................................143 9.4. ábra. Központi egység ütemezés.......................................................................................144 9.5. ábra. A közbenső szintű ütemezés hatása..........................................................................145 9.6. ábra. Időosztásos ütemezés................................................................................................148 9.7. ábra. Többsoros ütemezés.................................................................................................150 10.1. ábra. Dinamikus relokálás relokációs regiszterrel.............................................................156 10.2. ábra. Multiprogramozás helycserével (swapping).............................................................156 10.3. ábra. Swapping pufferezéssel............................................................................................157 10.4. ábra. Tömörítés..................................................................................................................159 10.5. ábra. Logikai lapok, laptábla és fizikai lapkeretek............................................................160 10.6. ábra. Kódmegosztás lapozásnál.........................................................................................161 10.7. ábra. Szegmenscím ellenőrzés bázis/limit regiszterpárral.................................................163 10.8. ábra. Logikai szegmensek, szegmenstábla és fizikai szegmensek....................................164 10.9. ábra. Laptáblázat virtuális tárkezelésnél...........................................................................165 10.10. ábra. Lapkeresés és belapozás...........................................................................................166 10.11. ábra. Kilapozás..................................................................................................................167 10.12. ábra. Laphiba-sorozat példa..............................................................................................168 10.13. ábra. Optimalizált laphiba-kezelés....................................................................................169 10.14. ábra. Címellenőrzés határregiszterekkel............................................................................171 10.15.a) ábra. Címzési hiba két határregiszter esetén......................................................................171 10.15.b) ábra. Címzési hiba bázis/limit regiszterpárnál...................................................................171 10.16. ábra. Szegmentált lapozás.................................................................................................173 10.17. ábra. Lapozott szegmentálás..............................................................................................174 10.18. ábra. A legrégebben használt lap kilapozása (LRU algoritmus).......................................175 11.1. ábra. Fa-struktúrájú katalógusrendszer..............................................................................183 11.2. ábra. Fa-struktúra kapcsolatokkal......................................................................................184 11.3. ábra. Folytonos helykiosztás a lemeztárakon....................................................................186 11.4. ábra. Láncolt helykiosztás a lemeztárakon........................................................................187 11.5. ábra. Indexelt helykiosztás a lemeztárakon.......................................................................188 12.1. ábra. Precedenciagráf........................................................................................................194 12.2. ábra. Az elágazás (fork) precedenciagráfja.......................................................................194 12.3. ábra. Az egyesítés (join) precedenciagráfja......................................................................195 12.4. ábra. Tiszta fork/join szerkezet........................................................................................196 12.5. ábra. Folyamatok dinamikus létrehozása..........................................................................197 12.6. ábra. Hatelemű precedenciagráf........................................................................................212 12.7. ábra. A monitorok koncepciója.........................................................................................213 13.1. ábra. Az IBM 370 OS/MVS ütemezői..............................................................................218 13.2. ábra. Terhelési szintek, terhelési sablonok és végrehajtási csoportok az SRM-ben.........................................................................221 14.1. ábra. Több operációs rendszer egy gépen.........................................................................226 TÁBLÁZATOK 2.1. táblázat. CP/M, UNIX és MS-DOS összehasonlító táblázat....................................................49 7.1. táblázat. Az IBM 360/370 OS néhány rendszerhívása...........................................................126 7. táblázat. A UNIX kernel tipikus rendszerhívásai....................................................................128
OS$EV06.RTF,2001-04-16,ZSP ELŐSZÓ Mottó: "Az elefánt nem más, mint egy egér, IBM operációs rendszerrel! " -- Barron.
Könyvünket bevezető tankönyvnek szánjuk, ezért igyekszünk nem túl mélyre ásni az operációs rendszerek elméletébe, amelyről sok tekintetben ma is elmondható, hogy nem alakult ki eléggé. A téma tárgyalását a 80-as évek elején megjelent, új -- "második generációs" -- operációs rendszer szakkönyvekben terjedő irányzathoz igazítottuk. Míg a korábbi könyvek egy-egy konkrét operációs rendszerhez kapcsolódtak, addig az új generáció megpróbálja általánosítva összefoglalni a szakma -- különösen a mikrogépek forradalma kapcsán szétzilálódott -- ismereteit. Tárgyalásmódunkkal kapcsolatban megjegyezzük még, hogy "európai logikát" követünk, amennyiben egy-egy téma bemutatásánál általában az elméleti alapokból indulunk ki, és csak később adunk gyakorlati példákat. Az operációs rendszerekről sokan úgy beszélnek, mint szükséges rosszról (lásd Barron idézetét). Ugyanakkor a mai alkalmazók zöme csupasz hardvert még sose látott, és aligha tudna vele mit kezdeni. A hardvert tökéletesen elfedi előlük a szoftver, amelynek legalapvetőbb része a (többnyire operációs rendszerként emlegetett) rendszerszoftver. Barron nyomán kijelenthetjük, hogy a mai számítógép alkalmazóknak maga az operációs rendszer "a gép"(!). Az operációs rendszerek történetileg az akkor még méregdrága nagyszámítógépek jobb kihasználása végett születtek. Fő elvük ezért a hardver hatékony kihasználásának biztosítása volt. Közben -- az árak zuhanásával, majd a minik és mikrók megjelenésével -- a körülmények erősen megváltoztak. Ma a felhasználó jó kiszolgálása fontosabb szempont, mint a hardver hatékony üzemeltetése. Az operációs rendszerekre vonatkozó erős kritikai megjegyzések alapja éppen az, hogy a nagygépes operációs rendszerek meglehetősen rugalmatlanul reagáltak erre a kihívásra, ami a minik és mikrók erős térnyeréséhez vezetett. A miniszámítógépes, de különösen a mikroszámítógépes korszak operációs rendszerei sokkal jobban idomultak az új követelményekhez. Gyökeresen új szoftver megoldásokat hoztak létre az erőforrásszegény környezetre, teljesen elrugaszkodva a nagygépes tapasztalatoktól. Mindezek eredményeképpen a Barron által már a korai operációs rendszerek kapcsán is ostorozott "ad hoc" jelleg csak tovább terebélyesedett, és a kialakult anarchiában alig lehet valami rendszerezést végrehajtani. Nem csoda, hogy a korai -- "első generációs" -- operációs rendszer szakkönyvek inkább praktikus célokat követtek. Véleményünk szerint sem lehet a kialakult helyzetben egyszer s mindenkorra rendet teremteni, így a mi tárgyalásmódunk is vita tárgyát képezheti. Ezért, lehetőség szerint, megpróbáljuk rendszerezni a témakör legfontosabb alapelveit, majd példák kapcsán bemutatni az eltérő megvalósítási módokat. Eközben érintjük a legújabb irányzatokat is (IBM OS/2, UNIX verziók, NOVELL, stb.), de kerüljük az iránymutató jóslatokat. Néhány, általunk hasznosnak vélt tanácsot azért elmondunk.
Könyvünk a SZÁMOK oktatási rendszerében az "Operációs rendszerek" tantárgy hallgatói segédkönyve, és egyben az oktatók támogatására is szolgál. Az anyag mennyisége meghaladja a hallgatóktól elvárt követelményeket, az előadóra bízzuk, hogy a rendelkezésre álló óraszámmal és a konkrét gépi környezettel összhangban szelektáljon. A fejezetek végén található mintapéldákat és gyakorlatokat az oktatók a gyakorlati órák anyagának kialakításánál, valamint egységes szemléletű vizsgatételek összeállításánál hasznosíthatják. A könyv anyaga támaszkodik a SZÁMOK "Számítógép alapismeretek" című tankönyvére, jóllehet, néhány hardver fogalmat újra áttekint az operációs rendszerek szemszögéből nézve. Az egyes fejezetekben szándékosan ismétlésekbe bocsátkozunk. Vannak olyan nehezebb fogalmak, amelyeket érdemes több oldalról is körüljárni, más és más megvilágításba helyezni. Ez segítheti az anyag rögzítését. A tárgyalás elsősorban a programozóképzés szempontjait veszi figyelembe, de úgy véljük, hogy könyvünkből a számítógépes szakma minden tagja hasznos ismereteket szerezhet. Ezt a megjegyzést bátorításnak szánjuk, minthogy az operációs rendszerek sokak számára valami homályba vesző, megérthetetlen szoftver kolosszusok. Mi megpróbálunk rávilágítani a csillogó cseppkövekre ebben a misztikusnak tűnő barlangban. Reméljük, sikerül! Megemlítjük még, hogy a könyvet a híres WORD szövegszerkesztővel írtuk, amelynek kényelmeit igen megszerettük. Sajnos -- meglepetésünkre -- a könyv tükörnyomata eleinte nem akart tökéletes lenni a STAR Laser Printer 8-as nyomtatónkon. A szövegben jobboldali szövegkizárási problémák adódtak. Több eset volt lehetséges: 1) vagy mi nem olvastuk el eléggé a dokumentációt, 2) vagy a magyar ékezetek érvényesítése miatt feltétlen megírandó nyomtató interfész programban vétettünk hibát, 3) vagy a lézernyomtató nem úgy működik, ahogy gondoltuk, és 4) végső esetben a Word is lehet hibás. Végül a térköz (SPACE) karakter mérete okozta a problémát. Mindenesetre az itt vázolt a hibaelemzési sorrendet figyelemre méltónak tartjuk mások számára is: az ember mindig a saját munkájában kerese először a hibát, csak aztán a másokéban -- és legkevésbé a rendszerszoftverben vagy a hardverben. A programozási feladatokban erősen rá vagyunk utalva, hogy legalább bizonyos elemi eszközök működésében higgyünk. Hiba észlelése esetén azonban tanácsos jól elgondolkodni (ha ez időben kiderül, nem úgy mint esetünkben), hogy a hiba nem veszélyezteti-e alapjaiban a projekt megvalósítását. Olykor segít a hibák kiismerése, és kicselezése. Ez ugyan nem túl vígasztaló szöveg az operációs rendszerekről írott könyv előszavában, de az Olvasónak a valós életkörülményeket szeretnénk inkább megmutatni. Egyébként, ahogy egy kollégánk egyszer megjegyezte: "a rendszerprogramozás nehéz kenyér". Kemény munka -- kevés siker. Azért mégis elég sokan csinálják -- szerencsénkre!
Budapest, 1989. február
A szerzők
A “commemorial e-text” átírásnál az ismert sajtóhibák kijavításra kerültek, és az összes ábrát átrajzoltam text-art megoldásúra. A szöveg az eredeti mű fejezetenkénti szövegeit tartalmazzák. Terveim szerint a jelenlegi .RTF formátum helyett a még hordozhatóbb Adobe .PDF formátumra konvertálom, tehát végül e-book lesz belőle. Budapest, 2001. április
Zsadányi Pál
OS01V10.rtf,2001-04-16,ZSP
1. BEVEZETÉS
1.1. Rendszerek és struktúrák Az operációs rendszer kifejezés kapcsán érdemes elidőzni kicsit a rendszer fogalmánál. Az irodalomban -- a számítástechnikaiban egyenesen előszeretettel -- igen sok helyen használják a rendszer szót. Sokszor előfordul, hogy több témáról van szó, és az ember nem is érti, hogy éppen melyikre céloz a szöveg a rendszer szó használatakor. Ez alkalmas arra, hogy a témában gyakorlatlan olvasót teljesen összezavarja. Hogyan keletkezik egy rendszer? Nyugodtan kimondhatjuk, hogy egy rendszer megalkotásához az ember rendszerező képessége szükséges. A valós világból -- amelyben minden mindennel összefügg -- az ember választ ki olyan részt, amely az éppen vizsgált szempontból összefügg. A vizsgálati szempontot az ember adja meg, és a létrehozandó rendszerbe illőnek azt tartja, ami ebből a szempontból lényeges szerepet játszik. Amit nem tart lényegesnek, azt elhanyagolja. (Az elhanyagolás persze nem feltétlenül pontos, ami hibát okozhat.) Az ember, amikor rendszert alkot, rögtön két részre bontja a világot: az általa vizsgált rendszerre és a világ - számára most érdektelen - többi részére. Így szerkezetet (struktúrát) visz az eddig szerkezetnélküli mindenségbe. Egy rendszer természetesen újabb szempontok alapján további elkülöníthető részekre osztható. Ezek a mondottakból következően ugyanúgy rendszerek, mint az első szempont szerint elkülönített része a világnak. Ilyenkor azonban megkülönböztetésül igyekszünk valamilyen szóösszetételt alkalmazni: alrendszer, részrendszer, rendszermodul stb., vagy a funkciója szerint adunk nevet a vizsgált résznek. A valós világnak azt a részét, amely lazán kapcsolódik a vizsgált rendszerhez, a rendszer környezetének nevezzük. Ha egy rendszerbe belevesszük a környezetét (amely ilyenkor annak részrendszerét képezi), olyan rendszert kapunk, amelynek nincsenek külső kapcsolatai, azaz zárt rendszer. Ellenkező esetben nyílt rendszerről beszélünk. Egy rendszert nem szoktunk minden határon túl felosztani. Vizsgálati szempontjaink rendszerint azt is kitűzik, hogy mi lesz a legrészletesebb felosztás. A legrészletesebb felosztásban szereplő rendszerrészeket elemeknek, vagy komponenseknek nevezzük. A vizsgált rendszer statikusan az elemek felsorolásával és a közöttük lévő esetleges kapcsolatokkal írható le. A kapcsolatok jellemzik a rendszer struktúráját.
A rendszer és a környezete közötti érintkezési felületen (interfészen) fellépő kapcsolatok a vizsgálat szempontjából rendszerint különös jelentőséggel bírnak. Az ilyen kapcsolatok jellemzésére szolgál az interfészleírás. A részrendszerek kapcsolatait szintén interfészleírásokkal lehet megadni. Az eddig mondottakat szemlélteti az 1.1. ábra. +------------------------------------------------------------+ | VALÓS RENDSZER (Valós világ, Reálszféra) | |
+-----------------------------------+
|
|
|
| (1)
|
|
|
+- - - - - - · - - - - - - - - - - -+
|
| (2)
|
|
|
|
|
+-I-·-n-·-t-·-e-·-r-·-f-·-é-·-s-·-z-+
|
|
|
+-----------------------------------+
| R
E
N
D
S
Z
E
R
|
| |
| E11<>E12
E13
E14
E15
|
| | | (3)
|
| E21
E22
|
E31<>E33 E32
E34
|
| |
|
| | K
Ö
R
N
Y
E
Z
E
T
|
| | +------------------------------------------------------------+ 1.1. ábra. A rendszerekkel kapcsolatos fogalmak szemléltetése Az ábrán zárójelekbe tett számok különböztetik meg a részrendszereket, a rendszerelemeket Ebetűvel kezdődő szimbólum jelzi, az elemek kapcsolatát pedig nyilak mutatják. A vizsgált rendszer dinamikus leírását mozgásának megadásával lehet rögzíteni. A rendszerben tevékenységek zajlanak, amelyek egy vagy több folyamatba csatlakoznak. A folyamatok különféle (rendszer)funkciókat valósítanak meg, azaz végrehajtódásuk valamilyen eredménnyel jár. Ha a rendszer tevékenységei céltudatosak, akkor a folyamatok valamilyen vezérlési elvek szerint haladnak. A vezérlés során a folyamatok döntési pontokon haladnak át és elágazhatnak, vagy ciklikusan ismétlődhetnek, amíg a kívánt eredmény meg nem születik. A működés erőforrásokat igényel. A rendszer folyamatai ezért versenyeznek a rendszer erőforrásaiért: vagy használják az erőforrást vagy várakozásra kényszerülnek az erőforrás foglaltsága miatt (sorban állnak az erőforrásért). A vizsgált rendszer folyamatai időbeli lefolyásuk szempontjából az alábbiak szerint osztályozhatók:
a) Soros folyamatok azok, amelyek időben egymásután zajlanak, és időben nem fedik át egymást (de szünet lehet közöttük): F1 F2 F3 F4 >---------->*>-------->······>---------->*··>------->* (szünet) b) Párhuzamos folyamatokról van szó, ha azok időben egymást átlapolva futnak, illetve ha egy adott pillanatban mindegyikük él: F1 >------------------------------------->* F2 >---------------->* F3 >--------/·····/---------------------------->* (várakozás) c) Szinkron folyamatokról beszélünk, ha a folyamatok olyan kapcsolatban állnak egymással, hogy valamelyik (a szinkronizáló) kiváltja mások (a szinkronizáltak) működését (szinkronjel) (a szinkronizáló folyamat sokszor meg is hal, lásd: F3-->F4): F1 >----+-----------+-----------+------>* | szj. | szj. | szj. v v v F2 F3 F5 >---->* >--->* >--->* | szj. v F4 >----------->*
szinkronizáló
szinkronizált párhuzamosak (szj.= szinkronjel, (*= STOP) szinkronizált soros
d) Aszinkron folyamatok párhuzamosan futnak, és nem függnek egymástól. e) Izokron (egyidejű) folyamatoknak hívjuk az olyan párhuzamos folyamatokat, amelyek mindegyike működik egy adott időintervallumban. f) Ütemezett, párhuzamos (szimultán, konkurens, versenyző) folyamatoknak nevezzük az olyan párhuzamos folyamatokat, amelyek közül mindig csak egy-egy halad, esetleg van közöttük egy, amelyik a többi működését vezérli (ütemező): Ütemez ő: F1: F2:
>-+.....+---+.....+-+...+-----+...+--+..¸ | | | | | | | | | >-----+...|.....|.+---+.....+--->* | | | | >-----+..................+-- ...¸
Ez a helyzet akkor áll elő, ha a vezérelt folyamatok közös erőforráson osztozkodnak, így ennek a folyamattípusnak különösen fontos szerepe van az operációs rendszerekben. Észrevehetjük, hogy az ütemező (Ü) a folyamatokat soros részfolyamatokra tördeli: Ü > F1.1 > Ü > F2.1 > Ü > F1.2 > Ü > F1.3 > Ü > F2.2 ...
Gyakorlati példa a sakkszimultán, ahol egy nagymester több sakkozóval játszik. Akár statikusan, akár dinamikusan akarunk leírni egy vizsgált rendszert, a leírást csak közelítéssel tudjuk elvégezni. A rendszerek ilyen leírását rendszermodellnek nevezzük. A modell leírásához használt módszerek alapján a modelleket osztályozni szokták. A számítástechnikában számunkra leghasznosabbak a matematikai modellek, amelyek a vizsgált rendszer legobjektívebb leírását adják (feltéve, hogy az elhanyagolások helyesek voltak). A rendszermodellekben alapvetően háromféle rendszerstruktúrát különböztetünk meg: Elsőként az egymástól független vagy egymással egyenrangú (rész)rendszereket említjük, amelyeket párhuzamos struktúrájúaknak nevezhetünk. Példaként a párhuzamos iskolai osztályok (I.a, I.b ...) említhetők. A második esetet képező, egymástól függő, egymásra épülő (rész)rendszereket hierarchikus struktúrájú rendszereknek nevezzük. A hierarchia azonos szintjén szereplő párhuzamos részrendszerek réteget alkotnak. A hierarchiában az alsóként ábrázolt rétegek valósítják meg a rendszer egyszerűbb funkcióit, amelyekre a felsőbb rétegek bonyolultabb funkciói épülnek. Tisztán hierarchikus rendszerekben csak szomszédos rétegek állnak kapcsolatban egymással a réteginterfészeken át. A felsőbb rétegek az alsóbbakat a réteginterfészeken át dinamikai szempontból szolgáltatáshalmazként használják (rétegszolgáltatások). Az iskolai példánál maradva, a felsőbb osztályokban oktatott tananyagok az alsóbb osztályokban elsajátított tudásanyagra támaszkodnak. Az iskolarendszer tehát többé-kevésbé úgy rétegződik, hogy az otthon és az óvodában szerzett ismeretekre számít az általános iskola, míg az (egymással párhuzamos rendszereket képező, különféle típusú) középiskolák az általános iskolai tudásanyagra, a felsőoktatás pedig ezek összességére épül. A példában szereplő hierarchia nem tiszta, mert a legfelsőbb szinten is közvetlenül használjuk a legalsóbb szinteken szerzett ismereteket. A harmadik esetet a strukturálatlan rendszerek képezik, amelyeket nevezhetünk inkább bonyolultnak is. Ez az eset tulajdonképpen azoknál a (rész)rendszereknél merül fel, amelyek szerkezetét még nem tártuk fel vagy szerkezetük számunkra érdektelen. Egy rendszer szerkezetének meghatározásánál egyszerű és világos struktúrára törekedjünk. Az ilyen rendszerekre azt mondjuk, hogy jól strukturáltak. Ez azonban mindig csak a felmerült szempont alapján igaz, és akkor is csak közelítéssel. Például a hierarchikus modellek akkor jól strukturáltak, ha egy réteg folyamatai csak a közvetlen alatta elhelyezkedő réteg szolgáltatásait veszik igénybe, és soha nem fordulnak annál mélyebb vagy a náluk magasabb rétegek szolgáltatásaihoz. A "VALÓS RENDSZER" felosztását mutató ábránkon az (1)-es alrendszer a vizsgált rendszerben a hierarchia tetején áll, a (2)-es és (3)-as alrendszerek egymással párhuzamosak, tehát egy réteget alkotnak. A környezetet képviselő részrendszer a hierarchia legalján szerepel. A példánkban vizsgált modell tehát háromrétegű, és zárt rendszert képez.
Vizsgált rendszerünk elemeinek kapcsolatát irányított gráf matematikai modellel ábrázolhatjuk. A kapcsolatrendszer lehet teljes (amikor minden elemnek minden elemmel van kapcsolata), lehet szabályos (pl. lineáris, hurkolt, fa alakú stb.) és lehet szabálytalan. A hierarchikus kapcsolatokat hurokmentes fa alakú gráfok írják le. (Az utóbbi szerkezet az operációs rendszerek szempontjából különösen fontossá vált.) Lineáris gráf
Hurkolt gráf
Hierarchikus gráf
E1<-->E2<-->E3<-->E4 E1-->E2-->E3 | | | | E6<--E5<--E4 E1 (gyökér) / \ E2 E3 │ / \ E4 E5 E6
0. szint 1. szint 2. szint
Összefoglalóul elmondhatjuk, hogy egy rendszer bizonyos szempontok szerint kiválasztott és egymással kapcsolatban álló elemek halmaza. A vizsgált rendszer belül tovább strukturálható, részrendszerekre, rétegekre bontható, amelyek között interfészleírások adják meg a kapcsolatokat. Működés közben a rendszerek erőforrásokat igényelnek a bennük zajló, különböző funkciókat megvalósító folyamatok számára, és vezérlés biztosítja a folyamatok célszerű viselkedését. (Ezzel korántsem merítettük ki a rendszer fogalmát, de az operációs rendszerek tárgyalásához az itt leírtak valószínűleg elegendőek.)
1.2. Számítógépes rendszerek A mi szempontunkból most a számítógépes rendszerek a fontosak, amelyek a rendszerek egy osztályát képezik, s a továbbiakban ezekre összpontosítunk. A számítógépes rendszerekben első közelítésben négy alapvető alrendszert (hierarchikus réteget) különböztethetünk meg (1.2. ábra): +-----------------------+ | Alkalmazók (környezet)| ++-----------------------++ Alkalmazói interfész | Alkalmazói réteg | ++-------------------------++ Nyelvi interfész | Nyelvi réteg | ++---------------------------++ Rendszerinterfész | Operációs rendszer réteg | ++-----------------------------++ Hardverinterfész | Hardverréteg | +-------------------------------+ 1.2. ábra. A számítógépes rendszer rétegződése a problémamegoldáskor Ez természetesen nem az egyetlen felosztás, hiszen gyakran elegendő az a durvább megközelítés is, amely a három felső réteget szoftver néven foglalja össze. Az alrendszer helyett azért használjuk a réteg elnevezést is, mert segít a komponensek egymásra épülését kifejezni. Az egyes rétegek
egymással meghatározott kapcsolatban állhatnak, ami lényegében azt jelenti, hogy a rétegek közötti információcsere mindkét irányban szabályozott módon bonyolódik. A rétegek kapcsolata, amit -mint már említettük -- interfésznek (angolul interface) neveznek, különösen jelentős, hisz a felhasználóknak a rendszer arculatát elsősorban e kapcsolatok összessége határozza meg. Említettük azt is, hogy jól strukturált rendszerek esetén megköveteljük, hogy minden alrendszer csak a hierarchiában közvetlenül alatta és felette levő réteggel álljon kapcsolatban (például a programozási nyelvek fordítóprogramjai csak az operációs rendszeren keresztül érjék el a hardvert), gyakorlati okokból azonban ezt sokszor nem tartják be. Az előző struktúrában a számítógépes rendszert a problémamegoldás szemszögéből vizsgáltuk. A számítógépes rendszer eltérő strukturálhatóságára példaként megemlítjük azt a szerkezetet, ahogy a számítógépes rendszert a számítógép üzemeltető személyzete látja (elsősorban a nagyszámítógépek esetében aktuális): +----------------------+ |Alkalmazók (környezet)| ++----------------------++ Ügyfélkezel ői interfész |Beviteli/kiviteli réteg | ++------------------------++ Er őforrás-elosztási interfész | Ütemez ő réteg | ++--------------------------++ Operátori interfész | Operációs rendszer réteg | ++----------------------------++ Hardvermérnöki interfész | Hardverréteg | +------------------------------+ 1.3. ábra. A számítógépes rendszer rétegződése az üzemeltetésnél A felhasználók szempontjából a számítógépes rendszer alapja, a hierarchia legalsó alrendszere a hardverréteg, ami a gép felsőbb rétegekből látható felépítését reprezentálja. Fizikailag processzorokból, tárakból, be- és kiviteli egységekből, vezérlőegységekből és egyéb berendezésekből áll, melyekhez "elvont" komponensek járulnak (pl. utasításrendszer (gépi kód), címkezelő alrendszer stb.). A hardverréteg elsősorban az operációs rendszerek fejlesztői számára fontos, mivel az általuk létrehozott operációs rendszer (réteg) tulajdonképpen a hardver egy kibővített megjelenését igyekszik biztosítani, amely ezzel jobban használható alapot ad a nyelvi rendszerek és az alkalmazások fejlesztőinek. Ezt a kibővített architektúrát könyvünkben "MEGAGÉP"-nek nevezzük. Az operációs rendszer olyan kapcsolatot teremt például a fordítóprogram írók számára, amely csökkenti a programozási igényt és egyszerűsíti a gép egyes szolgáltatásainak igénybevételét. Az operációsrendszeri interfész természetesen nem képes a hardverréteg teljes eltakarására. Egy fordítóprogram kódgenerátorának írója nem boldogul a célnyelv utasításrendszerének -- ami gyakran maga a gépi kód -- ismerete nélkül. Ugyanakkor a nyelvi alrendszereket (fordítóprogramokat, értelmező rendszereket stb.) létrehozó szakemberek számára alapfeladat, hogy a programozási nyelvekkel kapcsolatot teremtsenek a gyakorlati feladatok specialistái és a számítógépes rendszer között. Az ezzel kapcsolatos elméleti és gyakorlati részproblémák igen szerteágazóak, mi csak a teljesség igénye nélküli rövid felsorolásra szorítkozunk: * lexikális és szintaktikus elemzés, * kódgenerálás, kódoptimalizálás, * hibakezelés,
* mellékhatások kezelése. Az előző réteghez hasonlóan a nyelvi réteg sem képes az alatta lévő operációs rendszeri réteg teljes elfedésére. Sok programozási nyelv például lehetővé teszi az operációs rendszer egyes szolgáltatásainak igénybevételét egyszerű hívási mechanizmuson keresztül. Több, ma is működő rendszerben a fenti elv olyan, nyilvánvalóan hibás érvényesüléseivel is találkozhatunk, mint például a magas szintű nyelven írt programok hibáinak felderítése a hexadecimális tárkivonat alapján. (A dolog összefügg azzal, hogy a számítógépes rendszerek tervezői bizonyos mértékig hajlamosak megragadni egy korábbi technológiai korlát miatt létrehozott megoldásnál, de az alkalmazói programozók is nehezen tudnak áttérni új eszközök használatára. E két jelenség együttesen igen visszahúzó hatású.) Az eddig elmondottak vonatkoznak az alkalmazási rétegre is. Ezzel az alrendszerrel az alkalmazásfejlesztők foglalkoznak, akik a programozási nyelveken keresztül támaszkodnak az operációs rendszer szolgáltatásaival kibővített hardverre. A számítógépes rendszer használati értékét végső soron közvetlenül az alkalmazási szoftver mennyisége és minősége határozza meg. A többi alrendszer fejlettsége csak a jól hasznosíthatóság lehetőségét teremtheti meg. Az alkalmazási rétegben is gyakran eltérnek a célszerű rendszerhierarchiától. (Például, amikor összetett, nagy méretű alkalmazási rendszereket közvetlenül gépi kódban fejlesztenek.) Ez legtöbbször a kisebb teljesítményű hardverből minél többet kihozni akarók -- ez esetben dicséretes -- buzgóságának eredménye, de ma a más rendszerekre való átvihetőség erősebb szempontként jön számításba. Az utóbbit a gépi kódú megoldás eleve akadályozza, tehát ilyenkor csak a portábilis, magas szintű nyelven megvalósított fejlesztés hozza meg a kívánt eredményt. A hierarchiához tulajdonképpen legfelső rétegként hozzávehetjük magukat a felhasználókat is. Ők a számítógépes rendszer környezetét képezik. Ez az emberekből álló alrendszer azonban összetételében állandóan változik, tendenciájában bővül. A számítástechnika társadalmiasodása során ma már katonák, hivatalnokok, tervezőmérnökök és vezérigazgatók egyaránt lehetnek felhasználók. A felhasználóknak számunkra nem az összetétele, hanem a kiszolgálása a fontos. Állandóan szem előtt kell tartani, hogy a felhasználókat elsősorban a rendszertől kapható információ érdekli. Mint csoport, a lehető legkevesebbet akarják tudni a számítógéprendszer speciális tulajdonságairól. Egyes felhasználók azonban programoznak is, előre nem látható problémákat hoznak, melyek megoldásához elvárják a rendszer hathatós támogatását. Ezért a jó számítógépes rendszernek olyan felhasználói kapcsolatot és feladatmegoldó környezetet kell nyújtania, amely csak a legszükségesebb számítógépes szakismeretet igényli.
1.3. Az operációs rendszer fogalma Az operációs rendszer nem teljesen egyértelmű fogalom. Tartalma függ a hagyományoktól, a hardverréteg jellemzőitől és a különböző szolgáltatásoknak a teljes rendszeren belül való elosztásától. Az operációs rendszert tehát környezetéből kiragadva (géptől függetlenül) nem lehet meghatározni, de lehet adni olyan általános felsorolást, amely az operációs rendszer részeinek tekintett részrendszereket tartalmazza. Egyes konkrét operációs rendszerek esetében a részrendszerek halmaza szűkülhet vagy bővülhet. A következő részek kapcsolódnak ide: 1. A számítógépes rendszer működésébe gépkezelői beavatkozást megvalósító részrendszerek. Idesorolható a rendszer átkonfigurálása, a programok és a berendezések állapotának vizsgálata, működési jellemzők lekérdezése stb.
2. A rendszer és a külvilág közötti kapcsolat legalsó szintjét megvalósító beviteli-kiviteli (B/K) rendszerek. Ide tartozik a B/K igények sorkezelője, a B/K műveletek indítása és a külső egységekről érkező megszakítások kezelése. 3. A multiprogramozás vezérlését megvalósító részrendszerek. Tágabb értelemben ebbe a csoportba sorolható minden olyan tevékenység, amely a számítógépes rendszer erőforrásainak az igénylők közötti szétosztására vonatkozik. A munkavezérlő nyelvek értelmezői vagy a parancsértelmezők például az operációs rendszerek speciális komponensei, hiszen ezek sok esetben magas szintű programozási nyelvek is. Nem tekinthető teljesen hibásnak az a nézet sem, amely ezeket az operációs rendszer bővítéseinek tekinti. Nem szokták az operációs rendszer részének tekinteni a programozási nyelvek gépi megvalósításait, bár vannak olyan gépek, melyeken az operációs rendszer teljes vezérlése egy nyelv (mikrogépeknél gyakran a BASIC) köré épül. Annak eldöntése, hogy egy szoftver komponens az operációs rendszerhez tartozik-e, részben megítélés kérdése, részben a válaszoló nézőpontjának függvénye, részben pedig történelmi hagyományokkal kapcsolatos. Az első és második generációs gépeknél például vagy nem volt operációs rendszer, vagy jóformán csak hardver elemekből állt (különféle kapcsolók, címkiválasztó kulcsok, indító-, megállító-, lépésenkénti végrehajtást kiváltó gombok stb.). A harmadik generációban (1965 körül) alakult ki a főleg szoftverrel megvalósított operációs rendszer (pl. IBM DOS és OS), amit ma már mindenki természetesnek tart. Itt idézzük az ISO nemzetközi szabványosítási szervezet definícióját, mely szerint az operációs rendszer: "Olyan programrendszer, amely a számítógépes rendszerben a programok végrehajtását vezérli: így például ütemezi a programok végrehajtását, elosztja az erőforrásokat, biztosítja a felhasználó és a számítógépes rendszer közötti kommunikációt." Hozzátehetjük: a minél kényelmesebb kommunikációt. A korai számítógépekkel a kommunikáció a már említett, bonyolult, kapcsolókból és kijelzőkből álló konzolon (főpanelon) keresztül történt. Később vezérlő nyelveket használhattunk a munkák feladására és programozási nyelveket a problémák kódolására. A terminálok lehetővé tették, hogy e két műveletet egy hardvereszközzel tudjuk megoldani, azonban a kapcsolattartás tipikusan "szöveges" jellege megmaradt. Ezek közül a legkorszerűbb a menüvezérelt kapcsolat. Ma, a képernyős terminálok grafikai lehetőségeinek növekedésével terjed a képorientált kapcsolattartás, amelyet grafikus interfésznek hívnak. Ennél a menüelemek nemcsak szövegesen, hanem képecskék, ún. ikonok formájában, maguk a menük pedig vagy kihúzható redőnyökön, vagy külön, a képernyő más részein átlapoló ablakokban jelennek meg). Hamarosan tért hódít a hangbevitel és -kivitel is (Képzeljük csak el az ilyen szoftverfejlesztő rendszert! Vajon hogy fog reagálni a szitkokra, és hogyan tud egy szobában egynél több ember dolgozni?). Nincs elvi akadálya persze a szemmozgást figyelő hardver eszköz készítésének sem, amely figyelheti, hogy hova -- melyik menüelemre -- nézünk. A ma legkorszerűbbnek mondható, egérnek nevezett beviteli eszköz kapcsolóját pedig helyettesíthetnénk egy pillantással. (Egy ilyen eszközzel mindenesetre csendesebben lehetne dolgozni.) A kommunikációs lehetőségek fejlesztése mind a hardveresektől, mind a szoftveresektől jelentős erőfeszítéseket igényel még ma is.
1.4. Hardver alapfogalmak A számítógépes rendszerek legalsó rétege, a hardver közelebbről vizsgálva igen változatos képet mutat. A teljesség igénye nélkül általában a következő komponenseket különböztethetjük meg: processzorok, tárak, lemezek, dobok, szalagok, nyomtatók, csatornák, képernyők, billentyűzetek, adatátviteli vonalak. Ezek közül az operációs rendszerek szempontjából fontosabbakat részletesen, a többit csak nagy vonalakban tárgyaljuk. 1.4.1. Processzorok A felhasználók számára a processzorok csak egy elektronikus alkatrészt jelentenek, hasznos formájukban a "központi feldolgozó egység" (angol rövidítése: CPU) vagy röviden központi egység nevű dobozként jelennek meg, amik más alkatrészeket is tartalmazhat. A központi egység tulajdonképpen elektronikus elven működő automata, amelyet speciálisan számítási műveletek automatizálására készítenek, ezért szám(kód)okkal (gépikód) vezérelhető, és számszerű adatok feldolgozására képes. Bár a központi egység növekvő teljesítménye mellett is a számítógépes rendszer összköltségének egyre csökkenő hányadát reprezentálja, mégis -- több szempontból is -- a rendszer legfontosabb komponense. Az operációs rendszerek felépítése szempontjából a központi egység néhány tulajdonsága különösen nagy jelentőséggel bír: a címzési mechanizmus, az utasításrendszer, a megszakítási rendszer és a védelmi mechanizmus. Az említett négy hardverelem tárgyalása előtt -- a felmerülő kapcsolatok miatt -- röviden megemlítjük az operatív tárat. Az operatív tár olyan tárolóeszköz, amelyet a központi egység közvetlenül elérhet, így a benne tárolt kódok (utasítások) közvetlenül végrehajthatók. Régebben ténylegesen a központi egység szekrényében helyezkedett el, ezért van az, hogy az ISO szabvány ma is központi tárként, főtárként emlegeti, jóllehet ma már meglehetősen önálló hardver elem. Operatív tár nélkül nem is képzelhető el számítógép, különösen amióta Neumann János bevezette a tárolt program elvét. A tárakról részletesebben is lesz még szó. A címzési mechanizmus mindazon -- számkódolási -- eszközök és módszerek összessége, melyeknek segítségével az utasításokhoz és adatokhoz operatív tárhelyeket lehet hozzárendelni, vagy a különböző hardvereszközök azonosítását meg lehet oldani. A továbbiakban az operatív tár címzésével foglalkozunk. A legegyszerűbb az egyenes címzés: a címek közvetlenül a tárolóhelyekre hivatkoznak. Ilyen központi egység programozása igen nehézkes lenne. A következő "fokozat" egy vagy több indexregiszter használata, melyek tartalma (általában hozzáadással) módosíthatja az egyenes címet. Az indexeléssel is kombinálható indirekt címzés (a cím tartalma egy újabb cím, ahol az operandus van) sok lehetőséget tartogat az ügyes programozónak. Gyártottak többszörös indirekciót megengedő központi egységeket is. A központi tár méretének növekedésével bővíteni kellett az utasítások címtartományát is. Ma már a 16 biten címezhető 64 Kbájt abszolút minimum. Hogy ne kelljen az utasításokban a teljes címtartománynak helyet biztosítani, bevezették a bázisregisztereket, amelyek tulajdonképpen speciális indexregiszterek. Az alapcím a megfelelő méretű (pl. 32 bites) bázisregiszterben van, az utasítások csak az ehhez hozzáadandó különbséget (angolul: displacement vagy offset) tartalmazzák, amelyek hosszát 8-12-16 bitre korlátozzák. Az említett különbséget a magyar számítógépes zsargonban eltolásnak vagy ofszetnek nevezik.
A háttértárak fejlődése lehetővé tette a virtuális címzés kialakulását. Ekkor a felhasználó által látott, jóformán korlátlan méretű tárolónak csak egy kis része létezik a rendszerben operatív tárként, nagyobbik része valamilyen háttértáron (általában mágneslemezen) van. A központi egység címzési mechanizmusa fölé az operációs rendszerbe olyan virtuális tárkezelő alrendszert építenek, amely a háttértár és az operatív tár között automatikusan elvégzi a felhasználó számára a címhivatkozások során igényelt adatcserét. A virtuális címzés lehet egy- (lapozás), vagy kétszintű (lapozás és szegmentálás). Ezekről a megfelelő operációs rendszeri kezelőeszközök kapcsán lesz szó részletesebben, itt csak egy vázlatos ábrával próbáljuk szemléltetni a viszonyokat: Virtuális (logikai) címtartomány (lapokra szabdalva) >--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--> >aa bb cc dd ee ff gg >*>.........>*>...............>* 1. szegmens 2. szegmens 3. szegmens ... Lapleképezés a valós tárra: oo oo oo oo bb aa ff ee (oo=operációs rendszer!) >--+--+--+--+--+.....+--+--+--> Operatív tár (lapokra tördelve) A logikai és fizikai címtartomány nemcsak a virtuális címzés problémáját vetette fel a hardverekben. A virtuális címzési technika feltételezi, hogy a processzor nagyobb címtartomány átfogására képes, mint az operatív tár valódi címtartománya. Vannak azonban olyan processzorok is, amelyek nem tudják egyszerre megcímezni az operatív tár teljes címtartományát. Ilyenkor különleges hardvereszközzel, a társzervezéssel és csatlakozó operációs rendszeri szoftverrel teszik lehetővé a teljes operatív tár elérését. Az egyszerre elérhető tárrészt szegmensnek hívják. (Vigyázat! Ez a szegmensfogalom nem egészen azonos a virtuális címzésnél használt szegmensfogalommal!) A fizikai címtartományban a szegmens tényleges helyét egy speciális regiszter, a szegmensregiszter jelöli ki: Teljes operatív tár >-------------------*--------------------------------------> | szegmensregiszter | >-------------------> szegmens A társzervezést egyes hardverekben kombinálják a virtuális címzéssel is (pl.: INTEL 80286/80386!), ami igen rugalmasan konfigurálható számítógépes rendszerek létrehozását biztosítja. Az utasításrendszer a hardverrétegben mindazon utasítások összessége, melyeket a központi egység végre tud hajtani. Bár az utasítások szerkezete gépenként nagyon változatos lehet, a legtöbb utasítás egy utasításkódból és egy vagy több címből áll. Míg a régebbi processzoroknál az utasításkészlet néhány tucat utasításra korlátozódott, a mai rendszereknél általában több száz különböző utasításkód használható. Az utasításkódon és a cím(ek)en kívül gyakran valamilyen járulékos információ is szerepel az utasításban (például: címzési mód, indexelés, indirekció stb.). Tipikus utasítás-beosztás: +------------+-------------+---------------+ | Műveletkód | Címzési mód | Címek | +------------+-------------+---------------+ Minél bonyolultabb egy központi egység utasításkészlete, annál rövidebben lehet hozzá gépi kódú
programokat írni. (A gépi kódút azért hangsúlyoztuk ki, mert a gyakorlati tapasztalat szerint a fordítóprogramok írói nem merik kihasználni a hatékonyabb hardver utasításokat, s ezért a magas szintű nyelvek nemigen profitálnak belőlük! Rendszerint az a probléma, hogy a fordítóprogramoknak a gépcsaládok legalacsonyabb modelljein is működő kódokat kell generálniuk.) Az egyszerűbb utasításkészlet gyorsabb dekódolást tesz lehetővé, ami nagysebességű utasítás-végrehajtást eredményez. Ezért és a magas szintű, portabilitást biztosító programozási nyelvek fokozottabb térnyerése miatt manapság terjednek a csökkentett utasításkészlettel rendelkező számítógépek (angolul RISC = Reduced Instruction Set Computers, velük szemben állnak a komplex utasításkészletűek (CISC = Complex Instruction Set Computers). A csökkentett utasításkészletet úgy határozzák meg, hogy lehetőleg minden utasítás egyforma hosszúságú legyen, és egyetlen gépi utasításciklus alatt végrehajtódjon. Bonyolultabb utasításokat csak akkor engednek meg, ha azok használata nagyon jelentős előnnyel jár. A komplex utasításkészletek alkalmazása azonban még napjainkban is meghatározó hardverirányzat. Az újabb -- a mai hardver fejlődést döntően meghatározó (MOTOROLA, INTEL) -- mikroprocesszorok is kifejezetten bonyolult utasításkészlettel rendelkeznek (a nagyobb gépeknél ez a természetes!). Az operációs rendszerek egyrészt messzemenően figyelembe veszik, másrészt általában kibővítik az eredeti utasításrendszert. A bővítés elvileg azt jelenti, hogy az eredeti hardverutasítások segítségével programozott új utasítások új -- az eredeti gépi kódban kihasználatlan -- kóddal hajthatók végre. A bővítést megvalósító programokat mikrokódnak, mikroprogramoknak is nevezik. Az így létrehozott virtuális központi egység sok egyéb lehetőséget is tartalmazhat. Igen általános -- és az operációs rendszerek védelmi rendszerének megszervezéséhez nélkülözhetetlenül fontos -- több működési állapot megvalósítása. Ezek közül leggyakoribbak a kétállapotú architektúrák. Normál állapotban a bővített utasításkészletnek csak egy részhalmaza használható, míg privilegizált állapotban a teljes utasításrendszer rendelkezésre áll. A privilegizált állapotot az IBM 370-en például "supervisor állapot"-nak, a Honeywell-en "master mód"-nak hívták. A privilegizált állapot legtöbbször megszakításokkal kapcsolatos, sok hardverben a megszakítás fellépése kiváltja a privilegizált állapotba való átmenetet is. Természetesen szükség van olyan utasításra is, amely normál állapotban mesterséges megszakítást és ezzel állapotváltást idéz elő (ilyen például az IBM 370 SVC utasítása). Az ilyen utasításokat használják az úgynevezett szoftver megszakítások programozásához. Többnyire csak privilegizált állapotban hajhatók végre a B/K utasítások, valamint a gép megszakításokra adott reakcióját befolyásoló parancsok. A megszakítási rendszerre azért van szükség, mert a számítógépes rendszerek olyan alkatrészeket is tartalmaznak, amelyek párhuzamosan is működtethetők. Gondoljunk például a B/K műveletekre! Ezek egyrészt időigényesek, másrészt általában csak indítást igényelnek a központi egységtől, végrehajtásukról pedig külön processzorok (csatornák) gondoskodnak. A probléma gyökere az, hogy az elindított transzfer végét hogy lehet észlelni. Elképzelhető lenne olyan megoldás, hogy megvizsgáljuk időnként a perifériát, hogy foglalt-e még. Kérdés, hogy milyen időközönként vizsgáljuk. Ha sok perifériával kell egyidejűleg foglalkozni, akkor a processzor egyebet se csinálna, mint állandóan csak a perifériákat figyelné ciklikusan. Hasznos tevékenységre alig maradna ideje. Jobb, ha a periféria jelez akkor, amikor kész az átvitel, hiszen akkor csak egyszer kell foglalkozni a perifériával. A processzor éppen folyó munkáját persze meg kell szakítani ahhoz, hogy a transzfer végén szükséges teendőket el tudjuk végezni.
A megszakítási rendszer ezért lehetővé teszi: * a reagálást a központi egységen belül fellépő speciális feltételekre (pl.: processzorhiba feldolgozását, ami lehet nullával való osztás, vagy nem létező bájtra való hivatkozás eredménye), * a kívülről érkező jelzések (megszakításkérelmek) kezelését, és ezek által * a párhuzamosan üzemeltethető egységek közötti koordinációt. A megszakítások kezelését a hardver- és szoftvereszközök igen változatos keveréke végzi bonyolult algoritmusok alapján. Minden megszakító rendszer azonban azt az alapvető problémát oldja meg, hogy egy véletlenszerűen bekövetkező esemény képes legyen megváltoztatni a műveletek végrehajtási sorrendjét az éppen elvégzés alatt álló művelet eredményének elvesztése nélkül. A megszakítás tehát tulajdonképpen hardver úton erőltetett vezérlésátadást (ugrást) jelent a megszakítást feldolgozó, ún. megszakító rutinra. A megszakító rutin indulása előtt azonban rögzíteni (menteni) kell a központi egység állapotát, hogy azt a megszakítás feldolgozása után vissza tudjuk állítani úgy, hogy az eredeti programot hibátlanul folytathassuk (ha ennek van értelme). A központi egység állapotát minden pillanatban egy rögzített hosszúságú állapotvektorral lehet jellemezni (utasításszámláló, regiszterek, állapotjelzők tartalma). A megszakító rutin hívása általában ugrótáblán (hardveres zsargonban megszakítási vektoron) keresztül valósul meg, ahova a vezérlés a megfelelő megszakítás bekövetkezésekor hardver úton adódik át. Az ugrótáblából a megszakító rutin átveheti a működéséhez szükséges paramétereket is. A megszakítási rendszert főleg az teszi bonyolulttá, hogy egy megszakítás feldolgozása közben újabb megszakítási kérelem is érkezhet, amivel a rendszernek szintén foglalkoznia kell. Ez a jelenség jóformán tetszőleges mélységben egymásba skatulyázva is felléphet. A problémát a gyakorlatban úgy egyszerűsítik, hogy bizonyos (például processzor hiba) megszakítások kezelésének idejére letiltják minden más (de legalább az adott osztályba tartozó) megszakítás fogadását. Ez azt jelenti, hogy ha ismételten ilyen megszakítási kérelem érkezik, akkor ezt a központi egység várakoztatja az éppen feldolgozás alatt álló processzorhiba lekezelésének befejezéséig. Ugyanakkor természetes, hogy valamilyen megszakítás kezelése közben a központi egység más osztályba tartozó megszakításokat elfogad. Egy nyomtató működése közben például egy lemez-adatcsere kényelmesen lefolytatható. Azt, hogy a megszakító rutinok is megszakíthatók legyenek, úgy oldják meg, hogy az állapotvektort veremként működő tárba mentik. Ez jórészt szoftver úton megy végbe, de az első lépésekhez hardver támogatásra is szükség van. (A régi utasításszámláló értéket csak a hardver tudja félretenni, a program nem!) A veremből mindig az oda utoljára beírt állapotvektor emelhető ki (az ilyen vermet angolul LIFO = Last In First Out stacknek hívják), a veremmutató pedig automatikusan átáll az eggyel mélyebben elhelyezett elemre. A skatulyázott megszakításoknál ez a verem teszi lehetővé a megfelelő helyre való visszatérést valahányszor egy megszakítás feldolgozása befejeződött. A megszakítások feldolgozása azonban még így sem problémamentes, mivel az állapotvektor mentésének ideje alatt a rendszer "védtelen" egy újabb megszakítással szemben. Kézenfekvő megoldás, hogy erre a rövid időre letiltjuk a megszakításokat. A letiltást addig kell fenntartani, amíg a megszakító rutin el nem ér egy olyan biztonságos pontra, ahol az újabb megszakítás már nem zavarhat.
A megszakítás menete sematikusan a következő: * megszakítási kérelem érkezik a központi egységhez; * a központi egység a kérelmet várakoztatja, amíg egy utasításciklus be nem fejeződik, vagy amíg az adott osztályú megszakítás tiltott; * amikor a központi egység elfogadja a megszakítást, segít félretenni a megszakított program állapotát jelző állapotvektort a megfelelő verembe; * automatikusan privilegizált állapot jön létre, és legalább az adott osztály megszakítása letiltódik; * a megszakítási osztálynak megfelelő megszakítási vektorból a központi egység előveszi a megszakító rutin induló állapotvektorát, és a megszakító rutin első utasítására adja a vezérlést; * a megszakító rutin befejezi az előző program állapotvektorának mentését, ha ezt a hardver nem végzi el tökéletesen, majd elkezdi a megszakítás-kérelem okának felderítését és a szükséges teendők elvégzését; * amint a megszakítás feldolgozása túl van a kritikus szakaszon, visszaállítja az adott osztály megszakíthatóságát; * a megszakítás feldolgozása rendszerint azzal ér véget, hogy a vezérlést átadja valamilyen más programnak, ami többnyire az operációs rendszer valamelyik ütemező rutinja; * az ütemező dönt a folytatásról, és előveszi a folytatni szándékozott program állapotvektorát a veremből, majd a vezérlést a program megszakítását követő utasításra adja. A megszakításkezelés nyilvánvalóan határterületen van, jó megszakítás-kezelő rendszer csak a hardver- és szoftvertervezők harmonikus együttműködésétől remélhető. Ezen együttműködésből származó néhány -- azóta általánosabban elterjedt -- ötlet ma is figyelemre méltó: * A központi egység állapotának mentése helyett több regiszterkészletet építenek a processzorba. * Megszakításokat engedélyező egyszerűen manipulálhatók.
maszkok
bevezetése,
amelyek
logikai utasításokkal
* Egymást nem zavaró megszakítási osztályok bevezetése és az osztályok fontossági sorrendbe állítása (prioritás). * Az utasításszámláló regiszter tartalmának közvetlen (ugró utasítás nélküli) módosíthatósága. Minden esetben az a közös cél, hogy a rendszer minél kevesebb ideig legyen elvágva -- megszakítás fogadására alkalmatlan állapotban -- a külvilágtól. Védelmi mechanizmusra azért van szükség, hogy megakadályozhassuk a számítógépes rendszerben a programok hibás működéséből eredő károsodásokat vagy a felhasználók illetéktelen beavatkozásait. A probléma tipikusan a multiprogramozásnál fordulhat elő (a felhasználók ilyenkor tudnak "egymás levesébe belekanalazni"). Figyelembe kell venni még azt is, hogy az operációs rendszer és a felhasználó programja eleve "párhuzamosan" fut, ami végeredményben kétszeres
multiprogramozást jelent. A védelmi mechanizmusok alapvetően háromfajta védelmet nyújtanak: a központi egység, az operatív tár és a B/K műveletek védelmét. A központi egység védelme a felhasználói programok említett ésszerűtlen viselkedése miatt fellépő veszélyek elhárítását célozza. Ha például a program végtelen ciklusba kerül, az operációs rendszer nem kapja meg a vezérlést bizonyos, periódikusan ismétlődő feladatainak (például a képernyőtartalom frissítése) ellátásához, ami nyilván nem megengedhető. A szokásos megoldás az úgynevezett óramegszakítás, amely szabályos időközönként generálódik. Az óramegszakítás lehet állandó (pl. 1/50 másodperc) vagy szabályozható időközű. Maga a megszakítás egy regiszterben való számlálással valósítható meg. Az órára vonatkozó műveletek természetesen csak privilegizált módban hajthatók végre. Normál állapotban az ilyen utasítások végrehajtása helyett a hardver megszakítja a program működését, mert hibának tartja a privilegizált utasítások végrehajtásának kísérletét. Az operatív tár védelme azt jelenti, hogy minden program csak a számára valamilyen módon kiosztott tárterületen dolgozhat, ha ezt a szabályt megsérti, megszakítás jön létre, majd az operációs rendszer be tud avatkozni. Azt, hogy ilyen fajta védelemre szükség van, nem kell különösebben indokolni, hiszen például súlyos esetben a felhasználói programok átírhatnák az operációs rendszer területének tartalmát, ami teljes anarchiához vezetne. A B/K műveletek védelme szintén megoldható privilegizált utasítások segítségével olymódon, hogy a külső egységekkel való adatcsere alsó szintjét csak privilegizált utasításokkal engedjük megvalósítani. Erre azért van szükség, mert különben egy hibás -- például az állomány végét nem érzékelő -- olvasóprogram megbéníthatná az egész rendszert. A közösen használható perifériák (mágneslemezek) használatát pedig eleve központilag kell koordinálni. A koordinálás csak akkor működik jól, ha minden igény egy pontban találkozik. Célszerűen a privilegizált üzemmódban működő operációs rendszerre kell rábízni a B/K koordinációját, normál állapotban működő alkalmazói programoknak pedig meg kell tiltani a B/K műveletek közvetlen használatát. Hangsúlyozzuk, hogy az operációs rendszerek védelmi mechanizmusai csak akkor működnek hatásosan, ha a processzor hardver úton, privilegizált üzemmód(okk)al támogatja. Nem lehet például az MS--DOS operációs rendszerben védett, multiprogramozott környezetet teremteni, mert az INTEL 8086/8088-as mikroprocesszoroknak nincs privilegizált üzemmódja. A dolognak az a szépséghibája , hogy az MS--DOS az AT gépeken sem használja ki az AT gépek fejlettebb INTEL 80286-os processzorának privilegizált üzemmódját. Ez példája annak, hogy egy rossz operációs rendszeri architektúra képtelen igazodni a későbbi hardverfejlődéshez, és gyakorlatilag a fejlődés gátjává válik. Az AT gépek hardver lehetőségeit igazán csak a UNIX operációs rendszer Microsoft változata, a XENIX tudja kihasználni (de a felhasználó elég drága árat fizet érte mind pénzben, mind az elrabolt hardver erőforrások tekintetében). A mondottakból világosan kitűnik, hogy az IBM PC-k multiprogramozható OS/2 (az MS--DOS utódját képező) operációs rendszere miért csak a privilegizált üzemmóddal felszerelt INTEL 80283/80383-as processzorokkal megépített IBM AT vagy PS/2 modelleken használható. A UNIX XENIX/86-os változata, és néhány más szoftver (konkurens DOS, NOVELL ANW86, PCUNIX stb.) lehetőséget teremt ugyan multiprogramozásra az XT gépeken, de hibás programok ellen nem tud védelmet nyújtani. Bele kell nyugodni, hogy az XT és az MS-DOS igazából csak egyfelhasználós, monoprogramozott környezetet biztosít. Maga az MS-DOS sem védett az ellen, hogy egy alkalmazói program esetleg tönkre tegye. Ellenkezőleg! Az MS-DOS kifejezetten igényli, hogy a jól képzett alkalmazói programozók "beletúrjanak" az operációs rendszer területébe, és/vagy közvetlenül mozgassák a perifériákat. Az így eluralkodott programozói stílus hosszú időre akadályozni fogja, hogy az ehhez szokott programozók rátérjenek védelmet biztosító operációs rendszerek (OS/2, XENIX) használatára.
1.4.2. Tárak Általános értelemben tárnak nevezünk minden adattárolásra használható eszközt, amellyel -- azt mondjuk -- írás és olvasás útján kommunikálni lehet. Mi a számítógépes rendszerekkel kapcsolatban a gép belső vagy operatív tárolóját (amelynek szavai vagy bájtjai az utasításkészlet számára elérhetők) hívjuk tárnak (angolul: memory), a mágneslemezek, mágnesdobok, mágnesszalagok és egyéb hasonló tárak esetében inkább a háttértár vagy a külső tároló (angolul: store) kifejezést használjuk. A tár a hardverréteg nélkülözhetetlenül fontos része, így nem véletlen, hogy egy számítógéppel kapcsolatban általában ez az első adat, amit megkérdeznek vagy megadnak. Az egyszerűbb rendszerekben (első és második generáció) a tárat mágnesdob, majd ferritgyűrűk (core memory) segítségével realizálták, és teljes kapacitása felett a felhasználó rendelkezett. Az operációs rendszerek megjelenése, a tárkapacitás növekedése azonban viszonylag gyorsan megváltoztatta ezt a helyzetet. A sok regiszterrel rendelkező központi egységekben a regiszterek halmaza tulajdonképpen valami gyors működésű tárként fogható fel, amely a központi egység és a tényleges operatív tár közötti adatcserét igyekszik gyorsítani. A gyors működésű regiszterek mintájára a legtöbb gépet továbbfejlesztették, ami más szóval azt jelenti, hogy az operatív tár sem egységes. Általában kis kapacitású, de rövidebb elérési idejű gyorstárból és az eredeti operatív tárból épül fel. A két tároló között legalább egy nagyságrend sebességkülönbség van, ugyanakkor a gyorstárak jóval drágábbak (viszont még mindig olcsóbbak, mint a regiszterek). A gyorstárat az egyes gyártó cégek általában saját elnevezésükkel látták el (buffer, cache, scratch pad stb.). A gyorstár kezelése erősen eltérő. Van, ahol a felhasználó is hozzáfér legalább egy részéhez, de sok esetben csak az operációs rendszer végzi az adatmozgatást a gyors és a normál operatív tár között. A processzor közvetlenül csak a gyors tárból dolgozik, s ha a hivatkozott adat nincs ott, a felhasználást egy implicit adatátvitel előzi meg az operatív tár és a gyorstár között. A rendszer teljesítménye szempontjából meghatározó a gyorstár találati valószínűsége. A mérések azt mutatják, hogy a találati valószínűség 5 %-os növelése a processzor utasítás-végrehajtási sebességét mintegy 25 %-kal is javíthatja. A gyorstárak gyorsító szerepének alapja a lokalitás elve: a számítógépes algoritmusokra jellemző, hogy viszonylag hosszú ideig foglalkoznak az operatív tár egy szűk környezetével. A félvezetős integrált áramkörök elterjedésével nőtt a tárak kapacitása és sebessége, csökkent az ára és fizikai mérete, így a tárakkal kapcsolatban egyéb szempontok -- elsősorban az elérési módok -kerültek előtérbe. Elterjedtek a csak olvasható (angolul ROM = Read Only Memory) tárak, amelyekben állandóan használt szoftverkomponenseket (pl. az operációs rendszer fontosabb rutinjait, fordítóprogramokat) tárolnak fixen. Egyes számítógépekben már a ROM előtt is alkalmaztak -- erősen korlátozott módon -- ún. átírható tartalmú tárakat (például a Burroughs B1700 gépében) a látható architektúra változtatása céljából. Ezek utódja az integrált áramkörök korában a PROM és az EPROM, a törölhető, programozható tár, melynek tartalma csak rendszeren kívüli folyamattal, elektronikus programozással írható át (beégetés). A ROM és (E)PROM eszközök lehetővé tették, hogy a mikroprogramokat a hardverréteg alá rejtsük, illetve, hogy a hardver architektúrát is programozott úton oldjuk meg egyszerű utasításkészletű mikroprocesszorokra támaszkodva. Ez teremti meg a számítógépes rendszer intelligenciájának korábbi lehetőségeknél jobb szétosztását is. Jellemző erre az intelligens terminálok létrejötte és a mikroprocesszorok megjelenése a korábban csak huzalozott elektronikát (logikai áramköri kapcsolásokat) tartalmazó perifériákban. Huzalozott elektronikát ma már csak akkor alkalmazunk, ha a sebességtényezők ezt indokolják, mert a huzalozott elektronika mindig gyorsabb működést biztosít, mint a mikroprogramozott, ugyanakkor sokkal drágább, és lassabban fejleszthető ki, hibája javíthatatlan.
Míg a ROM és az (E)PROM nemfelejtő, statikus tárak, azaz a gép kikapcsolt állapotában is megőrzik tartalmukat, a hagyományos operatív tár szerepét az ún. RAM (Random Access Memory), a véletlen elérésű (és rendszerint a tartalom folyamatos frissítésére szoruló) tárelem vette át, amely a feszültség kikapcsolása után elveszti tartalmát. Az összkapacitást már megabájtokban mérik, a tárchipek kapacitása pedig 256-1024-4096 kilobit, sőt -- a közeljövő nagy ugrásaként! -- 16 Mbit (1989!). 1.4.3. Háttértárak Általános jellemzőjük a nagy statikus tárolókapacitás, a viszonylag lassú és esetenként korlátozott hozzáférés. A fejlődés során először a már csaknem elfelejtett mágnesdobok jelentek meg, majd a mágnesszalagok korszaka következett. A mágnesszalagok hatalmas tárolókapacitása (amit tulajdonképpen csak a szalag hossza determinál) sokat enyhített azon a hátrányon, hogy csak szekvenciális adatelérésre adtak lehetőséget. Nagy adathalmazok archiválására ma is használatosak. A mindennapi használatban a szalagot a mágneslemezek elterjedése szorította vissza. Ezek előnye, hogy valamivel kisebb -- de még mindig több 100 megabájtos -- kapacitás mellett elfogadhatóan gyors, véletlen elérést biztosítanak (a véletlenség arra utal, hogy a tárolt adatok nagyjából egyforma időn belül hozzáférhetők, függetlenül attól, hogy véletlenül melyikre van éppen szükség). A cserélhetőség feladásával az elérési idő tovább csökkent, a fix és cserélhető lemezek kombinációja pedig minden rendszer számára megvalósíthatóvá tette az alkalmazási környezethez legjobban illeszkedő tárlókonfiguráció kialakítását. Az ún. winchester rendszer, valamint a hajlékony cserélhető lemezek bevezetésével a nagygépek mellett a mini- és a mikrogépek is megkapták olcsó, gyors és elég megbízható, nagy kapacitású háttértáraikat. (A CD-ROM-ot még akkoriban fedezték föl.) A mágneslemezek megjelenése az operációs rendszerek szempontjából döntő jelentőségű volt, mert a drága és kis mérető operatív tárakban nem lehetett túl sok adatot tárolni, a sorkezelési adatok mágnesszalagos tárolása pedig elviselhetetlenül lassú működést eredményezett volna. A mágneslemezek a véletlen elérési lehetőségeikkel egyszerű megoldást kínáltak a kötegelt és multiprogramozott környezetben felmerülő sorok kezelésére. 1.4.4. Egyéb perifériák A számítógépes rendszerhez kapcsolható készülékek igen nagy változatosságot mutatnak, mi azonban csak a legfontosabbakkal, a nyomtatókkal, képernyőkkel, billentyűzetekkel és adatátviteli vonalakkal foglalkozunk. Ezek legfontosabb közös tulajdonsága, hogy bájtonkénti adatátvitelt igényelnek. A nyomtatók minden számítógépes rendszer nélkülözhetetlen részei. Az írógépből kiindulva, a sornyomtatókon keresztül a mátrix, majd a lézernyomtatókig sokat fejlődtek és nagy változatosságot mutatnak. Az operációs rendszerek általában megkülönböztetett módon kezelik a nyomtatókat, összegyűjtik a nyomtatóra szánt adatokat, és külön menetben, más munkákkal párhuzamosan végzik el a listázást. A képernyő és a billentyűzet a manuális adatcsere eszközei. Ezek is a korábbi elektromos írógépből erednek, amely először a hardver vezérlésére szolgáló ún. főkonzol billentyűinek és kijelzőinek szerepét vette át. Így ragadt rá erre az operátori írógépre a konzolírógép vagy a még rövidebb konzol elnevezés. Később a papírt képernyő váltotta fel, de az írógép billentyűzet megmaradt. Az operációs rendszerek fejlődésének külön lökést adott a képernyős terminálok elterjedése, mivel így a nehézkes, kötegelt rendszereket a legtöbb alkalmazási területen a felhasználót segítő, interaktív rendszerek válthatták fel. Ez legalább egy hardvergenerációval felérő
fejlődés volt. A grafikus lehetőségekkel felruházott, finom felbontású, színes képernyő nagyban segíti az igazán barátságos (interaktív) alkalmazási rendszerek fejlesztését. Az adatátviteli vonalak a távközlési vonallal összekapcsolt számítógépek esetében játszanak fontos szerepet. Az adatátvitel itt is bájtonként megy végbe, a vonalra az adat egy modem közbeiktatásával jut. Az adatátvitelhez természetesen meglehetősen összetett szoftver tartozik, hiszen a kétoldalú kapcsolattartás -- főként a vonalhibák elhárítása miatt -- bonyolult feltételeket teremt.
1.5. Mintapéldák: hardverarchitektúrák A hardverarchitektúrákat (a történelmi fejlődés vonalán) a nagyszámítógépektől kiindulva, a miniszámítógépeken át a mikroszámítógépekig tekintjük át. 1.5.1. IBM 360/370, ESZR-I/II/III sorozatok Az IBM cég a hatvanas évek közepén vezette be 360-as gépeit, amelyek modelljei egy -- szoftverszinten erősen, hardverszinten kevésbé -- kompatibilis sorozatot képeztek. A 370-es sorozat ennek folytatásaként jelent meg, de csak korlátozott virtuális címzési lehetőségekkel haladta meg elődeit (a korlátozás azt jelentette, hogy a lapozás és a szegmentálás hardver úton nem támogatja a programok menet közbeni dinamikus áthelyezését, amire sok akkortájt gyártott hardver már képes volt -- pl.: ICL). A 370-es gépek új utasításokkal segítettek a nagy pontosságú tudományos számításoknál, és még a többprocesszoros üzemmód koordinációs problémáinak megoldására is felkészültek. Legújabb tagjaik a 4300-as és a 30xx-es inkább csak hardvertechnológiában és szoftver támogatásban különböznek. A keleti ESZR indulásakor IBM 360-as kompatibilitást tűzték ki célul, így az ESZR sorozatok szintén ebben az irányban haladnak. A processzor állapotát a programállapotszó (angolul PSW = Program Status Word) határozza meg, amely nyolcbájtos, és bitcsoportjai különféle processzorállapotokat reprezentálnak. A PSW végén három bájton szerepel a 24 bites tárcím. A maximális címezhető tár így 16 megabájt. A mai hardverfejlődés szempontjából ez meglehetősen kellemetlen korlát. A processzor utasításkészlete komplex, de eredetileg opcionálisan vásárolható részei is voltak, amelyek a későbbi modellekben és különösen az ESZR sorozatokban standard elemmé váltak. Az utasítások hossza és végrehajtási ideje erősen változó. Az utasítások hosszát félszóban mérik, ami két bájt. Egy, kettő és három félszavas utasítások vannak aszerint, hogy hány operandusa van az utasításnak, és milyen címzési módot használunk. Az utasítások a tárban csak ún. "félszóhatáron" helyezhetők el, azaz csak páros címeken kezdődhetnek. (A PSW utolsó bitje így mindig nulla.) Címzési rendszere elég egyszerű. Konstansmegadás, regiszteroperandus, báziskódolt és indexelt címzés használható csak. Erősen hiányzik az indirekt címzés. A virtuális címzési rendszer nem jelent külön címzési módokat, a programozónak a virtuális címkezelés "átlátszó". A B/K műveletek puffereinek azonban összefüggő "valós tárterületekre" kellenek, mert nem tudnak lapozni. A gépcsalád megszakítási rendszere óvatosan vektorosnak mondható, de csak öt megszakítási osztály vektorainak van hely. Az operatív tár alsó címeit a központi egység fix kiosztásban használja. A PSW elmentendő állapota megszakításkor a megfelelő fix címre kerül (régi PSW terület), majd a megfelelő osztály fix vektorcíméről (új PSW terület) kerül be a processzor PSW-be a megszakítás-kezelő program induló állapotát meghatározó státusszó. A státusszó megadja a megszakító program címét, és letiltja az adott osztályban a megszakítást. Ezzel a processzor vezérlése átkerül a megszakító programba, amely folytatja az állapotmentést a processzor regisztereinek és a régi PSW értékének elmentésével. Ez utóbbi után felszabadítható a megszakítás
tiltása az adott osztályban, mert a régi PSW vektor már elrontható. Védelmi rendszerével kapcsolatban már volt szó arról, hogy a processzornak két állapota van. A normál állapotot programállapotnak, a privilegizált állapotot pedig szupervizor (felügyelő) állapotnak nevezik IBM terminológiával. A privilegizált utasításkészlet csak szupervizor állapotban használható. A B/K műveletek a processzor működésétől függetlenül, több csatornán át, izokron és aszinkron módon folyhatnak. A processzor csak elindítja a transzfereket, és azok befejeződésüket megszakítás-kérelemmel jelzik. A tárvédelem 2 Kbájtos szegmensenként négybites tárvédelmi kulcs hozzárendelésével működik. Ez az operatív tárban egyidejűleg -- az operációs rendszer magjával együtt -- 16 program egymástól védett működését engedi meg. A nullás (0) tárvédelmi kulcsú tartományokban elhelyezkedő programoknak a tár bármely részéhez tetszőleges (írási, olvasási) hozzáférési joguk van. Természetesen ezt a rendszermag, a szupervizor szegmenseinek tárolásánál használják, de ideiglenesen felhasználói programok egymás közti közlekedésének lebonyolításához is szükség lehet ilyen védelmi kulcsra. Ilyenkor feltételezik, hogy jól belőtt rendszerprogram működik a kritikus partícióban. 1.5.2. PDP 11, MSZR I/II, VAX, MSZR III sorozatok A miniszámítógépek a Digital Equipment Corporation (DEC) cég azon reklámötletéből erednek, hogy nem kell nagyobb hardverkapacitást vásárolnunk, mint amit a feldolgozásunk igényel. Ennek nyomán a DEC elkezdett "lecsupaszított" gépeket gyártani, amelyek csökkentett utasításkészletű, kis sebességű processzort, kevés operatív tárat, minimális háttértárat és egyéb perifériát, rendszerint csak egy Teletype telexírógépet tartalmaztak. A telex írógép egyidejűleg négy perifériát tudott helyettesíteni: bevitelt billentyűzetről és lyukszalagolvasóról, valamint kivitelt írógépre és lyukszalaglyukasztóra. Az egész nagyon ökonomikus volt, és átütő sikert aratott, pedig a gépvásárlók addig erősen megszokták, hogy a számítógépekkel nagy számítógéptermeket szokás bebútorozni. Szerencsére a DEC a nagygépektől jobbára idegen piacot, a folyamatvezérlési környezeteket célozta meg, amelyekben eleinte tényleg nagyon egyszerű folyamatvezérlő programok üzemeltetésére volt igény. Természetes volt, hogy ezekhez kis kapacitású gépek lehetnek csak gazdaságosak. Később persze a folyamatvezérlési környezetek igényei is rohamosan növekedni kezdtek, úgyhogy a DEC is kénytelen volt minigépeinek teljesítményét növelni, de addigra már megnyerte a csatát a piacon. A DEC gépek telexírógépes perifériája kezdettől fogva interaktív használatot tett lehetővé, bár ez a folyamatvezérlő környezetben inkább szükségszerűségként merült fel. A minigépek tehát eleinte csökkentett utasításkészlettel rendelkeztek (PDP 11), de a későbbi fejlődés nyomán szintén elérték a komplex színvonalat (VAX). Címzési rendszerük már kezdettől fogva elég bonyolult volt, hogy a szűk utasításkészlettel minél hatékonyabb kódokat lehessen generálni. Egyes címzési módok igazodtak a folyamatvezérlési feladatokból eredő különleges sajátosságokhoz (veremkezelés, autoinkrement/dekrement). (Ezeket a hardverújdonságokat a mikroprocesszoros korszak később kapásból át is örökölte.) A címzési rendszerre erősen rányomja bélyegét, hogy a címbusz eredetileg 16 bites volt, ami csak 64 Kbájt, illetve PDP filozófiával 32 Kszó címzését tette lehetővé (azaz egy szó kétbájtos). Ráadásul bevezettek egy addig szintén szokatlan technikát, a tárcímekbe beágyazott perifériakezelést, ami a címtartomány felső címeiből 4 Kszót mindig elrabol. A későbbi PDP modellek társzervező modullal próbáltak úrrá lenni a helyzeten (PDP 11/40: 124 Kszó, PDP 11/70: 2 Mszó). A címzési problémákat persze a minigépeknél is csak a 32 bites korszak beköszöntése oldotta meg megnyugtatóan, amelyet még ráadásul virtuális címzéssel is kombináltak (VAX-ok). A 32 bites minigépeket úgy tervezték meg, hogy 16 bites üzemmódban is tudjanak szükség esetén dolgozni. A minigépek megszakítási rendszerének kialakítását szintén erősen motiválta a megcélzott alkalmazói környezet. A folyamatvezérlő környezetből érkező megszakítási kérelmek
szétválasztásához ugyanis erősen vektoros megszakítási rendszerre volt szükség, hogy a hardver segíteni tudja a megszakítási okok szétválogatását. Több szoftvermegszakító utasítás is van az utasításkészletben. Megszakításkor automatikusan a verembe kerül a megszakított program 16 bites programállapotszava és a 16 bites programszámláló, majd a vektorcímről betöltődik a programszámláló és a programállapotszó. Ezzel megtörtént az átkapcsolás a megszakítás-feldolgozó programra. A megszakító program végén egy speciális (visszatérés megszakításból -- RTI) utasítással elérhetjük, hogy a programszámláló és a programállapotszó értéke a veremből automatikusan visszatöltődjön, és a megszakított program folytatódjon. Így a visszakapcsolás is igen gyors. (A mikroprocesszorokban ezeket a tulajdonságokat is igyekeztek maximálisan átörökölni.) A kevés számú (végeredményben csak hat darab) 16 bites, általános regiszter mentése a megszakító rutinok feladata, de olykor a veremtároló regiszter mentése is szóba kerül. A védelmi rendszer természetesen itt eleve nem hiányozhat, hiszen erős multiprogramozás merül fel. Kettő vagy három, egyes minigépeknél még több processzorállapot is létezik. 1.5.3. INTEL 8086/8088, 80286, 80386 mikroprocesszor család Az INTEL cég a mikroprocesszorok atyja. Igazán azonban akkor "fogta meg az Isten lábát", amikor az IBM bekapcsolódott a mikroszámítógép üzletbe. Az IBM, hogy végleg le ne késsen az üzletről, lemondott a saját fejlesztésű alkatrészek alkalmazásáról, ami korábbi stílusától teljesen szokatlan volt. Az ügy nyertese az INTEL 16 bites, komplex utasításkészletű (CISC) mikroprocesszor családja lett. Ugyanakkor az IBM úgy látszik ezzel a húzással igyekezett gátolni a mikrók terjedését a 32 bites kategória irányába. Volt is féltenivalója a 32 bites IBM 3x minigépes kategóriájú gépcsalád miatt! A mai helyzet ismeretében ez a stratégia bevált. Az azonban nem vált be az IBMnek, hogy létrejött egy hatalmas hasonmás piac, amely az eredeti IBM gépeknél sokszorosan hatékonyabb, és ráadásul sokkal olcsóbb gépeket kezdett produkálni. Az INTEL mikroprocesszor család természetesen ebből is hasznot húzott. Addig is meg tudta vetni lábát a sokkal korszerűbb 32 bites mikroprocesszorokkal szemben, amíg létre nem hozta a családon belül a 32 bites családtagot, a 80386-os formájában. E mikroprocesszor család alapján ma mintegy tízmillió gép működik a világon (1989!). Az INTEL 8086-os volt a család kiinduló eleme. Ez a korábbi 8 bites INTEL processzorok vonalát folytatta a 16 bites tartományban. A processzor állapotát a regiszterkészlet és a programszámláló tartalma határozza meg. Megszakításkor a processzor automatikusan verembe menti a programszámlálót és a szegmensregisztert. Minthogy a 16 bites címbusz csak 64 Kbájt címzésére alkalmas, a 64 Kbájtnál nagyobb címek képzésére szegmentált társzervezést és nagyszámú címzési módot alkalmaznak. A 8086-os társzervezésében igen egyszerű "trükköt" találtak ki. Szegmenscímként csak 16-tal osztható címeket engednek meg. Az ilyen bináris címek utolsó négy bitje mindig nulla. Ezeket tehát fölösleges tárolni. Így a 16 bites szegmensregiszterekben tulajdonképpen 16+4=20 bites címeket tudunk tárolni, ha a társzervezőre rábízzuk, hogy a címet egészítse ki a végén négy nulla bittel. Kettőnek a huszadik hatványát kiszámítva belátható, hogy így maximálisan egy megabájtot lehet megcímezni. A PC korszak azonban nem több mint két év alatt kinőtte ezt az akkor meglehetősen nagynak számító címtartományt. Az INTEL sem volt rest, és a 80286-ban bedobta a fentebb tárgyalt trükk "meredekebb" változatát. Ha csak 256-tal osztható szegmenscímeket engedünk meg, akkor a 16 bites szegmensregiszterek egyenesen 24 bites, tehát 16 megabájtos címtartomány megcímzését teszik lehetővé. Minthogy előre látható volt, hogy a PC-k ezt a címtartományt is ki fogják nőni, az INTEL virtuális lapozást is beépített ebbe a mikroprocesszorba. A 32 bites architektúrájú 80386-os modell 32 bites címbusza 4 Gbájt címzését is lehetővé tenné minden nyakatekert trükk nélkül. Mégis, a felhasználók tárcímek iránti elborzasztóan növekvő igénye arra sarkallta az INTEL-t, hogy még ebbe a modellbe is beépítsen társzervezőt, ami -- mai szemmel nézve értelmetlenül nagy, --
64 terabájt nagyságú virtuális tárcímek kezelésére is lehetőséget nyújt. A 80286/80386-os processzorokat az INTEL úgy tervezte meg, hogy tudják a 8086-os processzor működését szimulálni, de annál jóval gyorsabban. A 80286-os bonyolultabb, virtuális lapozást tartalmazó címzési rendszere mellett azonban már tarthatatlan volt az az állapot, hogy az INTEL 8086 -- a korábbi 8 bites modellek vonalából eredően -- hardver úton nem támogatta a védelmi rendszer megvalósítását. A virtuális címkezelés mindenképpen szigorúan operációs rendszeri hatáskörbe vonandó tevékenység, amelyet a többi program elől el kell zárni. Ez csak privilegizált üzemmódok bevezetésével lehetséges. A 80286/80386-os INTEL családtagoknak vannak privilegizált üzemmódjaik. Ezekbe a processzorokba külön processzorállapot-regiszter (PSW = Processzor Status Word) került, amelynek két bitje határozza meg a privilégium szintjét. A két bit négy állapotot jelent, így az INTEL terminológia szerint a privilégiumok négy gyűrűt (angolul: ring) alkotnak. A legtöbb jogot biztosítja a nullás (0) állapot, majd az 1-es, 2-es fokozatosan kevesebbet, és a 3-as jelenti a normál állapotot. Az alkalmazói programok csak normál állapotban futhatnak, míg az operációs rendszer három alrétege használhatja az igazán privilegizált processzorállapotokat. Mint később látni fogjuk, ezt az OS/2 operációs rendszer kidolgozásakor tökéletesen ki is használták. Az eredeti 8086-os mikroprocesszor a tár első 1 kilobájtnyi területét megszakítási vektorcímek tárolására használja. Minden vektor két 16 bites címet (tehát összesen négy bájtot) tartalmaz. Az egyik cím egy szegmenscím, a másik egy szegmensen belüli ofszet. Megszakításkor a processzor félreteszi a verembe a 16 bites programszámlálót (ofszet), és a CS (Code Segment) programszegmens regisztert, majd a megszakítási vektorcímről betölti a programszámlálóba az ofszetet, a CS-regiszterbe pedig a szegmenscímet. Utána végrehajtja az e címen található utasítást, aminek feltétlenül megszakítás-letiltó utasításnak kell lennie, mert a hardver magától nem tiltja meg a megszakítást. A további kódban kell felismerni a megszakítás okát és feldolgozni a megszakítást. A megszakítást programozottan kezdeményezhetjük az INT utasításokkal. Az INTEL 8086-ra alapozott PC-k ezt intenzíven használják operációs rendszeri funkciók hívására. A fejlettebb családtagok privilegizált üzemmódja megakadályozza az INT utasítás említett használatát, de egyben sokkal tisztességesebb szolgáltatás hívási algoritmusok kialakítását teszik lehetővé. A privilégiumok megsértése és speciális hibás szituációk (hiányzó virtuális lap) miatt fellépő megszakítások feldolgozásával, és az ún. kapukon át történő közlekedéssel lehet a fejlettebb családtagok alapján jó védelmekkel felruházott hardver-szoftver rendszert létrehozni. Említettük, hogy a család mikroprocesszorainak komplex utasításkészlete van. E processzorok azonban még társprocesszorokkal (koprocesszorokkal) való együttműködésre is alkalmasak. Ilyen az aritmetikai koprocesszor, amely az aritmetikai műveletek gyorsítását teszi lehetővé, de más, pl. sejtprocesszoros gyorsítók szolgáltatásainak igénybevételére is "idomíthatók". Ez a lehetőség az utasításkészlet további alapos kibővítésére ad módot. Utánozhatók például az IBM 370-es processzorok utasításai, ami PC-ken nagygépi programok futását teszi lehetővé stb.
Kis kiegészítés 2000-ből (ZSP): Az Intel 386-os architektúra lényegében azóta sem változott koncepciójában, hiába jöttek gyorsabb változatok (486, Pentium-XXX stb.). Ami a fenti leírásból kicsit hiányzik, az a 386-os architektúra speciális üzemállapota, a VM86 virtuális gép üzemmód. Ez teszi lehetővé, hogy a régebbi, a Microsoft-nál 16-bitesként emlegetett, de ennél fontosabb, hogy kifejezetten egyfelhasználós koncepcióval készült programokat a mai multiprogramozható operációs rendszerek felügyelete alatt "karanténba" zárhassuk, hogy hibás működésük ne döglessze le az egész operációs rendszert. Ez a DOS-ablak a Windows rendszerekben, a DOS-compatibility box az OS/2-esben, és a DOS-emulátor a UNIX/LINUX-jellegű PC-s operációs rendszerekben.
Kiegészítés 2001-ből (ZSP): A hardverek egyre több, hajdan szuper-számítógépes architektúrákban megszokott allűrt vesznek föl, még asztali és hordozható kategóriában is. Ezek közül a harmadik évezredben döntő jelentőségű váltás a 64-bites aritmetika tömeges elterjedése amiatt, hogy az alkalmazásoknak hatalmas adattömegekkel kell megbirkózniuk (a 64 bit tehát az adatkezelés miatt vált fontossá, nem az aritmetikai pontossági igények növekedése folytán, persze, azokhoz sem rossz, ha már van!). A további fontos fejlődési tünet a hibatűrő, sőt, katasztófatűrő hardver-szoftver rendszerek elterjedése, egészen az asztali gépekig (RAID). Szintén fontossá vált a világméretű hálózatok futótűzszerű terjedésével a védelmi rendszerek javítása, amelyeket korábban csak a hadiiparban véltek igazán fontosnak. A számítástechnika belépése a tömegpiacra olyan negatív jelenségekkel is párosult, mint a számítógépes kriminalisztika (rosszindulatú programok: férgek, vírusok; rosszindulatú "szakértők": crackerek, bitbetörők stb.), amire csak a centrálisan működő operációs rendszerek adhatnak kellő választ, intenzív hardver támogatásokkal. A hatalmas adattömegek biztonságos kezelése automatizált mentő-felügyelő, és az adatelérésekhez igazodó sebességű hierarchikus tároló-visszakereső rendszereket igényel. A nagy megbízhatóságú eszközök érdekes módon felvetik az üzemeltetési feladatok kiadását olyan cégeknek, akik az üzemeltetést távvezérelten tudják professzionális szinten megoldani, mert náluk már elegendő tapasztalat tud összegyűlni, és a magas képzési költségeket is le tudják nyelni (a szolgáltatási díj rovására), amit kis cégek már képtelenek megoldani (de ez fölösleges is, csak szakember pocsékolás volna!).
1.6. Gyakorlatok 1.6.1.
Soroljuk fel az operációs rendszer legfontosabb célkitűzéseit!
1.6.2.
Milyen operációs rendszert kell tervezni ahhoz, hogy a magas szintű nyelveken programozóknak ne kelljen bináris (vagy hexa) tártartalmat elemezni a programbelövés során?
1.6.3.
Mikor jó egy fejlesztői környezet?
1.6.4.
Mi az összefüggés a megszakítási rendszer és a védelmi mechanizmus között?
1.6.6.
Mikor célszerű indirekt címzést használni?
1.6.7.
Mit nevezünk privilegizált utasításnak?
1.6.8.
Milyen problémát okozhatna, ha az alsó szintű B/K-t nem privilegizált utasítások valósítanák meg?
1.6.9.
Mi a megszakítás és miért van rá szükség a számítógépes rendszerekben?
1.6.10.
Hogyan védekezhet az operációs rendszer egy felhasználói program végtelen ciklusa ellen?
1.6.11.
Sorolja fel a ma használatos operatív tárak leggyakoribb típusait!
1.6.12.
Mi a különbség a ROM és a RAM működése között?
1.6.13.
Mi a különbség a ROM és a RAM alapvető alkalmazási területe között?
1.6.14.
Mi a gyorstár szerepe a számítógépes rendszerben, és mit jelent a lokalitás elve?
1. Milyen közös tulajdonsággal rendelkezik a nyomtató, a billentyűzet és a képernyő?
OS02V12.RTF,2KI.4.16.
2. AZ OPERÁCIÓS RENDSZEREK FUNKCIÓI
Az operációs rendszerek funkcióit (szolgáltatásait) a szakirodalom nem egységesen definiálja. Eleve megkülönböztethetünk azonban alacsony- és magas szintű funkciókat. Az alacsony szintű funkciók szolgáltatásait a programokból úgynevezett rendszerhívások segítségével vehetjük igénybe, míg a magas szintűeket vezérlőnyelvekkel és segédprogramokkal (rendszerközeli szoftverelemekkel) érhetjük el. A funkciókat osztályozhatjuk az alábbiak szerint: * primitívek: elemi,- atomi,- tovább nem bontható funkciók; * összetettek: több primitív funkcióra épülő bonyolultabb funkciók; * fő funkciók: relatíve önálló egységet képező, együttműködő funkciók összessége. Az operációs rendszeri funkciókat természetesen programok valósítják meg. Az operációs rendszerekben önkényesen az alábbi három fő funkció jelölhető ki: * rendszeradminisztráció, * programfejlesztési támogatás és * alkalmazói támogatás. A programfejlesztési támogatás és az alkalmazói támogatás a rendszeradminisztrációs funkciókra épül, ezért a vonatkozó rétegszerkezetet a 2.1. ábra mutatja. +---------------------------+---------------------------+ | Programfejlesztési │ Alkalmazói | | támogatás │ támogatás | +---------------------------+---------------------------+ | | | Rendszeradminisztráció | | | +-------------------------------------------------------+ 2.1. ábra. Az operációsrendszeri szoftver rétegződése
2.1. Rendszeradminisztráció Rendszeradminisztrációnak nevezzük magának az operációs rendszernek a működtetésével kapcsolatos funkciókat. Ezek közvetlenül semmire sem használhatók, csak a hardverlehetőségek kibővítését célozzák, illetve a hardver kezelését teszik kényelmesebbé.
A rendszeradminisztráción belül a következő összetett funkciókat jelölhetjük ki: * processzorütemezés: a CPU-idő szétosztása a rendszer- és a felhasználói feladatok (taszkok, folyamatok) között; * megszakításkezelés: a hardver-szoftver megszakításkérések elemzése, állapotmentés, a kezelőprogram hívása; * szinkronizálás: az események és az erőforrásigények várakozási sorokba állítása; * folyamatvezérlés: a programok indítása és a programok közötti kapcsolatok szervezése; * tárkezelés: a főtár, -- mint kiemelten kezelt erőforrás, -- elosztása; * perifériakezelés: a bemeneti/kimeneti (B/K ill. I/O) igények sorba állítása és kielégítése; * adatkezelés: az adatállományokon végzett műveletek segítése (létrehozás, nyitás, zárás, írás, olvasás stb.); * működés-nyilvántartás: a hardver hibastatisztika vezetése és a számlaadatok feljegyzése; * operátori interfész: a kapcsolattartás az üzemeltetővel. A konkrét operációs rendszerek a funkciókat másképpen oszthatják fel. Így például az IBM OS operációs rendszerek változataiban négy fő funkciót szoktak megkülönböztetni: a munkakezelést, a taszkkezelést, az adatkezelést és a rendszerstatisztikát. Az IBM OS munkakezelése tulajdonképpen a mi felosztásunk szerinti alkalmazói támogatáshoz tartozik. A taszkkezelés körülbelül a mi felosztásunk szerinti rendszeradminisztráció folyamatvezérlési funkcióját fedi le, bár a háttérben feltételezi a processzorütemezést, a megszakításkezelést, a szinkronizálást és a tárkezelést. Az OS adatkezelési funkciója sem pontos megfelelője a mi felosztásunkban szereplőnek, mert tartalmazza a perifériakezelést is (fizikai szintű I/O kezelést). A rendszerstatisztika egyrészt a hardverkarbantartást segíti, másrészt a számítóközpont ügyvitelét támogatja (számlázás a felhasznált erőforrások alapján). Mi a hardverkarbantartás igényeivel itt nem foglalkozunk. A felhasználóbarát operációs rendszerek (CP/M, PC/MS--DOS, UNIX stb.) használatakor alig kell foglalkozni a funkcionális felosztás részleteivel. Ezeket az operációs rendszereket a boltból készen veszik, és nagyon kevés felhasználó kísérletezik a rendszer módosításával. Továbbá módosítás esetén a rendszer nem lenne kompatibilis a piacon készen kapható programokkal, ami a hétköznapi alkalmazók számára nem kívánatos. Az operációs rendszerek tervezésekor az elemi funkciók kijelölése bonyolult feladat. Függ a hardver erőforrásoktól és az alkalmazói igényektől. Némely feladatra (például szerszámgépvezérlés, folyamatvezérlés) rendkívül egyszerű funkciókból felépülő "operációs rendszer" is elegendő. Az esetek túlnyomó többségében azonban ez nem így van. Mindenesetre a bonyolultabb funkciók működése mindig az elemi funkciókra épül, ezért a bonyolultabb funkciókat magasabb hierarchiaszinten tételezzük fel. Az elemi funkciókat és a hierarchiaszinteket úgy kell meghatározni, hogy a kialakuló rendszer minél kevesebb ismétlődést tartalmazzon, és minél rugalmasabban tudjon alkalmazkodni a felmerülő igényekhez. Az elemi és összetett funkcióknál egyaránt fontos kérdés, hogy mely funkciók kerüljenek egymás melletti hierarchiaszintre, és melyek legyenek különböző hierarchiaszinten. A rendszeradminisztrációs funkciókat a rendszermag valósítja meg, amelynek a szolgáltatásait a már említett rendszerhívásokkal érhetjük el. Erről részletesen később, főként a 6. és 7. fejezetben lesz szó.
2.2. Programfejlesztési támogatás Ahhoz, hogy egy számítógépet használni lehessen, előbb programokat kell hozzá készíteni. Az operációs rendszerek egyik speciális feladata ennek a programfejlesztésnek a támogatása.
A programfejlesztési támogatás funkciói azonban csak kis részben tartoznak a szűkebb értelemben vett operációs rendszer funkciói közé. Oda soroljuk viszont a rendszerhívásokat, amelyekkel a rendszeradminisztrációs szolgáltatásokat igénybe tudjuk venni. A programfejlesztést leginkább a számítógépes rendszer nyelvi szintje támogatja (szövegszerkesztők, programnyelvi eszközök). A továbbiakban nem a funkcionális felosztás részleteiből, hanem magának a programozási tevékenységnek az elemzéséből indulunk ki, a végén pedig összefoglaljuk a talált funkciókat. 2.2.1. A programozási munka részfeladatai A következő részfeladatok merülnek fel: 1) a probléma elemzése (adatszerkezetek, algoritmusok), 2) esetleg az algoritmus felbontása több részprogramra, 3) a (rész)program(ok) megírása alkalmas programnyelven, 4) a (rész)program(ok) belövése (modulteszt), 5) a részprogramok összeépítése (integrálás), 6) átadás üzemeltetésre. 2.2.2. Támogatások a problémaelemzéshez A problémaelemzéshez az operációs rendszerek általában nem nyújtanak külön támogatást. A korai rendszerekben nem is voltak ilyen eszközök. A későbbiekben megjelentek a problémadefiniáló nyelveket értő fordítóprogramok, továbbá adatdefiniáló és adatmanipuláló nyelvekkel igyekeztek segíteni az adatbázis--technikában használatos adatelemzést. Ezeket később az ún. integrált programfejlesztő rendszerek speciális problémadefiniáló eszközei és programgenerátorai követték. A problémaelemzés fázisában először a feladat nyers vázlatát (informális specifikációját) adják meg, amelyet követ az ennél jóval precízebb formális specifikáció. Ez az integrált programfejlesztő rendszerekben adatbázisba kerül. A formális specifikációt még egyszer ellenőrzik, hogy kielégít-e minden megrendelői igényt. A véglegesített formális specifikáció alapján kezdődhet az implementálás. Eközben kiválasztják a megfelelő szoftvertechnológiát (Jackson, Warnier, heurisztikus stb.), valamint a (rész)feladat(ok)hoz legjobban illeszkedő programozási nyelvet, majd megindulhat a programtervezés és a programozás (részei: a programírás, a belövés, a rendszerpróba és az átadás). 2.2.3. A programírás támogatása Említettük a részprogramokat. Az algoritmusok részprogramokra bontásával (a módszer neve: moduláris programozás) kisebb programokat kell belőni. Bonyolultabb feladatokat pedig rendszerint nem is lehet egyetlen programmal megoldani, ezért ezek megírását több programozó együttműködésével, ún. team(illetve csoport-)munkában végzik. A részekre bontásból további előny származik, ha észrevesszük, hogy a részfeladatok többször felhasználható programjaiból programkönyvtárakat hozhatunk létre. A későbbi feladatokban már e könyvtárakra támaszkodhatunk, mert belőlük a szükséges elemek átvehetők az új program(ok)ba. Ezzel programozói kapacitásigényt takaríthatunk meg, ami a szoftverkrízisként emlegetett veszély elhárításában jelentős szerepet játszhat. (A szoftverkrízis: az igényelt új és módosítandó programok száma rohamosabban nő, mint a programozói kapacitás!) A programok írására olyan programozási nyelveket használnak, melyeket a nyelvi szint már említett programnyelvi eszközei, a fordítóprogramok és az interpreterek értelmezni tudnak. (Ezek közül a feladat megoldásához legjobban illeszkedőt kell kiválasztani.) A fordítóprogram megérti az adott programozási nyelven írt programot, és ha hibátlan, lefordítja
olyan kódra (úgynevezett gépi kódra), amelyet a hardver értelmezni tud. A korai számítógépeken az így előkészített programmal már meg lehetett oldani a feladatokat. Az interpreter soronként értelmezi az adott programnyelven írt kódot -- többnyire -- anélkül, hogy gépi kódra fordítaná. Ezért ha interpretert használunk, a forrásnyelvű program azonnal használható feladatok megoldására. A fordítóprogramokat és az interpretereket nem tekintjük a szűkebb értelemben vett operációs rendszer részének. Persze a személyi számítógépek interpreter típusú BASIC rendszere egyben az adott gép operációs rendszere is. Benne integrálódnak a nyelvi funkciók és -- az egyszerűbb hardver és a kisebb igényű alkalmazás miatt szűk körű -- operációsrendszeri funkciók. A moduláris programozás és a programkönyvtárak használata létrehozott két speciális programot: * az ún. programszerkesztőt, amely programok modulokból való összeállítását végzi, és * a betöltőprogramot, amely a programokat közvetlenül a futáshoz készíti elő. Létrejöttüket az alábbiakban igyekszünk megindokolni. Vizsgáljuk meg először a programkönyvtárakat, amelyeket több szinten is használhatunk. A legalacsonyabb szint a forrásnyelvű könyvtárak alkalmazása, amikor a programok forráskódját (vagy annak egy részét) valamilyen módon könyvtárakból nyerjük. Egyes fordítóprogramok beépített forráskód-generálási lehetőségeket tartalmaznak (ezt preprocesszor- vagy makrotechnikának nevezik). A forráskönyvtárak használatát támogatják a programírásra használt szövegszerkesztő programok is, amelyekkel a szükséges könyvtári programrészek bemásolhatók programunkba. A fordítóprogramok eleinte a gépbe közvetlenül betölthető, komplett gépi kódú programokat generáltak (ezekben mind az utasításkódok, mind az operanduscímek véglegesek voltak). Később a fordítókat megtanították arra, hogy a forrásprogramot ne fordítsák le azonnal tiszta gépi kódra, hanem félig fordított kódot (a forráskódból kiindulva úgynevezett célkódot, más néven tárgykódot, angolosan object-kódot) állítsanak elő (amelyben a hardver utasítások gépi kódja szintén végleges, de a címek átcímezhetők maradnak). Ezáltal kevesebb kódot kell a fordítóval generáltatni, mert a programhoz a félig fordított programrészek tárolására használt tárgyprogram-könyvtárból hozzá lehet másoltatni a program működéséhez szükséges kész, további modulokat (az első ilyen modulok a perifériakezelő szubrutinok voltak). A tárgyprogram-könyvtárban tárolt, tárgykódú, lefordított modulok jóval kisebb helyet igényelnek, mint a forrás-szövegek, ami újabb előny. Eleinte ezek a tárgyprogram-könyvtárak egy-egy fordítóprogramhoz kapcsolódtak, és a fordítóprogram maga vette elő a szükséges modulokat. Hamarosan rájöttek arra is, hogy a programkönyvtári programok (szubrutinok) belső formátumát uniformizálni kell, mert akkor egy program különböző moduljait a részfeladathoz legjobban illő programnyelven lehet megírni. A különböző nyelveken írt modulok lefordítása után keletkező tárgymodulok az azonos formátum miatt egyetlen monolit programmá fűzhetők össze. Az összeállításhoz új program kellett: a programszerkesztő, amelyet az angol linkage editor elnevezés alapján kapcsolatszerkesztőnek is hívnak -- a szövegszerkesztőktől megkülönböztetendő. Ez az egyes programmodulokat (fő- és alprogramokat, szubrutinokat) egyetlen (vagy néhány) végrehajtható programmá fűzi össze. A korai rendszerekben ezt a végrehajtható modult végcímzett programnak is hívták, mert a program a végrehajtásakor a főtárnak pontosan arra a helyére került, amit a szerkesztő kijelölt neki. Ezen a multiprogramozás kialakulása után változtatni kellett, mert ott az a célszerű, ha a programok a főtár bármely helyén működőképessé tehetők. Ezért a mai programszerkesztők nem készítenek végcímzett programokat, hanem a végrehajtható programban megtartják a tárgymodulokban található, átcímzéshez szükséges (relokációs) adatokat. Az összeszerkesztett programok futás előtti átcímzéséhez pedig egy újabb program kellett: az ún. betöltőprogram. Ez teszi lehetővé, hogy a végrehajtandó program a kijelölt tárhelyen működőképes legyen. Ezt nevezzük dinamikus áthelyezésnek.
A programszerkesztőnek, a betöltőprogramnak és a tárkezelőnek nyilvánvalóan egyeztetett formátummal kell dolgoznia. Ezért, bár ezek a programok eredendően a nyelvi szinthez csatlakoznak, központi szerepük miatt a szűkebb értelemben vett operációs rendszer részének tekintik őket, tehát operációsrendszeri funkciók. A betöltő olykor ténylegesen az operációs rendszer magjában helyezkedik el (kézenfekvő módon a tárkezelés részeként). Itt kapcsolódnak a témához a rendszerhívások vagy más néven rendszerszubrutinok. A programozás során legsűrűbben használt funkciók programját nyilván érdemes állandóan a tárban tartani, és szubrutinként használni. A perifériák kezelése már a korai időkben is olyan bonyolult volt, hogy meghajtóikat eleve szubrutinként használták a programozók. Később az operációs rendszerek -- védelmi okokból -- ki is vették a programozók kezéből a perifériák közvetlen kezelésének a jogát. Mindezek miatt az operációs rendszerbe épült sok hasznos, vagy a védelmi rendszer miatt másképp megoldhatatlan funkció kódja, amelyek szolgáltatásait a már emlegetett rendszerhívások segítségével vehetjük igénybe. Mivel a tárvédelem az operációs rendszer szubrutinjainak normális behívását megakadályozná, speciális módszert kell használni a rendszerfunkciók hívására. A behívást rendszerint a hardver erre specializált utasítására, a szoftvermegszakításra alapozzák, ha egyáltalán van ilyen utasítása a hardvernek (az INTEL 8080-nak például nincs, ezért a CP/M-ben trükkökhöz kell folyamodni: szubrutinugrás az 5-ös címre). A paramétereket regisztereken vagy veremtárokon át adják át a hívott funkció szubrutinjának, majd az eredmények ugyanilyen módon jutnak vissza a hívóhoz. Tipikus szoftvermegszakító utasítások: SVC (IBM 360/370 és a velük kompatibilis gépek: ESZR, SIEMENS, ICL, HITACHI stb.), TRAPS (PDP 11, MSZR), INT (INTEL 8086 család). Ezeket általában nem közvetlenül használják, hanem valamilyen makrohívás keretében. A makró neve ilyenkor jellemző lehet az elvégzendő funkcióra (például TIME, WAIT, GETMAIN, MESSAGE stb.), és a makrokifejtés szervezi meg a makrohívás paraméterlistáján felsorolt változók átadását, majd a kívánt kódú operációs-rendszeri funkció behívását a szoftvermegszakító utasítással. A legalacsonyabb szintű funkciók első sorban ASSEMBLY nyelven állnak rendelkezésre, de az utóbbi időben terjednek az olyan lehetőségek, hogy magas szintű nyelvek is el tudják érni az alacsony szintű funkciókat. Tipikus eset a C rendszerprogramozási nyelv, amely a UNIX kapcsán fejlődött ebbe az irányba. A UNIX kernel szolgáltatásait alapvetően C függvények formájában szokták megadni, bár párhuzamosan ASSEMBLY szintű definíciók is használatosak. Ma már nem megy csodaszámba például, hogy a TURBO PASCAL-ból elérhetjük az MS--DOS funkciókat. Egyszerű funkcióhívási példát mutat a 2.2. ábra (IBM PC). Program Operációs rendszer +-----------+ +------------+ | | | Szoftver >>>4*nn>>>> Ugrótábla | | v | megszakítás > | | | | INT nn >>>>>>>>>>>>>>>> | | | |...........| | | | | Folytatás <<<<<<<<<<<<<<<< |.....v......| | | | < | INTnn rutin| | v | <<<<<<<<<<< IRET | | | |............| +-----------+ +------------+ 2.2. ábra. Szoftvermegszakítás Programkönyvtárak végrehajtható programmodulokból is készíthetők. Ezeket bináris könyvtáraknak nevezik, és szintén nem tartják őket a szűkebb értelemben vett operációs rendszer
részének, jóllehet olykor a rendszermagot, és az operációs rendszer más részeit is bináris programkönyvtárakban tárolják (UNIX, MS--DOS stb.). Az operációs rendszerek funkcióit megvalósító rendszermag (kernel, supervisor, monitor stb.) legnagyobb része mindig a tárban található (rezidens rész), köré azonban igen sok program csatlakozik a működés folyamán. Ezek időlegesen vesznek részt a munkában, emiatt tranziens (átmeneti) programoknak hívják őket. Az ilyen tranziens programokat szükség esetén a rendszermag a tranziens programkönyvtárból hívja be, amely szintén bináris programokat tartalmaz. A műveletek gyorsítására egyes tranziens programokat állandóan a főtárban tartunk az úgynevezett rezidens területen. A rezidens területen található programok esetében egy különleges operációsrendszeri támogatást, a kódmegosztás lehetőségét kell megemlíteni. Ennek lényege, hogy multiprogramozott környezetben egyes kódokat egyidejűleg több feladat (folyamat) is használhat. Amikor az egyik feladat munkája valamely okból a hívott kód közepén megszakad, az operációs rendszer a kód használatát más feladatnak is kiadja úgy, hogy egyrészt nem várja ki, amíg az előző feladat végigfut a kódon, másrészt külön munkaterület biztosításával újraindítja a hívott kódot. Ez megköveteli olyan kódok írását, amelyek bármikor újraindíthatók, aminek konkrét feltétele az, hogy a kódok önmagukat ne módosítsák működés közben, tehát minden állapotinformációt munkaterületen kezeljenek. Az operációs rendszerrel közölni kell, hogy a kód újraindítható vagy sem. Az újraindítható kódokat az operációs rendszer csak egyetlen példányban tartja a főtárban, akkor is, ha azt többen használják. Ez jelentős tármegtakarítást eredményezhet. Vannak olyan operációs rendszerek, melyekben a magas szintű nyelvek fordítói újraindítható kódokat generálnak (pl.: UNIX). A multiprogramozható operációs rendszerek elemi funkcióit megvalósító programok igen nagy százalékban (mondhatni szükségképpen) újraindíthatók (megoszthatók). A UNIX operációs rendszer olyan új elvet valósított meg, amely a moduláris programozást végrehajtási szinten -- ún. bináris programkönyvtárakkal -- támogatja. A UNIX-ban is van programszerkesztő és betöltőprogram (operációsrendszeri funkcióként), de az összeszerkesztett, végrehajtható programokat a parancsnyelv segítségével összefűzhetjük egy adott feladat megoldására, és az egyes bináris programok önállóan oldják meg a részfeladatokat. Ezért egy probléma megoldásához nem kell őket nagy méretű monolit programmá összefűzni. A UNIX itt említett végrehajtható (bináris) könyvtárait inkább az alkalmazói támogatás segédprogramjaihoz sorolhatnánk. Mindenesetre a UNIX alapelve a sok egyszerű, hasznos kis segédprogram alkalmazása, amelyek univerzálisan felhasználhatók, és kombinációjukkal számtalan bonyolult feladat megoldható. A kis modulok belövése után elmarad a monolit programoknál szokásos integrációs teszt, ami a rendszerek gyors megvalósításához jelentős segítség. A tárigények is csökkennek, ami multiprogramozott környezetben szintén előnyökkel jár. A programkönyvtárak a nyelvi szinten helyezkednek el, de kezelésükhöz a legtöbb operációs rendszer speciális könyvtárkezelési funkciókat biztosít (az adatkezelési funkció részeként). 2.2.4. Támogatás a programok belövéséhez A programozói munka legszorgosabb része a programbelövés. Ezért ehhez a munkához a programozó szeretne minél több támogatást kapni. A programbelövést az operációs rendszerek és a programozási nyelvek a nyomkövetési (angolul debug, trace) funkciókkal támogathatják. Nyomkövetés több szinten végezhető. A legkézenfekvőbb megoldást már korán megtalálták: a programba -- az algoritmushoz funkcionálisan hozzá nem tartozó -- speciális kimeneti ("tesztprint") utasításokat, úgynevezett nyomkövető utasításokat lehet beépíteni az adott programnyelv szabályai szerint. Sajnos, mint minden kódot, a nyomkövető utasításokat is be kell lőni, ami néha a hibás adatmező-tartalmak miatt nem túl könnyű, elég sok vesződséggel jár. További bonyodalmak adódhatnak akkor, amikor a végleges programból ki kell hagyni ezeket a kimeneti formátumot rendszerint igen erősen zavaró utasításokat. A nyomkövetés kihagyása újabb belövési igényt
támaszt. A nyomkövető utasítások mellékhatása ugyanis ideiglenesen kiküszöbölheti a program algoritmushibáit, ezért a korábbi hiba a nyomkövetés eltávolítása után ismét előjöhet. A nyomkövető utasításokkal majdnem minden belövési probléma megoldható, de olykor csak igen fáradságosan. A nyomkövető utasítások nyelvi szintű eszközök. Már a korai időkben rendelkezésre állt egy másik módszer: hibás futás esetén az operációs rendszer tárkivonatot (vagy az elterjedt angol kifejezéssel dumpot) készít, ami nem más, mint az operatív tárban található programok és adatok tárcellánként számokkal kódolt, formázott listája. További lehetőségként a programozó is kezdeményezhette a tárkivonatok készítését. A korai rendszerekben ezért kiterjedten alkalmazták a belövéshez a dumpelemzést. Ehhez azonban a belső tárolási formátumok, és az operációs rendszer működési részleteinek alapos ismeretére volt szükség. E módszerrel tulajdonképpen minden hibát el lehet hárítani, de igen nagy szellemi erőfeszítéssel. Az operációs rendszerek bonyolultságának növekedtével ez a módszer egyre jobban kiszorul a belövési technikából, s alkalmazásának csak az amúgy is ismeretigényes alapszoftver-munkák esetében van még néha értelme. A tárkivonat készítése operációsrendszeri funkció, mert alkalmazói szintről az operációs rendszer védelmi rendszerén át csak így lehet hozzáférni a keresett információkhoz. A legkorszerűbb nyomkövetési technika nem tesz további terheket a programozó vállára, hanem a meglevőket is igyekszik levenni. A nyomkövetési eszközöket két nagy csoportba sorolhatjuk: hardver- és szoftver nyomkövetési támogatások. A hardver nyomkövetési támogatás azon alapul, hogy a hardver speciális utasítás(ok) végrehajtása esetén megszakítja a program futását, és ebben a pillanatban elemezhető a program állapota. Ezt a támogatást főként a korábbi dumpelemzés helyettesítésére lehet használni, ezért ugyanolyan mély ismereteket igényel, mint a dumpfejtés, így fő alkalmazási területe az alapszoftver-gyártás. Ezt a funkciót az operációs rendszer speciális megszakítás-kezelő alrendszerrel szokta támogatni, de a lebonyolításhoz magasabb szinten működő monitor, debugger programra is szükség van. A szoftver nyomkövetési támogatás nyelvi szinten áll rendelkezésre. Az interpreterrel értelmezett nyelvek például eleve tartalmaznak beépített nyomkövetési alrendszert. Az interpretereknél a nyomkövetési igényt egy nyelvi utasításpárral lehet be és kikapcsolni. A legelterjedtebb a programlogika működésének ellenőrzésére alkalmas TRACE ON/OFF parancspár, amely a feltételes és feltétlen programelágazások követését teszi lehetővé. Ebből már lehet következtetni egyes programváltozók (vezérlőváltozók) értékének alakulására. Bonyolultabb lehetőség a szimbolikus dump: az interpreter a gépkezelő (aki rendszerint maga a programozó) manuális beavatkozásakor (BREAK = megszakítás) vagy programhiba miatti leállás esetén egy parancs hatására kilistázza az összes érvényes változó tartalmát. Ennél is bonyolultabb lehetőség az értékadások nyomkövetése, amelynek bekapcsolásakor az interpreter kilistázza minden olyan programváltozó új értékét, ami értéket kap. Ez olykor-olykor éppen olyan nehezen áttekinthető listát eredményez, mint a régi dumpok. Ilyenkor jó, ha az interpreter szelektált értékadási nyomkövetésre is képes, azaz megmondhatjuk neki, hogy éppen mely változók értékeire vagyunk kíváncsiak. A fordítóprogramoknál a helyzet egy kicsit más, mert az eddig említett nyomkövetési technikák legjobban interaktív környezetben érvényesülnek (ezért említettük először az interpreteres lehetőségeket). Persze a fordítóprogramokba is be lehet építeni hasonló automatikus nyomkövetési funkciókat. Ilyenkor az előbb említettekhez képest más lehetőségek is adódnak. Például elég korán bevezették az úgynevezett feltételes kommentárokat. Ezek olyan megjegyzésként kódolt
programutasítások, amelyeket a fordító egy adott opció bekapcsolt állapota esetén a forrásprogram részének tekint, egyébként nem. Így ezekbe a feltételes megjegyzésekbe helyezhetjük el a korábban már említett nyomkövető utasításokat. Miután a nyomkövetés segítségével kijavítunk egy hibát, nem kell mást tenni, mint kikapcsolni a feltételes fordítási opciót, és megszabadulhatunk a nyomkövető kiírások "dzsungelétől". A nyomkövető utasítások benne is maradhatnak a programban, és egy esetleges későbbi hibaelemzésnél újra felhasználhatók. Egyes nyelveknek van mind interpreteres, mind fordítóprogramos támogatása. Ezek egyesítik az interaktív programbelövés előnyét a hatékony programlétrehozás lehetőségeivel. Ez persze csak akkor igaz, ha a fordítóprogram pontosan meg is érti azt, amit az interpreter változat elfogad. Ellenpéldaként említhető az az eset, amely a DOS alatt működő dBASE III adatbázis kezelő rendszerrel történt meg. A dBASE-nek interpreteres programértelmezője van, de egy idegen cég fordítóprogramot (CLIPPER) írt hozzá. Az természetesen bizonyos interaktív parancsokat nem tudott kezelni, ami érthető volna. A rosszabb, hogy javítani is akartak az eredeti dBASE III nyelven. A dBASE III újabb változatába ezek egy része szintén belekerült, de természetesen más jelentéssel. Így a CLIPPER ezeket nyilvánvalóan félreértette. Ilyen inkompatibilitási problémák esetén arra vagyunk utalva, hogy programíráskor csak a két nyelvjárás közös elemeit használjuk, különben le kell mondanunk az interpreteres fejlesztés adta kényelmekről. (A CLIPPER-t később hozzáigazították a dBASE-hez, de mi az esettel csak az interpreter-fordítóprogram inkompatibilitásokra szerettük volna felhívni a figyelmet.) A nyomkövetési technika különleges eszközei a keresztfejlesztő rendszerek, amelyek olyan szoftverek belövését támogatják, amelyek nem a fejlesztőgépen, hanem egy másik -- esetleg még éppen csak kidolgozás alatt álló -- számítógépen fognak futni. Ezek adatátviteli kapcsolatot is igénylő elég bonyolult hardver-szoftver környezetet jelentenek. 2.2.5. A programintegrálás támogatása A programok összeépítése modulokból tartogat még egy olyan munkafázist, amellyel foglalkozni kell. Ez az úgynevezett integrációs teszt. Ennek halovány támogatását jelenti maga a szerkesztőprogram, amely hibajelzést ad, ha valamely modul hiányzik a komplett program összeállításához. A program algoritmushibáinak kiszűrésében, a hivatkozott változókban és adatstruktúrákban felmerülő ütközések kiderítésében azonban nem sokat segít. Az integrációs tesztben rendszerint újra kell kezdeni a nyomkövetést. A problémákon igyekeznek segíteni az integrált programfejlesztő rendszerek, melyek megpróbálják megőrizni az adatok és adatszerkezetek konzisztenciáját. Az algoritmushibák kivédésére programhelyesség bizonyítási (verifikálási) módszereket, programgenerátorokat, és programstruktúra visszafejtő, automatikus programdokumentáló programokat használnak. Ez utóbbiak tulajdonképpen alkalmazói szintű funkciók.
2.2.6. A programfejlesztési támogatás fő funkcióinak összefoglalása A programfejlesztési támogatás fő funkciói tehát a következők: * rendszerhívások: a programokból alacsony szintű operációsrendszeri funkciók aktivizálására, * szövegszerkesztők: a programok és dokumentációk írására, * programnyelvi eszközök: fordítóprogramok és interpreterek a nyelvek fordítására vagy értelmezésére, * szerkesztő- és betöltőprogramok: a programmodulok összefűzésére illetve tárba töltésére (végcímzés), * programkönyvtári funkciók: a különböző programkönyvtárak használatára, és * nyomkövetési rendszer: a programok belövésére. Ezek részben vagy egészben megtalálhatók az integrált programfejlesztő rendszerekben.
2.3. Alkalmazói támogatás Az alkalmazói támogatás funkciói a számítógépes rendszer több szintjén valósulnak meg, és az alábbi fő funkciókra bonthatók: * operátori parancsnyelvi rendszer: a számítógép géptermi üzemvitelének támogatására; * munkavezérlő parancsnyelvi rendszer: a számítógép alkalmazói szintű igénybevételének megfogalmazására; * rendszerszolgáltatások: az operációs rendszer magjával közvetlenül meg nem oldható rendszerfeladatokra; * segédprogramkészlet: rutinfeladatok megoldására; * alkalmazói programkészlet: az alkalmazásfüggő feladatok megoldására. 2.3.1. Az operátori nyelvi rendszerek Az operátori és a munkavezérlő parancsnyelvek elvileg a nyelvi szinthez tartoznak, de fontosságuk és a megvalósításukhoz igényelt, mélyebb szintű operációsrendszeri funkciók (beolvasók, ütemezők) miatt a szűkebb értelemben vett operációs rendszer részének tekintjük őket. A számítógépek történetében kimutatható, hogy az operációs rendszerek az üzemeltetési problémák könnyítésére jöttek létre. A korai számítógépek nagyon lassúak voltak, és kezelésük is igen bonyolult tevékenységet igényelt, ezért többnyire maguk a programozók kezelték a gépet. A gépek sebessége azonban rohamosan nőtt, így hamarosan tarthatatlanná vált, hogy két munka között a (méregdrága) gép hosszabb ideig álljon (például azért, mert a programozó gondolkozott a felmerült hibán). Az állásidők egy része abból adódott, hogy a munkák közötti váltás manuálisan, nem "elektronikus tempóban" ment végbe, más része a felhasználók gyakorlatlanságából és ügyetlenkedéséből származott. Voltak elkerülhetetlen veszteségidők is, mint például a különböző fordítók betöltéséhez szükséges idők, amit azonban jobb munkaszervezéssel ritkítani lehetett. Ebből jutottak arra a következtetésre, hogy szükség van olyan személyzetre, aki kizárólag a gép megtömésén fáradozik, és akinek helyismerete és munkatapasztalata nagyban segíteni tudja a programozók munkáját is. Hamar kiderült, hogy az üzemeltető személyzet munkájából sok mozzanat automatizálható, sőt automatizálandó az emberi tévedések csökkentésére. Az automatizáló programcsomagot nevezték el operációs rendszernek. Maga az elnevezés is az üzemeltetésre utal. Az első operációs rendszerekben tehát központi szerepet játszottak az operátori parancsnyelvek. Később ezekből vált
ki a munkák (kötegek) összeállításának megfogalmazására szolgáló munkavezérlő nyelv, de az interaktív rendszereknél megint visszatérés figyelhető meg egy közös vezérlőnyelvhez. Az operátori parancsnyelv a géptermi, futásideji események vezérlésére szolgál. Kifejezetten a géptermi személyzet munkáját segíti. Részleteiben itt nem foglalkozunk vele, csak megjegyezzük, hogy a programozási nyelvekhez viszonyítva igen primitív, erősen a konkrét hardver--szoftver környezethez illeszkedő stílusa van. A túl korai kialakulás nyomai máig is érződik rajta. Szabványosítása a jelenlegi tényhelyzetben szinte reménytelen. 2.3.2. A munkavezérlő-nyelvi rendszerek A munkavezérlő parancsnyelv (röviden munkavezérlő nyelv, angolul Job Control Language, a továbbiakban: JCL) a számítógépre szánt munkák csomagokba (kötegekbe) gyűjtésére, összeállítására, számítógépes zsargonban job-ok (dzsobok, munkacsomagok, munkák) írására szolgál. A munkacsomagokat tipikusan nem az üzemeltető személyzet írja, bár ez sem kizárt. A munkavezérlő nyelv az alkalmazók és a programozók munkáját segíti. Megjegyzendő, hogy a munkacsomagokba rendszerint operátori parancsokat is be lehet iktatni. A két nyelv tehát keveredik. A munkavezérlő nyelvek, amelyeket vezérlőáram olvasó programok fogadnak, horizontális jellegűek, mert kevés számú, de bonyolultan paraméterezhető parancsokra épülnek. Ezek sem hasonlítanak a programozási nyelvekre, akárcsak az operátori nyelvek. A legtöbb interaktív rendszerben, ahol tipikusan nincsenek munkacsomagok, az operátori és a munkavezérlő nyelv egyetlen parancsnyelvvé olvadt össze. Ezekben is lehet azonban munkacsomagokat összeállítani az úgynevezett parancsállományok alkalmazásával, amelyekben parancsnyelven írt szövegek vannak, és ezek helyettesítik a terminálról kiadható parancsokat. Az interaktív parancsnyelvek, amelyeket parancsértelmező programok fogadnak a terminálokon, vertikális jellegűek, mert szerteágazó, egyébként egyszerű paraméterezésű parancsokra építenek. A parancsnyelvek további jellegzetességei: a programnyelvekre hasonlító szintaxis, algoritmikus jelleg (feltételes végrehajtás, ciklusszervezés, aritmetikai,- logikai,- karakteres műveletvégző képesség, változók és parancsparaméterek kezelése) és erőforráskorlátokat is beállíthatnak (munkaterület mérete, jogkörök, a kezelhető könyvtárak stb.). Újabban tért hódít az ún. grafikus interfész, melyet elsőként az APPLE MACINTOSH valósított meg. Szokták ikonvezérelt felhasználói interfésznek is hívni, mert a grafikus képernyőn megjelenő „ikonokkal” (képecskékkel) igyekszik szimbolizálni az igénybe vehető szolgáltatásokat. (A hardver kapcsán már volt szó róla, de az új hardverelemek -- egér, grafikus képernyő -- jóval kisebb szerepet játszanak benne, mint a szükséges szoftver). A grafikus interfészen át tartott munka során először érezheti igazán a felhasználó, hogy nem olyan barátságtalan számítógéppel van dolga, ami rögtön a kezére üt, ha elgépel valamit, mert a lehető legkevesebb alkalmat adja neki a tévesztésre. Az alkalmazó kifejezetten a problémára koncentrálhat, nem kell folyton számítógépes zsargonban fogalmaznia. Ilyen kapcsolatot az IBM PC-ken a GEM és a WINDOWS tesz lehetővé. Nem véletlen, hogy az OS/2 Presentation Manager-e is ugyanezt fogja tudni. Az AT&T a UNIX PC-n a UNIX SYSTEM V. verziót szintén grafikus interfésszel látta el, de még a kis COMMODORE 64-en is van már ilyen a GEOS formájában. Ezek arra mutatnak, hogy a grafikus interfész megállíthatatlanul terjed. Mégsem kell azt hinni, hogy a vezérlőnyelveknek ezzel bealkonyult. Programfejlesztésnél például könnyebb egyetlen, jól paraméterezett paranccsal áttérni a szükséges üzemmódba. A problémához ingadozó viselkedéssel kihasználhatjuk mindkét interfésztípus előnyeit. 2.3.3. A rendszerszolgáltatási funkciók A rendszerszolgáltatások
alapja
az
a
programkészlet,
amely
az
operációs
rendszer
szolgáltatásainak igénybevételét közvetve teszi lehetővé. Ezek a programok általában nem a rendszermaghoz tartoznak, hanem folyamatokként futó külön programok (beolvasók, nyomtatók, ütemező, iniciátor/terminátor stb.). Az 5. fejezetben erről részletesebben lesz szó. 2.3.4. A segédprogramkészlet A segédprogramkészlet -- amelyet rendszerközeli szoftvernek is neveznek -- nem tartozik a szűkebb értelemben vett operációs rendszerhez és bináris programkönyvtárak útján valósul meg. Segédprogramokkal, egyszerű paraméterezéssel, sok rutinfeladat (állománylétrehozás, másolás, törlés, rendezés stb.) oldható meg. Egyes operációs rendszerekben a segédprogramok döntő szerepet játszanak (UNIX, CP/M, PC/MS--DOS, OS/2 stb.), mert a vezérlőnyelv parancsainak kibővítésére használják. Pontosabban: amit a parancsértelmezője közvetlenül megért, azt belső parancsnak, a program-könyvtárból előveendő parancsokat pedig külső parancsnak szokták nevezni. 2.3.5. Alkalmazói programcsomagok Az alkalmazói programkészlet vagy a hardvergyártótól, vagy független szoftvergyártóktól készen vásárolható programcsomagokból áll, esetleg maga az alkalmazó fejleszti ki őket a saját igényei szerint. Egyes interaktív operációs rendszerekben az alkalmazói programok is beépülnek a vezérlőnyelv (külső) parancskészletébe, ami egységes kezelésmódot biztosít.
2.4. Mintapéldák 2.4.1.
Az IBM 360/370/30XX/43XX és az ESZR--I/II/III sorozat operációs rendszerei
Az IBM cég -- mint már említettük -- a hatvanas évek közepén vezette be 360-as gépcsaládját, melyek modelljei egy -- szoftver szinten erősen, hardver szinten kevésbé -- kompatibilis sorozatot képeztek. Az erős szoftverkompatibilitást egyrészt a sorozat gépeire kidolgozott operációs rendszerek, másrészt szigorúan szabályozott szoftverfejlesztési alapelvek biztosították. Az IBM egy újítás bevezetésekor maximálisan igyekszik figyelembe venni régi felhasználóinak érdekeit. Ez jelentősen kötötte a fejlesztők kezét (amit Amdahl, a sorozat főkonstruktőre nem tudott elviselni, kilépett, új céget alapított -- sikerrel!). E kötelmek azonban a felhasználóknak nagy biztonságot adtak, mert hosszú távon számíthattak arra, hogy programjaikat nem kell minden újabb operációsrendszeri módosítás átvétele után módosítani, sőt esetleg újraírni, mint az a korábbi időkben napirenden volt. Az IBM politikájának megfelelően a későbbi új sorozatok (370/30XX/43XX) gépein ugyanazon operációs rendszerek fejlettebb változatai futnak. Tulajdonképpen sok operációs rendszer készült a 360/370-es sorozatú gépekre, de ezekből csak három típus maradt talpon: a DOS, az OS és a VM/370. Ezeknek viszont rengeteg verziója alakult ki a hardverfejlődés követésére. Az ESZR sorozat és a dugasz-kompatibilis gépeket gyártók (amerikai, japán és európai cégek) gépein szintén az említett operációs rendszerek kompatibilis változatai futnak, így elterjedtségük a nagygépes kategóriában döntő jellegű. Ezért bár a folytonos újítások ellenére eléggé elavultak, megismerésüket fontosnak és tanulságosnak véljük. Különösen azoknak, akik nagygépes rendszerekkel állnak valamilyen kapcsolatban. DOS operációs rendszer A DOS (Disk Operating System = lemezrezidens operációs rendszer) a kis teljesítményű (kevés tárral rendelkező, lassú) gépek tipikus univerzális, kötegelt üzemmódú multiprogramozható operációs rendszere. Rendszeradminisztrációs funkciói statikusak, de a kezelésmódból adódó
egyszerűbb kivitelezés lehetővé teszi, hogy a rendszeradminisztráció kapacitásigénye ne csökkentse túlzottan az amúgy is kis teljesítményű hardver átbocsátóképességét. A későbbi változatok rugalmassága nőtt, és támogatást kaptak új hardverlehetőségek, melyek közül a legjelentősebb a virtuális tár bevezetése volt. Ez a DOS egészen új változatának, a DOS/S-nek a kezdetét jelentette. Több jel arra mutat, hogy az IBM igyekezett volna megszabadulni a DOS-tól, de a lelkes felhasználói tábor nem engedte kihalni. Ha az IBM úgy nyilatkozott, hogy ennek, vagy annak az újdonságnak a támogatását a DOS-ba már nem veszi fel, akkor mindig akadt egy ügyes felhasználó, aki ezt megtette. Az IBM ugyanis az önmaga szabta szabályok szerint köteles támogatni a felhasználókat minden olyan fejlesztés elvégzésében, amit ő nem végezne el, -- a támogatásba beleértve a forráskódok rendelkezésre bocsátását is(!). A DOS forráskódja elég kis méretű volt ahhoz, hogy "ne tudjon ellenállni a buzgó bitfaragók kísérletezéseinek" (én is foglalkoztam vele: Zs.P.). Ez odavezetett, hogy ma nincs a világon két tökéletesen kompatibilis DOS installáció. A DOS operációs rendszer részei mágneslemezen találhatók. Indításához a mágneslemeztár legkisebb fizikai című blokkjában van egy program, amely az indítógomb hatására betöltődik a főtár legalsó részére, majd automatikusan elkezd végrehajtódni. Ez a kezdeti programbetöltő program, amely végrehajtása során a mágneslemezről betölti a főtárba az operációs rendszer magprogramját. Ezt IBM szóhasználattal supervisornak (felügyelőprogramnak) nevezik, és ez szolgáltatja a 2.1.-ben elemzett rendszeradminisztrációs funkciókat. A DOS nyelvi szintjén a következő nyelvek és nyelvi fordítók találhatók: FORTRAN, az IBM legkorábbi szoftver csúcsteljesítménye (ez volt az első magas szintű nyelv, amely bebizonyította a magas szintű nyelvek létjogosultságát -- sokan máig is lelkesednek érte); ALGOL (az első precedens a nemzetközi szabványosításra a számítástechnikában, de az IBM, bár megalkotásában tevékenyen részt vett, nem szerette -- DOS változata nem is IBM eredetű!); COBOL (nyelv az ügyviteli munkák támogatására -- és a rossz nyelvek szerint: a nagybetűk írásának a gyakorlására), majd a 360-as sorozatra újonnan létrehozott IBM-szülött nyelv: a PL/I (Program Language One = első programnyelv), melyet az IBM az előbb felsorolt három nyelv ötvözeteként, univerzális nyelvként igyekezett bevezetni (más gépsorozatokon alig terjedt el). A PL/I-et az IBM számos alsóbb szintű operációsrendszeri funkcióval is megtámogatta, így az tényleg elég jól funkcionál a sorozat gépein, különösen, ha a legújabb optimalizálós változatokat nézzük. További nyelvekhez is készültek fordítóprogramok a DOS rendszerben. Ezek egy része interaktív alrendszerként interpreteres formában jelent meg. Manapság minden lényeges nyelvre van valamilyen DOS alatt használható fordítóprogram vagy interpreter. A DOS-os fordítóprogramok, a fentebb elemzett okok miatt, félig fordított kódot, azaz tárgykódot generálnak, aminek szabványos formátuma van, ezért elvileg a programszerkesztő (IBM terminológiával: Linkage Editor) bármely nyelven írt kódmodul tárgyprogramját hozzá tudja szerkeszteni a komplett programokhoz. Ezt az ideális állapotot rontja, hogy a futáskor minden nyelvi fordító speciális nyelvi végrehajtási környezetet tételez fel. Így az assembly nyelvű modulok hozzáfűzése okozza a legkisebb gondot. A későbbi változatokban ezen úgy igyekeztek segíteni, hogy a nyelvi fordítóknak be lehet jelenteni, hogy milyen, más forrásnyelvből fordított modulok hozzáfűzésére kell felkészülniük. Igazi programfejlesztési támogatást először az interaktivitást biztosító távfeldolgozó hardver megjelenése hozott. Létrehoztak interaktív alrendszereket (pl.: APL), amelyekben szövegszerkesztők is megjelentek. Fejlődést jelentett az RJE (Remote Job Entry= távoli kötegelt munkabevitel) megjelenése is, mert bár csak a kötegelt üzemmód határait terjesztette ki a géptermen kívülre, de ezzel decentralizálta a hardvererőforrásokat, ami a programfejlesztésekre igen kedvező hatású volt. A programfejlesztés támogatásának újabb lépcsőjét az adatbázis-technika kialakulása jelentette (DL/I = Data Language One = első adatkezelő nyelv -- PL/I mintára!). Az adatbázis-technika a
DOS/VS-ben rendszeradminisztráció szintű támogatást kapott: bevezettek egy új adatkezelési módszert, a VSAM-ot (Virtual Storage Access Method = virtuális adatelérési módszer). VSAM használatával a programozónak csak a logikai adatszerkezetre kell figyelnie. Látszólag, azaz virtuálisan, elrugaszkodhat a fizikai tárolási szerkezettől. (A VSAM, de még inkább a DL/I, alkalmazásakor a fizikai tárolási szerkezettel nem az összes programozónak, hanem csak egy személynek, az adatadminisztrátornak kell foglalkoznia.) A DOS/VS legfejlettebb programfejlesztési támogatása az ETSS (Entry Time-sharing System = interaktív időosztásos alrendszer), amely közeli és távoli terminálokon vehető igénybe. A terminálkapcsolatokat a rendszeradminisztráció a VTAM (Virtual Telecommunication Access Method = virtuális távfeldolgozási elérési módszer) adatkezelési technikával támogatja. Ez elődje a későbbi hálózati adatkapcsolati szabványoknak (SNA stb.). A nyomkövetési támogatás a DOS-ban kezdetben csak a dumpot jelentette. A fordítóprogramokba később beépítettek szoftver nyomkövetési eszközöket is. A DOS operációs rendszer programfejlesztést támogató funkcióit még további programtermékek egészíti ki, amelyek nem is mind az IBM-től származnak. Az ESZR-en belül szintén jelentős DOS és DOS/VS fejlesztéseket hajtottak végre, és még továbbiak vannak folyamatban. A hazai kutatóhelyek pl. elől járnak az integrált programfejlesztő rendszerek kidolgozásában (SZÁMALK, SZKI). A DOS alkalmazói támogatásában megtaláljuk a 2.3.-ban felsorolt minden fő funkciót. Így van operátori parancsnyelv, van munkavezérlő nyelv (JCL-utasítások), amelyek annyiban keveredhetnek, hogy a munkakötegben is megadhatók operátori parancsok, és az operátori konzolról is beadhatók JCL-utasítások, illetve a futás közben hibásnak bizonyult JCL-utasítások konzolról javíthatók. A JCL beolvasóprogramja egyben magas szintű ütemezői feladatokat is ellát rendszerszolgáltatásként. A rutinfeladatok megoldásához sok segédprogram áll rendelkezésre (DITTO -- másoló, SORT/MERGE -- rendező, összefésülő stb.). Az IBM igen széles skálán biztosít alkalmazói programcsomagokat. A jobbakat sajnos csak bérelni lehet, megvenni nem. OS operációs rendszer Az OS (IBM System 360/370 Operating System = az IBM 360/370-es sorozatú gépeinek operációs rendszere) a nagyobb teljesítményű modellek üzemeltetésére és univerzális használatra szánt, de alapvetően kötegelt üzemmódú, multiprogramozható operációs rendszer. Rendszeradminisztrációs funkciói jóval dinamikusabb üzemeltetést tesznek lehetővé, mint a DOS rendszer. Ennek ára a rendszeradminisztráció jóval nagyobb kapacitásigénye, amely a kisebb modelleknél oda is elvezethet, hogy az alkalmazói program alig halad a nagy rendszeradminisztrációs terhelés (IBM terminológiával: overhead) mellett. A modellméretek függvényében az OS-nek három változatát lehetett használni: * PCP-t (Primary Control Program= egyáramú vezérlő), * MFT-t (Multiprogramming with Fixed number of Tasks = multiprogramozás fix (maximált!) számú taszkkal), és * MVT-t (Multiprogramming with Variable number of Tasks = multiprogramozás változó számú taszkkal). A PCP kihalt, mert csak igen kis kapacitású modelleken lehetett használni, az MFT és az MVT pedig jelentősen átalakult a virtuális gépek megjelenésével. Az MFT utóda az OS/VS1, míg az MVT-nek két utóda is van az OS/VS2 keretében: az SVS (Single Virtual Storage = egyetlen virtuális táras rendszer), és az MVS (Multiple Virtual Storage = több virtuális táras rendszer). Az OS operációs rendszerek indítása hasonló a DOS-éhoz, de a betöltési folyamat elég hosszú
lehet, mert induláskor az OS feltérképezi a teljes hardver-szoftver környezetet, "rátelepszik" az összes erőforrásra. Működés közben az állapotváltozásokat folyamatosan nyomon követi. A nagy rendszerterhelés hátterében ez húzódik meg, azonban igen jelentős előnyöket jelent a felhasználónak, hogy szinte semmit nem kell a "rendszer szájába rágni", az mindent tud magától (ugye, milyen régi a Plug&Play? -- ZSP,2K.9.28.). Az OS rendszeradminisztrációs funkcióit megvalósító rendszermagot is supervisornak nevezik. Ez azonban jóval bonyolultabb és jóval nagyobb, mint kisöccsének, a DOS-nak a supervisora. (Jobban ellen is áll a rendszerprogramozók inkompatibilitást generáló kísérletezéseinek, illetve "exit" (kilépési) pontokkal rendszabályozza a módosítási lehetőségeket.) A funkciókat kiszolgáló programok igen nagy része tranziens, amelyek közül az adott installációban leggyakrabban használtakat induláskor be lehet hozni a főtár rezidens területére. Az OS támogatja a kódmegosztást, azaz az újraindítható programokat. Az OS alatt használható programozási nyelvek köre és alkalmazásuk filozófiája azonos a DOS-nál mondottakkal. Az OS tárgykódú moduljai kevésbé nyelvfüggők, mint a DOS-belieké. Az OS-ben a program-szerkesztő mellett létezik egy megtévesztő nevű program is, a loader. Ez nem azonos a 2.2.-ben tárgyalt betöltővel, bár angolul azt jelenti. Inkább speciális szerkesztőprogramnak tekinthető, amely nem készít háttértáron elhelyezhető programmodult, hanem egyenesen a főtárba helyezi az összeszerkesztett programot. A főtárba töltéshez persze igénybe veszi a rendszeradminisztráció tárkezelő moduljának programbetöltő funkcióját. Ez példa arra, hogy az egyes számítógépgyártók mennyire eltérő tartalommal használhatják ugyanazt az elnevezést. A terminológia szabványosítása folyamatban van, de világszabvány (ISO) szinten elég lassan halad (a szakirodalom pedig, sajnos, alig figyel rá!). Az OS programfejlesztési támogatása jóval fejlettebb, mint a DOS-é. Itt is persze inkább az interaktivitást biztosító eszközök emelhetők ki. Már az MFT-ben megvalósították az úgynevezett CRJE (Conversational Remote Job Entry = interaktív távoli munkabeviteli alrendszer) szolgáltatást. Ez szövegszerkesztőt is tartalmaz, ezért interaktív programbevitelt tesz lehetővé, ami jelentős előny a régi lyukkártya-technikához képest, hiszen nem kell bíbelődni terjedelmes kártyakötegekkel. Az MVT-ben hozták létre a legfejlettebb programfejlesztési támogatást nyújtó szoftverkörnyezetet, amelyet a rendszeradminisztráció TSO (Time-sharing Option = időosztásos lehetőség) alrendszere támogat. Az IBM gépeken eredetileg volt külön időosztásos operációs rendszer (TSS) is, de inkább a korábbi OS operációs rendszer alrendszereként megkonstruált időosztásos támogatás vált be (többek között azért, mert az üzemeltetésnek kényelmetlenebb volt állandóan operációs rendszereket váltogatni a gépen). A TSO nem csak interaktív szövegbevitelt biztosít, hanem lehetővé teszi a programok on-line belövését, méghozzá a hardver nyomkövetési támogatást is beleértve. (A nem interaktív programnyelvi eszközök csak dumpot, és szűk választékú szoftver nyomkövetést támogattak!) Az OS rendszerek adatkezelése igen rugalmas. A programokat maximálisan perifériafüggetlennek írhatjuk meg, és a hozzárendelés csak az utolsó pillanatban, a program futásakor történik meg. A DOS/VS-ben említett adatelérési módokat (VSAM, VTAM) az OS verziók is támogatják, de lényeges újdonságok nem jelentek meg bennük. Az IBM operációs rendszerekre jellegzetesen elmondható, hogy felfelé kompatibilisek: az egyszerűbb rendszerek felügyelete alatt készült programok (relatíve kevés módosítással) újrafordítás után használhatók a bonyolultabb támogatást nyújtó változatokkal is. Az OS alkalmazói támogatása a DOS-hoz hasonló. Az operátori nyelv elég bonyolult. Csak ezzel lehet biztosítani az üzemeltetés maximális rugalmasságát. Ehhez hozzájárul, hogy a támogatott
hardvereszközök köre is szélesebb, mint a DOS-ban. A munkavezérlő nyelv erősen elvált az operátori nyelvtől, ezért a hibás JCL-utasítások például konzolról nem javíthatók úgy, mint a DOSban. A hibás JCL-utasítást tartalmazó munkacsomagot a rendszerolvasó rögtön kirekeszti a feldolgozásból. A JCL-utasítások között azonban elhelyezhetők operátori parancsok, amelyeket -jogosultság esetén! -- az operációs rendszer azonnal végre is hajt. Az OS munkavezérlő nyelvét később részletesen is tárgyaljuk. Megjegyzendő, hogy az OS interaktív alrendszereinek (például a TSO-nak) a szolgáltatásait teljesen más filozófiájú parancsnyelvekkel támogatják. Az OS rendszerszolgáltatásait több rendszerelem bonyolítja le (beolvasó, kiíró, főütemező stb.). Az OS-ben még kiterjedtebb a segédprogramok köre. Ezek közül a jobbakat és sok alkalmazói programcsomagot szintén csak bérelni lehet. Az ESZR felhasználók támogatására hazánkban központi fejlesztési alapból beszerzett, nem IBM eredetű szoftverek is rendelkezésre állnak. VM/370 virtuális gépes operációs rendszer A VM/370 (Virtual Machine = virtuális gépeket emuláló) párhuzamosan több operációs rendszert is támogató, különleges időosztásos operációs rendszer, amely -- fő feladatként -- DOS/VS és OS/VS programok egyidejű használatát teszi lehetővé úgy, hogy a támogatandó operációs rendszerek számára a hardvert virtuálisan több gépre osztja fel. Az ehhez szükséges hypervisor funkciókról később lesz szó (14. fejezet). Itt megemlítendő azonban a programfejlesztést támogató CMS (Conversational Monitor System = interaktív felügyelőrendszer) szolgáltatás, amely kizárólag a VM/370 felügyelete alatt működő speciális operációs rendszer. Egyéb olyan szoftverek is vannak, amelyek csak a VM/370 szolgáltatásai mellett használhatók. A CMS és az említett további szoftvercsomagok működésekor összeköttetést lehet teremteni a VM/370 alatt futó DOS, vagy OS operációs rendszerek között, vagy a VTAM/SNA (System Network Architecture = számítógéphálózati architektúra) kapcsolaton át egy egész számítógép-hálózattal. 2.4.2. AZ OS MUNKAVEZÉRLŐ NYELVÉNEK ALAPELEMEI Az OS munkavezérlő nyelve három fő és néhány kiegészítő un. JCL-utasításra épül. A fő JCLutasítások: * JOB utasítás, a munka alapinformációinak definiálására; * EXEC utasítás, a hívandó rutinok aktivizálására; * DD utasítás, a használandó adatállományok megadására. A munkákról -- mint korábban említettük -- feltételezzük, hogy azok több lépésből állnak. Ennek megfelelően minden munkát egy JOB utasítás vezet be, amelyet egy vagy több (pontosabban lépésenként egy-egy) EXEC utasítás, majd lépésenként változó számú (adatállományonként egy vagy több) DD utasítás követ (ha egyáltalán kell DD utasítás). Az OS JCL-utasítások általános alakja öt mezőből áll: 1. 2. 3. 4. 5. mező //
<űr><művelet><űr><űr><megjegyzés> Az első mező fix hosszúságú, és a benne kódolandó két perjel a JCL-utasítások megkülönböztetésére (azonosítására) szolgál. A rendszerolvasó parancsértelmezője ennek alapján veszi észre őket, ami egyben korlátozást is jelent, mert emiatt adat és programkártyák normálisan nem kezdődhetnek ezzel a két karakterrel. A második a névmező, amely változó hosszúságú, hossza 1 -- 8 karakter lehet. Értelmezése műveletenként változó. A JOB parancsban a munkanevet, az EXEC parancsban a lépésnevet, a DD parancsban a DD-nevet adja meg.
A további mezőket űrmezők választják el egymástól, amelyek egy vagy több szóközből (IBM terminológiával "SPACE" vagy "BLANK") állnak. A harmadik a műveletmező, amely ugyancsak változó hosszúságú, és tartalma a már említett JOB, EXEC, DD, vagy más műveleti kulcsszó lehet. A negyedik az operandusmező, amely szintén változó hosszúságú, és az egymástól vesszővel elválasztott műveleti paraméterek megadására szolgál. Az ötödik a magyarázatmező, amely az operandusmezőt követő űrmező után a rekord végéig tart. Megjegyzendő, hogy a JCL-utasítások írási szabályait a lyukkártya-technikához igazították, minthogy az IBM 360-as sorozat megjelenésekor döntően ezt az adathordozót használták a JCLutasítások megadására. A lyukkártyák beosztása a következő: 1..... .16...
71. 72. 73.-80. >
Az utasításmező tehát az 1.-71. pozíciókra terjed ki. Ebben írhatók a JCL-utasítások mezői, ha elférnek. Ha az utasítás operandusai nem férnek el egy utasításmezőben, vagy egyes paramétereket külön kártyán szeretnénk megadni -- a jobb áttekinthetőség, vagy a könnyebb módosíthatóság miatt, -- akkor a 72. pozíción folytatásjelet (FJ) kell megadni, ami szóköztől különböző bármely karakter lehet. A parancs szétvágása a paramétereket elválasztó vesszőknél lehetséges úgy, hogy a vessző után egy űrmezőt alkalmazunk. Az űrmező után a 71. pozícióig írhatunk kommentárt is. A parancs folytatását valahol a következő kártya 2.-16. oszlopán kell elkezdeni. Az utolsó rekord FJ mezejét üresen kell hagyni (tipikus hibalehetőség a JCL-utasítások írásakor!). A sorvégi megjegyzések írásánál is vigyázni kell, nehogy a 72. pozícióra szóköztől eltérő karakter kerüljön (ez is jellegzetes JCL-hiba), mert az értelmező a következő kártyát folytatásként írt kommentárként értelmezi(!). A 73-76. kártyapozíciók -- opcionálisan -- az úgynevezett kártyacsomag azonosító (Az), a 77.-80. (vagy együtt a 73.-80.) pozíciók a kártyasorszám (Ssz) tárolására szolgálnak. Interaktív környezetben írt munkacsomagoknál sem lehet eltekinteni ezektől a fő szabályoktól, csak az űrmezőkben tabulátor karaktert is használhatunk. Az utolsó tabulátorpozíción ilyenkor folytatásjel található, mert interaktív környezetben a pozicionálás körülményes, és egyértelműen feleslegesnek érezzük. (Ezekből a borzasztó szabályokból talán érezhető, mennyire visszahúzó hatása van egy régi technológiai bázis folyamatos fenntartásának!) A JCL-utasításoknak vannak kötelező és választható (opcionális) mezői és paraméterei. A szabályok műveletkódonként eltérőek. Így például minden utasításban kötelező a műveletmező megadása. A JOB és az EXEC utasításban kötelező a címkemező, de máshol opcionális. Az elhagyott (opcionális) paraméterek úgynevezett alapértelmezett értéket kapnak. Ezek vagy fix értékek, vagy az OS generálásakor (tehát első üzembeállításakor) a rendszerprogramozó állíthatja be őket. Némelyek operátori paranccsal is módosíthatók, azaz hozzáhangolhatók a pillanatnyi üzemi viszonyokhoz. A számítóközpontok mindig tájékoztatni szokták alkalmazóikat a náluk beállított értékekről, illetve a megkövetelt előírásokról. Ha ezeket valaki nem tartja be, akkor azt az OS valamilyen módon bünteti (a munkát kidobja, vagy nagyon lassan halad stb.). A következőkben a műveletkódokat és a betű szerint írandó utasításrészeket nagybetűkkel, a konkrétan megadandó adatok fogalmát pedig kisbetűkkel írjuk. A feltételesen írható paraméterek szögletes zárójelbe kerülnek. A kiválasztandó paramétereket kapcsos zárójelek között soroljuk fel, és az egyes tagokat függőleges vonal választja el. (Ezek a szokásos metanyelvi szabályok.)
A JOB utasítás A JOB utasítás egy munkaköteg elejét jelzi és azonosítja. Néhány jellemző paraméterével az alábbi módon kódoljuk: //job-név JOB <paraméterek> A paraméterek OS verziónként változóak, és azokon belül is egyesek kötelezőek, mások pedig nem. Itt a következőket mutatjuk be: [számlázási információk] [programozónév] [CLASS=munkaosztály] [MSGCLASS=kimenetosztály] [MSGLEVEL=([0│1│2│[,0│1])] [PRTY=prioritás] [TIME=(percek,másodpercek)] [REGION=nK] A számlázási információk az üzemeltetésnek kellenek. Ebből tudják, hogy milyen munkaszámra számolhatják el a teljesített számítógépes szolgáltatások díját. Megadási módjuk erősen számítóközpont-függő. Ugyanakkor a programozónévre inkább a felhasználóknak van szüksége, hogy az eredménylistákat könnyebben megtalálják. Az alkalmazó (vagy a programozó) a munkájához erőforrásokat szeretne lekötni. Az OS-ben az üzemeltetés A,B,C stb-vel jelölt munkaosztályokat jelöl ki, amelyekhez a rendszergeneráláskor erőforrásokat rendelnek (például tárigény, időigény). (Ez is számítóközpont-függő, a konkrét számítógépen az üzemeltetés tud tájékoztatni a helyi beállításokról.) Az alkalmazónak kell kiválasztani azt az osztályt, amely elegendő erőforrást biztosít munkája teljesítéséhez. Az operátorok az osztályok erőforrásait módosíthatják, és a munkákat is átsorolhatják más osztályba, ha az üzemmenet úgy kívánja. Ez igen rugalmas rendszerhasználatot eredményez. Az OS-ben a nyomtatást igénylő üzenetek -- és az eredménylisták -- konkrét perifériái (többnyire sornyomtatók) is osztályokhoz vannak hozzárendelve (szoftver SPOOLING). Ezek a kimenetosztályok. Így szükség lehet a kimenetosztály megadására. Az MSGLEVEL paraméterrel szabályozhatjuk, hogy az összes rendszerüzenetre kíváncsiak vagyunk-e, vagy csak kevesebbre, sőt majdnem semmire. Rendszerint nem kell megadnunk, mert a rendszergeneráláskor logikus -- vagy a számítóközpontban előírt -- értékre állítják be. A paraméterek konkrét jelentésére itt nem térünk ki. A PRTY paraméterrel kérhetünk a munkaosztályra rendszergeneráláskor beállított sürgősségi (prioritási) értéktől eltérő értéket. Az OS-ben a magasabb számértékek jelentik a sürgősebb munkát. A számítóközpontok általában tiltják a PRTY használatát, mert téves adat megadása esetén a munka nagyon megzavarhatja az üzemmenetet! A TIME paraméterrel korlátozhatjuk a program futásához felhasználható maximális CPU-időt. Ez programbelövésnél hasznos, mert az OS spoolingos, multiprogramozott környezetében nehéz csak úgy észrevenni egy végtelen ciklusba esett programot. Munkaosztályonként itt is ésszerű értékeket szoktak beállítani rendszergeneráláskor, de erre a paraméterre oda kell figyelni! A REGION paraméterrel az operációs rendszernek előre jelezhetjük, hogy a munkánk elvégzéséhez mekkora tárméretre lesz szükség. Ez az ütemezőt befolyásolja majd, amikor arról dönt, hogy be tudja-e ütemezni a munkát végrehajtásra. Amíg nincs elég tár, addig a munkát várakoztatja.
Jellemző, hogy ezt a paramétert csak a dinamikusabb erőforrás gazdálkodást megvalósító MVT verziók használják, de azoknál megadása kötelező is. A paraméterek jelentésének részleteiről és a további paraméterekről az irodalomban, de leginkább a konkrét installáció gépkönyveiben és üzemeltetési utasításaiban érdemes tájékozódni. Az EXEC utasítás Az EXEC utasítás egy részfeladat megoldásához használandó program vagy ún. JCL-eljárás behívására és indítóparamétereinek megadására szolgál. Kódolása: //lépésnév EXEC <paraméterek> <megjegyzés> Az EXEC utasítás paraméterezése is erősen függ az OS verzióktól, és ezek közül is csak néhányat tudunk megvizsgálni futólag. Tipikus EXEC paraméterek: {PGM=programnév │ [PROC=]eljárásnév} [COND(feltétel)] [DPRTY=diszpécserprioritás] [PARM=programparaméterek szövege] [REGION=(érték0 K,érték1 K)] [TIME=(percek,másodpercek)]
(kötelező és első!)
Egy EXEC utasítással vagy egy bináris programot (PGM paraméter), vagy egy JCL-eljárást lehet aktivizálni, amely úgynevezett eljáráskönyvtárban található (PROC paraméter). Az eljáráskönyvtárban -- mint várható -- rutinfeladatokhoz könnyen paraméterezhető, szöveg alakú JCL-utasítások vannak. A COND paraméter, amely a JOB utasításban is szerepelhet, feltételtől teszi függővé a munkalépés végrehajtását. Így szabályozni lehet, hogy a köteg olyan munkalépései, amelyek az előző lépések helytelen működése következtében szintén rosszul működnének, ne hajtódjanak végre. Az operációs rendszer nyilvántartja az egyes lépések úgynevezett válaszkódját, amelyet az utoljára futó program hagy hátra. Ha ez az érték nulla, akkor nem volt hiba, egyébként a válaszkód értékétől függően súlyos vagy kevésbé súlyos a hiba. A COND feltételben a válaszkódokat tudjuk megvizsgálni, és ha azok nem megfelelők, akkor a munkalépés végrehajtását megakadályozhatjuk, nehogy hibát hibára halmozzunk. A feltételek konkrét megadási módját itt nem részletezzük, de megjegyezzük, hogy az egy kicsit nyakatekert. Más korai munkavezérlő nyelvekre is jellemző az ilyen, az operátori nyelvek kapcsán már említett, gyermekbetegség, hogy nem ügyeltek a nyelv kényelmes használhatóságára. A DPRTY paraméter a JOB utasítás PRTY paraméteréhez hasonló. Vele korlátozott mértékben szabályozhatjuk a prioritást. Értéke hozzáadódik a munkaosztály alapértelmezés szerinti prioritásához. Ezzel a lassúbb munkalépéseket kicsit meggyorsíthatjuk. A PARM paraméterrel szövegfüzért adhatunk át a hívott programnak, amely ennek függvényében választhatja meg működésmódját. A REGION paraméter az egész kötegre érvényes hatállyal a JOB utasításban is megadható, de főként lépésenként dönthető el a pontos értéke, a program futásához igényelt valós és virtuális tárigény (partíció, régió) megadására szolgál. Az EXEC parancsnak további kiterjedt paraméterezése van, amely szintén függ az OS verzióitól. A részletekért ismét a kézikönyvekre utalunk.
A DD utasítás A DD utasítás az adatállományok fizikai adathordozójának definiálására szolgál. Paraméterezése igen bonyolult. Ez a programok perifériafüggetlenségének ára. Kódolása: // DD <paraméterek> <megjegyzés> Ebben a fejezetben csak a legegyszerűbb paraméterekre térünk ki. Az OS-ben ugyanis igen könnyű olyan programok munkacsomagját megírni, amelyeknek egy szekvenciális bemenete és egy listakimenete van. Ilyenkor a bemenő adatokat közvetlen a kötegben helyezik el. Az ilyen munkakötegek szerkezete: <JOB utasítás> <EXEC utasítás> ... /* adatszeparátor kártya // NULL JCL-utasítás, kötegvége jel A bemenetet az úgynevezett szabványos bemenetről várjuk. Ennek speciális DD neve van: SYSIN. Azt, hogy az adatok a kötegben közvetlenül a DD utasítás után állnak, a következő paraméterezéssel lehet megadni: //SYSIN
DD
*
Ebben a DD utasításban a * egy úgynevezett pozícionális paraméter. A pozícionális paramétereket mindig előírt sorrendben kell megadni. Ezektől eltérően a KULCSSZÓ=valami alakú kulcsszavas paramétereket, tetszőleges sorrendben is megadhatjuk, mert a kulcsszó mindig pontosan mutatja, hogy melyik paraméternek adunk értéket. Ha a bemenő adatok között JCL-utasítások is vannak, akkor * helyett DATA paramétert kell megadni. DUMMY paraméter megadásával üres bemenetet is generálhatunk. Ilyenkor a program állománynyitáskor azonnal EOF (End of file = adatok vége) feltételt talál. Így egy programot adatok nélkül is kipróbálhatunk (ha ennek egyáltalán van értelme). TSO állományoknál DYNAM (dinamikus) paramétert kell használni, mert a TSO-ban még később történik az állományhozzárendelés, mint kötegelt esetben. Munkacsomag íráskor még nem is lehet tudni, hol lesz az állomány, ez csak végrehajtás közben derül ki. A DD utasításnak ez az egyetlen pozícionális paramétere. Használatakor a kulcsszavas paraméterek előtt kell megadni. A következő tanulságos DD utasítás a kimenetet leíró utasítás. Az OS filozófiája szerint a listák az úgynevezett szabványos kimenetre kerülnek. A szabványos kimenetnek szintén speciális DD-neve van: SYSPRINT. A szokásos DD utasítás: //SYSPRINT DD SYSOUT=kimenetosztály Itt lehet megadni, hogy a lista melyik kimenetosztályba kerüljön. A kimenetosztályok tulajdonságait az üzemeltetés szokta meghatározni, mint arról korábban a JOB utasításnál már volt szó. Rendszerint különböző típusú sornyomtatókat vagy a nyomtatókon használatos speciális beállításokat (más vezérlőszalagot, 1-2-4 példányos papírt stb.) jelentenek. Különleges
kimenetosztály terminálok esetében az R (remote = távoli) osztály, ha a felhasználó a termináljára kéri vissza az eredményt (egy számítóközpont persze kijelölhet más betűt is ennek az osztálynak!). A lehetséges kimenet-osztályokról mindig a szolgáltatást nyújtó számítóközpontban kell tájékozódni. A DD utasítás további paramétereivel a logikai adatállományokhoz konkrét fizikai adathordozón elhelyezett adatállományokat kapcsolhatunk hozzá, és állományvédelmi rendszabályokat írhatunk elő, de ezekkel kapcsolatban ismét a kézikönyvekre utalunk, illetve, az OS vezérlőtáblázatai kapcsán a 6. fejezetben még lesz róluk szó. 2.4.3. Az IBM PC operációs rendszerei Az IBM PC-ken négy (természetesen lemezrezidens) operációs rendszer terjed igazán: * PC--DOS/MS--DOS, amely egyfelhasználós, interaktív, monoprogramozott operációs rendszer; * CP/M86, amely szintén egyfelhasználós interaktív, monoprogramozott operációs rendszer; * XENIX, amely többfelhasználós, interaktív, multiprogramozható operációs rendszer (UNIX); * OS/2, amely egyfelhasználós, interaktív, multiprogramozható operációs rendszer (az MS-DOS vonal folytatása). Ezek közül legnagyobb teret a PC--DOS/MS--DOS páros nyert, és világcsúcsszámba menő, becsülhetően (1988-ban) tízmilliós, installációs számával valószínűleg hosszú távon is verhetetlennek bizonyul. A siker az egyszerű alkalmazói interfésznek köszönhető. Elnevezésükről annyit megemlítünk, hogy a PC--DOS az eredeti IBM PC-k operációs rendszere, amelyektől eltérő névvel különböztették meg a másolatgépek (klónok) operációs rendszereit, licensz okok miatt. Végül mindkét változat a Microsoft cégtől ered, de a PC--DOS-nak extra ROM-támogatása is van. A továbbiakban a rövidség kedvéért az elterjedt DOS elnevezést használjuk. A (közben sikertelenné vált!) PS/2 modellekkel az IBM új operációs rendszert akart bevezetni (OS/2), ami a DOS-hoz képest annyit javított a helyzeten, hogy kihasználja a privilegizált üzemmódokkal rendelkező INTEL mikroprocesszorok lehetőségeit, például lehetővé teszi védelmi rendszer kiépítését, és igazi multiprogramozást enged meg egyetlen felhasználónak (multitasking). Az IBM PC-ken igazi (többfelhasználós) multiprogramozott környezetet csak a UNIX változatok biztosítanak. Ezek közül legelterjedtebb (volt!) a Microsoft(!) cég XENIX operációs rendszere, és ennek verziói (XENIX SYSTEM V., SCO XENIX, XENIX/386), de valószínű, hogy az IBM a RISC gépére adaptált UNIX változatát, az AIX-ot némi módosításokkal át fogja vinni a PS/2 sorozat nagyobb modelljeire. Mi itt célszerűen csak a DOS-t mutatjuk be, amely paramétereivel legjobban hozzáidomult a hardver adta korlátokhoz (és a potenciális alkalmazók intelligencia szintjéhez??). Tény, hogy a UNIX-ok többet tudnak, de ennek ára is van: rengeteg erőforrást elvesznek az amúgy is szűk konfigurációtól, az alkalmazóktól túl sok számítógépes ismeretet követelnek, ráadásul nem eléggé "bolondbiztos" üzemet biztosítanak (az állományrendszer megsérülése többnyire csak egy jó "superuser" rendelkezésre állása esetén élhető túl!). A DOS-ba, mint majd látjuk, szerencsére igen sok jót átmentettek a UNIX-ból, ami messzebbre helyezi azt a szituációt, amikor tényleg a UNIX-hoz kell folyamodni a PC-ken (azóta igen!). A DOS rendszeradminisztrációs funkciók egyrészt ROM-ban (PC-DOS), másrészt mágneslemezen találhatók. A DOS indítása bekapcsolás, vagy RESET után a ROM indítórutinjának automatikus behívásával történik. A betöltés során inicializálódnak a RAM-tár rendszerterületei, majd az A: lemezegységről, vagy ha abban nincs lemez, a C: fixlemezegységről behívódnak az IBMBIO.COM, IBMDOS.COM rendszeradminisztrációs funkciókat támogató programok. Ezután behívódik a COMMAND.COM parancsértelmező program, amely a parancsnyelvet fogadja, és jobbára az alkalmazói támogatás funkcióit biztosítja. A
COMMAND.COM (a DOS 3.30-as verzióig) eredendően egy sororientált parancsértelmező, amely írógépes terminál típusú interfészt biztosít. Ezt a szabványos parancsértelmezőt azonban le lehet cserélni, és már terjednek helyette a különböző képernyő-orientált, menüvezérléses parancsértelmezők (amelyeket videoshelleknek szokás nevezni -- NC). Ezek közül a legfejlettebb a Microsoft WINDOWS, amely mellesleg multiprogramozást (multitaskingot) is lehetővé tesz egy felhasználónak az OS/2-höz hasonlóan, de nem támaszkodik az INTEL 80286 védelmi rendszerére (azóta a 4.0-val már a DOS-ban is megjelent a képernyős parancsértelmező). Mi az eredeti parancsértelmezőt vizsgáljuk meg, mert célunk az interaktív parancsnyelvi lehetőségek bemutatása. (A képernyős kapcsolat bemutatása jelenleg egyébként is meghaladná könyvünk kivitelezési lehetőségeit.) A DOS parancsértelmezője kétféle, belső és külső parancsot tud értelmezni, mint erről korábban a bináris programkönyvtárak kapcsán már volt szó. A belső parancsok algoritmusa a parancsértelmezőbe van beépítve. A külső parancsok értelmezőprogramját mágneslemezen kell tárolni, DOS-állományként, amelyek elnevezésére a CP/M operációs rendszerből örökölt szabályok érvényesek: maximálisan nyolc karakteres név, és egy ponttal (.) elválasztva maximálisan három karakteres névkiterjesztés (más néven minősítés, típusnév) adható meg. A kiterjesztés megadásával jelezhető a parancsértelmezőnek, hogy a hívandó értelmezőprogram melyik típusba tartozik. A DOS-ban három ilyen programtípus létezik, amelyek kiterjesztési kódjaikkal megadva a következők: * COM típusú bináris programok, * EXE típusú bináris programok és * BAT típusú szöveges parancsállományok. A bináris programokat a parancsértelmező betölti a tárba, és elindítja, a szöveges parancsállományok szövegét pedig elkezdi értelmezni úgy, mintha azokat a billentyűzetről adták volna meg. A belső parancsok között vannak olyanok is, amelyek csak parancsállományból használhatók, mert interaktív végrehajtásuk értelmetlen. A DOS-nak nincs kifejezett programfejlesztő alrendszere, interaktív természete mégis rendkívül kedvező környezetet nyújt a programfejlesztéshez. Minthogy a programozási nyelvek fordítói külső parancsokként aktivizálhatók, és bináris könyvtárakban tarthatók, gyakorlatilag minden programozási nyelv hozzáférhető. A programfejlesztési támogatás az operációs rendszerrel támogatott hardver nyomkövetési lehetőséget is biztosítja (03:Break megszakítás és DEBUG.COM külső parancs monitor). Kiterjedt azonban a nyelvi interpreterek használata, amelyek több szimbolikus nyomkövetési lehetőséget adnak. Újabban vannak szövegszerkesztővel integrált programfejlesztő eszközök is (pl.: TURBO PASCAL, --C, --PROLOG). Egyre több programgenerátort tartalmazó nyelvi rendszer létezik. Velük típusfeladatokra készíthetünk programokat vagy programrészeket, interaktív üzemmódban. Ilyenek az ernyőképtervezők, amelyekkel a képi formátum explicite adható meg, majd generálják a képet az adott nyelven elővarázsoló programot (pl.: PROFESSIONAL COBOL, dBASE III PLUS). A DOS adatkezelése részben a CP/M már említett állomány-elnevezési rendszerén, részben -- a ma élő verziókban, -- a UNIX hierarchikus állományszervezésén alapul. A CP/M szabályok az állományok elnevezésére adnak szabályokat (maximum 8 karakteres név és 3 karakteres kiterjesztési kód adható meg, mint fentebb már volt róla szó). Az állományokról a CP/M annak idején feltételezte, hogy azok mágneslemezen helyezkednek el, és szervezésük szekvenciális. Az állományok tartalmáról magától semmit nem tételezett fel, de a kiterjesztési kóddal megadhatjuk, hogy milyen típusú adatokat tárolunk az állományokban. A CP/M-et, és ebből a szempontból jogutódját, a DOS-t csak a külső parancsok érdeklik. A további állománytípusok értelmezése a fordítóprogramok és az alkalmazói programok feladata. Ezek a parancsoknál emlegetett .COM, .EXE és .BAT kiterjesztéstípusokon túl egy sereg más kódot is alkalmaznak (pl. .PAS = PASCAL
kód, .TXT = ASCII szöveg). A DOS használja még a .SYS kiterjesztést rendszerparaméterek és speciális rendszerelemek megjelölésére. A hardverhez természetesen nemcsak egyetlen lemezegység csatolható. Ezeket a DOS-ban szintén CP/M stílusban különböztetjük meg. A lemezegységek elnevezésére az ABC betűit használjuk a név előtt, a névtől kettősponttal (:) elválasztva. Ez az egységazonosító. Így a DOS állományok teljesebb elnevezése az alábbi szerkezetű: [<egységazonosító>:]<állománynév>[.] Mind a CP/M-ben, mind a DOS-ban van szimbolikus neve a nem mágneslemezes perifériáknak is. Ezek többkarakteres nevek, és szintén kettőspontot szoktak tenni utánuk. Az ilyen szimbólumokat nem használhatjuk állománynévként sem (fenntartott nevek!): CON, AUX, COM1, COM2, LPT1, LPT2, PRN, NUL stb. Az állományok elnevezésén túl fontos fogalom a DOS-ban a katalógusok illetve könyvtárak fogalma. A CP/M-ben, -- és eredetileg a DOS-ban is, -- minden mágneslemeznek csak egyetlen katalógusa volt. A CP/M-ben azonban egy lemezen több, maximálisan 255 különböző felhasználó adatait is meg lehetett különböztetni az úgynevezett USER azonosítóval. Az éppen aktuális user azonosítót egy paranccsal lehetett beállítani (induláskor a 0-s USER adataival lehetett dolgozni). Így az egyes felhasználók adatai egyszerűen elkülöníthetők, minden felhasználó csak a saját adatait látja. A helyzet akkor bonyolult, ha különböző USER-azonosítójú állományokat kell használni egy feldolgozáshoz. Valószínűleg az ebből eredő bonyodalmak miatt nem vették át ezt a módszert a DOS-ba. A DOS-ban egy mágneslemezt kényelmesen csak egy felhasználó tudott kezelni, de neki is gondot okozott, ha különböző munkákhoz tartozó állományai keveredtek ugyanazon a lemezen. A problémát a UNIX operációs rendszer hierarchikus katalógusrendszerének mintájára oldották meg, amikor az IBM PC/XT megjelent az 5 Mbájtos fixlemezével. Ebben a helyzetben ugyanis tarthatatlanná vált, hogy csak nagyon korlátozott számú állomány lehet a mágneslemezen, továbbá sürgetően felmerült a különböző alkalmazókhoz és alkalmazásokhoz tartozó állományok szeparálhatóságának igénye. A UNIX egy mágneses periférián úgynevezett állományrendszer(eke)t (angolul: file system) tételez fel. Minden állományrendszernek van egy kiinduló katalógusa, amit gyökérkatalógusnak (angolul: root directory) neveznek. A gyökérkatalógusban szerepelhetnek UNIX állományok (sima vagy speciális állományok) és a gyökérből elágazó alkatalógusok leírásai, amelyekben szintén lehetnek további állományleírások vagy alkatalógus leírások stb. Ez egy fordított fára emlékeztető, több szintű hierarchikus alakzat: 0. szint 1. szint 3. szint
G Y Ö K É / | kt1 á11 / | / á11 á12 kt21
R \ kt2 | \ á21 kt22
kt= (al)katalógus á= adatállomány
2.3. ábra. Az MS--DOS hierarchikus katalógusrendszere A DOS-ban a mágneslemezeken ugyanilyen állományszerkezet kezelését valósították meg. A gyökérkatalógust nevezik még alapkatalógusnak, illetve főkönyvtárnak (a DOS kezelési utasítás idétlen félrefordításából eredően!), az alkatalógusokat pedig alkönyvtáraknak. A könyvtárak használata megköveteli, hogy az állomány azonosításához megadjuk az őt tartalmazó könyvtár azonosítóját is. A főkönyvtár azonosítására a DOS-ban a \ (backslash = fordított perjel) karaktert használjuk (A UNIX-ban normál perjelet kell használni. Az eltérés oka az, hogy a CP/M nyomdokain járó DOS a normál perjelet másra használta el. A fordított perjellel némileg sikerült megőrizni a hasonlóságot.)
Egy állomány pontos leírásához a gyökérből kiindulva végig kell járni az alkönyvtárakat, mint faágakat. Minden érintett alkönyvtár nevét \ karakterrel kell elválasztani az előző alkönyvtárnévtől. Az eléréshez így kijelölt névsorozatot útnévnek nevezzük (akár a UNIX-ban). Az útnév fogalmát is felhasználva a DOS állományok azonosítása a legáltalánosabban így fest: [<egységazonosító>:][<útnév>\]<állománynév>[.] Az útnevek megadása: [\][\]... Az útnevek megadhatók abszolút útnévvel vagy más néven teljes útnévvel. Ilyenkor az útnevet mindig a főkönyvtárból kiindulva határozzuk meg. Minden könyvtárban van azonban két különleges alkönyvtári leírás, amelyek speciális elnevezést kaptak. A ponttal (.) jelzett alkönyvtár önmagára mutat, illetve képzeletben helyettesíti az alkönyvtár teljes útnevét. Alapértelmezés szerint minden (al)könyvtári elem neve úgy értelmezett, mintha előtte volna a ".\" pont-alkönyvtárnév. Így az alkönyvtárbeli elemek nevét egyszerűen leírva közvetlen névvel hivatkozhatunk a megnevezett elemre, nem kell hosszú útnevekkel bajlódni. E konvenció bevezetése segít annak áthidalásában, hogy a DOS korábbi verziói nem kezelték az alkönyvtárakat. Ott tehát nem is merültek fel útnevek az állománynév előtt. (A UNIX-ban ugyanígy használhatók a közvetlen nevek, a DOS tehát szerencsésen ezt is örökölte.) Fontos még a kétpont (..) alkönyvtár, ami arra a könyvtárra mutat, amelyikhez az alkönyvtár a hierarchiában tartozik, ezért szülőkatalógusnak is szokás nevezni. A szülőkatalógus segítségével relatív utakat adhatunk meg a katalógusfában (pl.: ..\KT\NEV.FMT). Relatív utak megadhatók a pont-alkönyvtárból kiindulva is. Ezek mélyebb hierarchiaszinten lévő elemek azonosítására szolgálhatnak. Ilyenkor egy alkatalógust jelölő közvetlen név után kell az elemhez vezető utat megadni. Az ilyen útnevek elején nincs fordított perjel, hiszen az út nem a gyökérből indul. A relatív útnevek alkalmazása lehetővé teszi, hogy egy feldolgozás állományait a katalógusfa bármely ágához csatlakoztathassuk, és emellett -- relatív utakon át, -- minden szükséges állományt elérjünk. Nem kell ismerni az abszolút útneveket. (Ez is UNIX örökség.) A DOS fent elemzett alkönyvtári rendszere maximálisan alkalmas különböző munkákhoz tartozó adatok szétválasztására, akár több alkalmazó feladatairól, akár egy alkalmazó különböző feladatairól van szó. 2.4.4. ALAPVETŐ DOS PARANCSOK A DOS tökéletes alkalmazói szintű használatához maximálisan 70 parancsot és az adatállományok hierarchiáját kell megismerni, ami nem sok erőfeszítést igényel. Ráadásul alig néhány parancs ismeretével már elég jól el lehet boldogulni. Először ezt a néhányat próbáljuk kiválasztani. A DOS-t valamilyen mágneslemezes perifériáról lehet indítani. Ez lehet az "A" betűvel jelölt első floppy lemezmeghajtó vagy a "C" fix (Winchester) lemezegység. Az indításhoz bekapcsolás előtt, ha nincs fixlemez, vagy ha a gépet az "A" egységből akarjuk indítani (pl. más DOS változat kell), be kell tenni az "A" meghajtóba a DOS rendszerlemezt. (Ha nincs fixlemez, és bekapcsoláskor az "A" egységben sincs lemez, akkor az IBM PC ROM-BASIC interaktív fejlesztőrendszere indul el, de ezzel most nem foglalkozunk.) Amikor a DOS elindul, akkor a 3.30 előtti verziókban kéri a dátumot majd az időpontot. Ezeket olyan alakban kell megadni, ahogy a képernyőn megjelenik. Két eset lehetséges. Vagy van beépített óra a gépben, és akkor csak helyesbítésre van szükség, vagy nincs, és ekkor nekünk kell pótolni a friss dátumot és időpontot, különben egy előre beállított konstans időpont jelenik meg. A beállítást
célszerű elvégezni, mert a DOS a beállított dátum és óraértékeket használja a keletkező állományok időpont adatában. Ha nem állítjuk be az időpontot, akkor nem tudjuk kézben tartani állományaink időrendiségét. A beépített óra nem áll le, csak ha az eleme kimerül (gyakorlatilag sose). Előfordul azonban, hogy késik vagy siet. Az induláskor ezt tudjuk korrigálni. Miután a dátumot és az időpontot megadtuk, egy szoftver óra kezd működni, amely addig jár, amíg a gépet ki nem kapcsoljuk. A dátum és az időpont megadása után a rendszergazda által beállított, és az adott gépi konfigurációra érvényes hasznos információk szoktak megjelenni a képernyőn (ha van ilyen), majd végre megkapjuk a "vezérlést". Erről a rendszer az úgynevezett prompttal értesít bennünket. Ez alapesetben egy nagybetű (A,C), és egy > jel. A betű azt mutatja, hogy melyik a rezidens lemezegység, azaz melyik lemezmeghajtóval dolgozik az operációs rendszer (ez CP/M hagyomány). A nagyobb (>) jel azt jelzi, hogy a parancsértelmező program a parancsainkra vár. Parancsainkat a billentyűzetről adhatjuk be, minthogy a DOS-nak, mint már kielemeztük, sororientált parancsértelmezője van. Lemez-tartalomjegyzék kilistázása -- DIR Indulásképpen az a legjobb, ha körülnézünk. Amíg nincs kellő gyakorlatunk, ez folyamatosan ajánlható. A DIR (Directory listing = al/katalógus, al/könyvtárlistázó) paranccsal induláskor kilistázhatjuk annak a lemeznek a katalógusát, amelyik a rezidens meghajtón van. Normál esetben ez a gyökérkatalógus. A parancs megadása a parancs nevének leírásával történik (elől a prompt van a sorban!): A>
DIR
A parancsot mindig az ENTER gombbal kell befejezni, ami azt jelzi a parancsértelmezőnek, hogy elkezdheti a parancsunk végrehajtását. Amíg az ENTER-t le nem ütjük, nem történik semmi(!). Ugyanakkor, amíg nem ütjük le, addig javíthatjuk a rosszul gépelt betűket. A Backspace (törlőkarakter) billentyű leütésével a kurzor (szabványos nevén helyőr, fizikailag a képernyőn egy futó folt) előtt álló betűt kitörölhetjük, és beírhatjuk a helyes karaktert. Ez tipikus sororientált parancsszerkesztési lehetőség az interaktív rendszerekben. Elvei a telex terminálokon eredetileg meglévő korlátozásokon alapulnak (nem volt képernyő, nem volt kurzor, a hibás karakterig vissza kellett menni a törléssel stb.). Ha több lemezegység van, akkor a nem rezidens meghajtóba helyezett lemezek tartalomjegyzékét is megnézhetjük. Például a "B" meghajtóba helyezett lemez esetében meg kell nevezni a meghajtót a DIR parancs paraméterlistáján (a parancsnévtől egy vagy néhány szóközzel elválasztva!): A>
DIR
B:
Figyeljük meg, hogy az egységazonosító betű után kettőspontot kell írni! (Az interaktív parancsnyelvekben jellemző a különféle elválasztójelek használata a parancsok megadásánál, ami a munkavezérlő nyelvekben a fixmezős beosztás miatt kevésbé merült fel.)
A fenti parancs után a katalógus körülbelül így jelenik meg: Volume in drive B has no label Directory of B:\ ASM AUTOEXEC COMMAND CONFIG GREATING
BAT COM SYS TXT
321 23791 122 6378
87-07-10 87-05-16 85-12-30 87-07-20 87-08-30
12.44 21.10 12.00 09.13 14.57
A listán kétféle név lehet: egy konkrét adatállomány, vagy egy alkatalógus neve. Fenti katalóguslistánk éppen alkatalógus-névvel indul (ASM). Most persze kíváncsiságunk növekedhet. Mi van az ASM alkatalógusban? Ezt megtudhatjuk, ha a lemezegység azonosító mellett megadjuk a látni kívánt katalógus (út)nevét is: A>
DIR
B:\ASM
Az útnevek megadásával az egész lemezt "feltérképezhetjük". A katalóguslistában az állományok neve mellett szerepel a hárombetűs minősítés (kiterjesztési kód), az állományhoz tartozó bájtok száma és az utolsó módosítás dátuma. A katalógusokat szelektált módon is ki lehet listázni. A DOS ugyanis tud kezelni névmintákat. A tipikus probléma az, hogy keresünk valamit, de a nevére nem emlékszünk pontosan. Például csak az első betűjét tudjuk. Ilyenkor a következő parancs használható: A>
DIR
B:\ASM\J*.*
Ennek hatására megjelenik az összes J betűvel kezdődő név, akármi a minősítése. A * ugyanis azt jelöli, hogy ott a névben akármilyen hosszú akármilyen szöveg lehet (persze 8 illetve 3 karakterig). Hasonlóan használható mintakarakter a kérdőjel (?). Ennek jelentése az, hogy abban a pozícióban akármi lehet, például: A>
DIR
B:\ASM\?.*
A parancs hatására megjelenik az összes egybetűs név, akármilyen a minősítése. A parancs használata kapcsán vegyük észre, hogy: * a parancsokban a rezidens egység neve nem kötelező; * az úgynevezett munkakatalógus nevét, ahol éppen dolgozunk, szintén nem kell megadni (ez a pont(.\)!). A rezidens egységet könnyen megváltoztathatjuk, egyszerűen megadjuk az új rezidens egység nevét (kettősponttal!): A> C>
C:
A parancs hatására a prompt mutatja, hogy már a "C" egység a rezidens egység. Ekkor egy másik lemez katalógusába kerülünk át, tehát ott lesz a munkakatalógus. A munkakatalógus azonban nemcsak a lemezek gyökérkatalógusa lehet. Bármelyik egységen a katalógus hierarchia bármely pontjára áthelyezhetjük, de ehhez szükség van egy újabb parancsra.
Katalógusváltás -- CHDIR vagy CD A CHDIR vagy rövidítve CD paranccsal elmozdíthatjuk a munkakatalógust egy másik (al)katalógusba. Ez történhet abszolút útnév, teljes név vagy relatív útnév megadásával. A lényeg az, hogy a korábbi munkakatalógusban a név értelmes legyen. A fenti mintát folytatva, a "B"-n el akarunk jutni a gyökérből az ASM katalógusba: C> B>
B: CHDIR
ASM
Mint látható, a közvetlen (tehát a .\ relatív) nevet használhattuk, mert éppen a "B" gyökerében voltunk. Figyelem! A CD parancs üres paraméterrel a pillanatnyi munkakatalógus teljes útnevét listázza ki a rezidens egység nevével együtt. Kezdetben ilyen üres paraméterű CD paranccsal célszerű ellenőrizni, hogy most hol is vagyunk. Ez a működésmód egyébként rámutat az interaktív parancsnyelvek olyan sajátosságára, hogy a paraméter nélküli parancshívásokat különleges célokra használják. Az egyik elterjedt működésmód az utolsó érvényes beállítás adatainak visszalistázása, a másik pedig a segítségnyújtás, vagyis a parancs paraméterezésének kiírása a terminál képernyőjére. Katalógusok létrehozása -- MKDIR vagy MD Jogos igény, hogy szeretnénk saját katalógust létrehozni. A fixlemezen ez alapvető érdek. A DOS nem hatékony, ha egy katalógusban túl sok név szerepel. Ez a probléma a fixlemez gyökérkatalógusában a legkellemetlenebb. Nem célszerű, ha a gyökérkatalógusban dolgozunk. Létesítsünk inkább a gyökérben egy saját katalógust, és menjünk át dolgozni abba! Persze előbb meg kell győződni, hogy milyen nevek léteznek már. Az MKDIR vagy rövidítve MD egy katalógusnevet vár, amelynek lehet hárombetűs kiterjesztése is, (de ennek használatát nem tanácsoljuk: egyes DOS változatokban a katalóguslistában a minősítés mellett nem jelenik meg a információ, mert nem fér el!): B>
MKDIR
A:\KARCSI
Meg kell tehát adni az egységszámot és a megfelelő útnevet. Szövegmegjelenítés képernyőn -- TYPE Most már jól tudunk közlekedni a katalógusfákon. Itt-ott találhatunk úgynevezett ASCII (aszkii) kódú, tehát számunkra olvasható szövegeket. Ezek minősítése .TXT vagy .DOC szokott lenni. Az ilyen állományokat rendszerint szövegszerkesztő programmal írták. Ezek tartalmát kilistázhatjuk a képernyőre a TYPE paranccsal. Például a fenti példa katalóguslistából kiindulva az indulóüzenetet újra elolvashatjuk: B>
TYPE
\GREATING.TXT
Ne felejtsük el, hogy utoljára az ASM katalógusban voltunk. Ha közben netán átmentünk volna a "C" egységre, akkor az egységazonosítót is meg kell adni: C>
TYPE
B:\GREATING.TXT
A képernyő törlése -- CLS Sokszor zavaró, hogy a képernyőn régebben kiírt szövegek is láthatók. Ilyenkor "tiszta lapot csinálhatunk" a CLS paranccsal: B>
CLS
Ha gépünkhöz van nyomtató csatlakoztatva, akkor a képernyőre listázott szövegeket nyomtatóra is kiírathatjuk. Amikor valamit ki akarunk íratni nyomtatón is, a CTRL + P billentyűkombinációt kell megnyomni (célszerű előbb a CTRL gombot lenyomni, majd e közben a P betűt leütni). Ha tovább nem kell nyomtatni, akkor megismételjük a CTRL + P kombinációt. Így a nyomtatás ki-be kapcsolható. Ez a CP/M-ből örökölt hardcopy (képernyőmásolat) technika. Dátum és időpont lekérdezése, módosítása -- DATE, TIME A dátum, és időpont beállító parancsok lekérdezésre és beállításra is használhatók. Paraméter nélkül ezek is az utoljára beállított értéket írják vissza, de kérnek egy új adatot is. Ha ilyenkor válaszként ENTER-t adunk, nem változik meg a korábban beállított dátum illetve időpont. Tipikus hívási példa: B> TIME Current time is 21:03:35.23 Enter new time: B> Lapozott listázás szűrővel -- MORE Idegesítő, hogy a hosszabb katalógusok vagy ASCII szövegek a képernyőn egy pillanat alatt átfutnak, és nem tudjuk őket elolvasni. A listázást, a CP/M-től örökölt módon, ideiglenesen megállíthatjuk a CTRL + S billentyűkombináció megnyomásával. Ez azonban jó reflexeket igényel (pláne 1GHz-es processzorokkal!) még gyakorlott felhasználóktól is, nemhogy kezdőktől. A problémán segít a UNIX-ból átvett szűrő (FILTER = FILe TranszfeR = állománymozgatás szavakból képzett akronim (betűszó és szójáték!). A MORE program úgy működik, hogy egy átmeneti állományon keresztül elkapja az előtte álló program képernyőre szánt kimenetét, és 24 soronként meg-megállva ő listázza ki a képernyőre. Alkalmazásához a listázó program és a MORE közé a függőleges vonás (|) csővezeték (pipe) jelet kell írni (ettől ez még nem lesz igazi UNIX pipe!). Példa: A>
TYPE
ADOSZAM.TXT | MORE
Megjegyezzük, hogy a DIR parancs úgy is paraméterezhető, hogy a listázás laponként megálljon. Ezzel kapcsolatban megemlítjük, hogy a DOS parancsok a paraméterlistán úgynevezett kapcsolókat is értelmeznek. A kapcsoló paramétereket (normálállású!) perjel (/) után kell írni. Így a DIR lapozott listázása a következő paranccsal érhető el: A>
DIR
B:\ASM/P
Itt a /P kapcsoló (Paging = lapozás) jelenti a lapozási funkció bekapcsolását. (A DOS tehát a perjelet a CP/M-től örökölt kapcsolók programozására használta fel.) Az IBM OS munkavezérlő nyelve és A DOS parancsnyelve csak illusztrációul szolgált a kötegelt és az interaktív számítógépes kommunikációs lehetőségek bemutatásához. A továbbiakban minden kommentár nélkül közlünk még egy összehasonlító táblázatot a CP/M, a UNIX és az MS--DOS operációs rendszerek különféle jellemzőiről, különös figyelemmel
parancsnyelvükre (2.1. táblázat).
FUNKCIÓ Rezidens egység Katalógusváltás Katalóguslista(mintával) Új katalógus készítése Katalógus törlése Állománymásolás Átnevezés Álnévadás Állománytörlés Összehasonlítás Keresés Szövegszerkesztő Lemezformázás Lemezmásolás Új állományrendszer Felkapcsolás Lekapcsolás Lefoglalás Keresési út kijelölés Dátumszolgálat Időszolgálat Bejelentkezés Parancsértelmező* Parancsállomány Változó beállítás Változóhivatkozás Parancsvezérlés Alparancsok Átirányítás Csővezeték Szöveglistázás Nyomtatás Képernyőlapozás Prompt Lemezjavítás Nemzeti billentyűzet Opciók megadása Állományvédelem
CP/M A: (nincs, ill. USER) DIR *.TXT (nincs, ill. USER) (nincs) PIP NÉV2=NÉV1 REN NÉV2=NEV1 (nincs) ERA NÉV (nincs) (nincs) ED NÉV FORMAT A: (nincs) (nincs) (nincs) (nincs) (nincs) (nincs) (nincs) (nincs) (nincs) (nincs explicite) NÉV.CMD (nincs) $1,$2 (nincs) (nincs) (nincs) (nincs) TYPE NÉV (CTRL+P) (CTRL+S) (nincs) (nincs) (nincs) /kapcsoló... USER
UNIX (nincs) cd útnév ls -ail [a-l]f?x* mkdir név1 név2 ... rmdir név1 név2 ... cp név1 név2 mv név1 név2 ln név1 nev2 rm név1 név2 ... cmp név1 név2 grep minta utak ed név (más az alapelv!) dd if=n1 of=n2 mkfs paraméterek mount meghajtó név umount meghajtó lock név PATH=$(PATH):kat date [új] date [új] login név sh, csh, vsh állománynévXbittel Név=szöveg $(Név) van sh vagy ( ) parancs out par1. | par2. cat név1 név2 ... SPOOLING more név PR1=$ PR2=> fsck meghajtó (nincs szabvány!) -kapcsolólista rwx/ugo **
MS--DOS A: CD ÚTNÉV DIR *.?65 MD NÉV RD NÉV COPY NÉV1,NÉV2 REN NÉV1,NÉV2 (nincs) DEL NÉV COMP NÉV1,NÉV2 FIND "minta" út EDLIN NÉV FORMAT A: DISKCOPY A: B: FDISK JOIN A: C:\A JOIN A:/D (csak LAN s/w!) PATH=%PATH%;\C DATE [új] TIME [új] (csak LAN s/w) COMMAND.COM NÉV.BAT SET NÉV=szöveg %NÉV%,%3 van COMMAND EXIT PAR. OUT PAR1. | PAR2. TYPE NÉV SPOOLING TYPE | MORE PROMPT $P$G RECOVER C:útnév KEYB xx... /kapcsoló ... (csak LAN s/w)
------------------------------------------------------------------* A UNIX-ban választható és lecserélhető, MS--DOS-ban csak lecserélhető! ** r=read(olvasás),w=write(írás),x=execute(végrehajtás); u=user(tulajdonos),g=group(csoporttag),o=others(idegenek) ------------------------------------------------------------------2.1. táblázat. CP/M, UNIX és MS-DOS összehasonlító táblázat
2.5. Gyakorlatok 2.5.1.
Az operációs rendszerek funkcióit melyik három csoportba soroltuk?
2.5.2.
Mi a rendszeradminisztráció?
2.5.3.
Melyek a rendszeradminisztráció fő funkciói?
2.5.4.
Melyik program valósítja meg a rendszeradminisztrációt?
2.5.5.
Melyek a programfejlesztési támogatás fő funkciói?
2.5.6.
Melyek a szoftver projekt fejlődési lépései?
2.5.7.
Mi a szövegszerkesztő?
2.5.8.
Milyen nyelvi eszközök vannak?
2.5.9.
Mi a szerepük a programkönyvtáraknak?
2.5.10.
Mi a tárgyprogram és mi a szerepe?
2.5.11.
Mi a kapcsolatszerkesztő?
2.5.12.
Mit csinál a betöltő?
2.5.13.
Mi a nyomkövetés?
2.5.14.
Milyen módon veheti igénybe a programozó az operációs rendszer szolgáltatásait?
2.5.15.
Milyen tulajdonságai vannak az újraindítható programoknak?
2.5.16.
Mi az integrációs teszt?
2.5.17.
Melyek az alkalmazói támogatás fő funkciói?
2.5.18.
Milyen vezérlőnyelveket használnak?
2.5.19.
Mi a szerepe a segédprogramoknak?
2. Mit nevezünk alkalmazási programoknak?
OS03V06.RTF,2KI.4.16.ZSP, végleges
3. AZ OPERÁCIÓS RENDSZEREK OSZTÁLYOZÁSA
3.1. Osztályozási elvek Az operációs rendszerek sok tekintetben különbözhetnek egymástól. A felhasználói igények és a különféle szolgáltatások színvonala, a rendszervezérlés módja, a hardverréteg tulajdonságai mind olyan ismérvek, melyek alapján a rendszereket osztályozni lehetne. A "nagygépes", "kisgépes" és "mikrogépes" csoportosítás például a hardvert helyezi előtérbe, de nem mond semmit a rendszer működéséről. Ha "parancsvezérelt" és "eseményvezérelt" rendszerekről beszélünk, túl tág csoportokat képezünk, megint csak egyetlen ismérv alapján. Könnyen belátható, hogy nem egyszerű csoportosításra, hanem több szempont szerint felépíthető taxonómiára van szükség. A sok lehetséges szempont közül legalább a következőket célszerű figyelembe venni: * * * * *
a felhasználók száma (egy- vagy többfelhasználós), a multiprogramozás foka (egy- vagy többáramú), az elérés módja (kötegelt, interaktív és valós idejű), a hardver mérete (nagy-, kis- és mikrogépes), a rendszer struktúrája (centralizált, elosztott vagy hálózati).
A hagyományok alapján használatos a következő felosztás: * * * * * * * *
egyfelhasználós (eredetileg kötegelt!), kötegelt multiprogramozott, időosztásos, tranzakciós, valós idejű, többcélú, elosztott és hálózati.
A felhasználás jellege alapján megkülönböztethetünk még: * * * * * *
ügyviteli adatfeldolgozó rendszereket, tranzakciós és lekérdező rendszereket, folyamatvezérlő rendszereket, ipari és tervezői munkaállomásokat, programfejlesztő környezeteket (pl. UNIX) és személyi számítógépeket.
A gép mérete szerinti elemzést előre vesszük. A gépméretek és a lehetséges üzemmódok között ugyanis elég egyértelmű összefüggés alakult ki a történelmi körülmények folytán.
Nagygépes rendszerek A nagygépes rendszerek kiépítése igen költséges (volt főleg régen, de még ma is az). Ennek következtében törekednek a jó kihasználásra. Ráadásul a rendszerterhelés (angolul: work load) jellege olyan, hogy független forrásból származó, eltérő karakterisztikájú feladatokat dolgoznak fel rajtuk. Mindezek következménye: * * * *
Fontos feladat jut az ütemező algoritmusoknak. Jelentős "önadminisztrációs" készségre van szükség. Egyidejűleg sokféle hozzáférési mód lehetséges. Sokszínű szolgáltatáshalmaz áll rendelkezésre (adatbázis-kezelők, integrált alkalmazói rendszerek stb.).
A nagygépes rendszerek költségérzékenységének fő következménye, hogy döntő többségben többcélú üzemmódban üzemelnek. A nagygépes rendszerek strukturális sajátosságai: Hardver: * * * *
aszinkron átviteli csatornák, több, esetleg specializált processzor, gazdag, nagy teljesítményű perifériaválaszték, nagy fokú konfigurálhatóság.
Szoftver: * * * * * *
komplex kezelőrendszerek, amelyeknek jelentős a tár- és időigénye, jelentős erőforrások lekötése a rendszer teljesítőképességének növelése érdekében, intenzív törekvés az erőforrások kihasználására, nagy fokú berendezés-függetlenség biztosítása, dinamikus ütemező és erőforrás-kijelölő algoritmusok, különböző interfészek gazdag választéka (operátori, rendszerprogramozói, magas szintű nyelvi, alkalmazói, alrendszeri, virtuális terminál stb.).
Kisszámítógépes (minigépes) rendszerek A minigépes rendszerek kiépítése kevésbé költséges. Keletkezésük éppen ezzel kapcsolatos, mint ahogy arról az 1.5. fejezetben már volt szó. A Digital Equipment Corporation (DEC) cég ott említett, lecsupaszított gépein periféria gyanánt kezdetben csak egy TELETYPE telexírógép volt, ami önmagában négy perifériát tudott biztosítani: bemenetet az írógép billentyűzetéről és a papírszalag-olvasóról, valamint kimenetet az írógépen és a papírszalag-lyukasztón. A programokat papírszalagon tárolták, és ha szükség volt rájuk, mindig be kellett olvasni őket a lassú TELETYPE olvasón. Ezt csak úgy lehetett elviselni, ha erre nem túl gyakran volt szükség. Minthogy ezek a csupasz gépek automatikák részeiként szerepeltek, ez a feltétel könnyen teljesült. A számítógépet (az áramkimaradásoktól eltekintve) csak a reggeli üzemkezdetkor kellett feltölteni a folyamatvezérlő programmal, amelyet elindítás után csak este kellett leállítani. A szükséges programokat nem is e gépeken fejlesztették, jóllehet élesben kipróbálni csak a célgépen lehetett. Ahogy a felhasználók étvágya nőtt, úgy növekedett a minigépek teljesítménye is. Ma már a nagygépek kategóriájába is betörtek -- a TELETYPE időszaktól kezdve -- eredendően interaktív kapcsolatot biztosító, felhasználóbarát tulajdonságaiknak köszönhetően. Minthogy a minigépes környezetek kiépítése kevésbé költséges, nem okoz akkora problémát a
kihasználatlanságból eredő veszteség. Továbbá -- mint a történelmi előzményekből látható -jellemző a dedikált (adott célnak szentelt) alkalmazás. Ilyenkor a számítógépet befogadó rendszer céljai előnyben részesülnek. Az egyszerűbb alkalmazási igények és a szűk erőforrások miatt a minigépes operációs rendszer (ha egyáltalán használnak ilyet az adott alkalmazásban) egyszerűsített funkciókat valósít meg egyszerű algoritmusok alapján. A felhasználói körre és a várakozást nehezen vagy egyáltalán nem tűrő alkalmazásra tekintettel egyszerű, mindenképpen jelenlétes, interaktív kezelést tesz lehetővé. A jellegzetes kapcsolattartási eszköz a terminál. A dedikált minigépes operációs rendszerek jórészt fix parancskészlettel dolgoznak. A parancskészlet valamilyen egyszerű állománykezelést és korlátozott adatlekérdezési lehetőséget biztosít a célrendszer állapotának vezérlése mellett. A többcélú minigépes operációs rendszerek (a nagygépesekhez képest) csökkentett szolgáltatásokkal rendelkeznek, így például a perifériákat és a programokat manuálisan kell hozzárendelni egymáshoz, valamint a multiprogramozást csak egyfelhasználós többáramú (multitasking) üzemmódban engedik meg. A minigépes hardverek kapacitásának rohamos növekedésével ez a korlát egyre kevésbé jellemző. A minigépeken ma már nagy teljesítményűnek mondható operációs rendszerek használhatók. Ilyen például a PDP-11 RSX családja, valamint ennek VAX gépekre továbbfejlesztett változata, a VMS és az igazán integrált szoftverfejlesztő rendszert képező, portábilis (hordozható) UNIX operációs rendszer. Mikroszámítógépes rendszerek A mikrogépes operációs rendszerekkel kapcsolatban -- a szűk erőforrások miatt -- megismétlődött az, ami a minigépes történelemben egyszer már lezajlott. De az az óriási különbség, hogy a gépeket eleve emberek személyi használatára szánták, ami igen speciális, dedikált alkalmazás. Lényegében egyáltalán nem kell törődni a kihasználatlanságból eredő veszteségekkel. Ez egyszerűen magánügy. Ugyanakkor fontos a minél egyszerűbb felhasználói interfész a számítástechnikai ismeretekkel nem rendelkező, a számítástechnikai részletekkel törődni nem akaró felhasználók biztonságos és kényelmes kiszolgálására. A korai személyi számítógépek tényleg szűk erőforrásokkal rendelkeztek, továbbá az emberi környezetben -- kezdetben -- nem volt jellemző a több esemény egyidejű észlelésének igénye sem. Ezért magától értetődő a -- még a minigépekhez képest is nagy visszalépést jelentő -- egyfelhasználós egyáramú operációs rendszerek visszatérése a számítástechnika őskorából. A kialakított rendszerek azonban koncepciózusabbak voltak, mint őseik. Itt említhetjük meg ismételten a CP/M-et, amely bevezette a perifériaelfedést a BIOS (Binary Input Output System -- bináris bemeneti-kimeneti rendszer) és a rárétegzett BDOS (Basic Disk Operating System -- lemezes operációs rendszermag) megalkotásával. Ezek eredeti, nem máshonnan másolt ötletek voltak, így jelentős mértékben gazdagították az operációs rendszerek tudományát. Néhány ötletet persze örököltek, méghozzá inkább a minigépektől, mert azoknak volt elég jól hasznosítható interaktív tapasztalatuk. Az egyfelhasználós egyáramú mikrogépes operációs rendszerek közül messzemenően kiemelkedik a PC/MS--DOS, bár sikere sok tekintetben a 8 bites családon szintén sikeres CP/M-en, és a minigépes UNIX-on alapul. Ma már a mikrogépek sem igazán mikrók. A fejlődés talán még viharosabb, mint a minikategóriában. A minik tulajdonképpen kettős szorítóba kerültek. Alulról a mikrók támadják őket, felülről a nagyok védik foggal-körömmel a területüket. A mikrókat ma már nagy teljesítményű UNIX operációs rendszerekkel is üzemeltetik, ráadásul a lokális hálózatok csodafegyverével igen ügyesen küzdik le az egyfelhasználós rendszerekből eredő korlátokat, s haladnak a kihasználtsági problémákon is segítő elosztott rendszerek irányába. Itt említjük meg, hogy a PC/MS--DOS világ az OS/2 megjelenésével átfejlődhet az egyfelhasználós többáramú (multitasking) üzemmódba, amit
korábban csak a minik biztosítottak.
3.2. Egyfelhasználós rendszerek Az ötvenes évek második felében a hardver ára a fejlett országokban is többszörösen meghaladta a vele kiváltható emberi munka árát, ezért az volt a legfontosabb feladat, hogy a számítógép-rendszert folyamatosan ellássák munkával. Ezek a drága gépek azonban elég lassúak voltak. Egyetlen munkát is csak lassacskán tudtak megoldani, ezért természetesen egyidejűleg csak egy felhasználó használhatta a gépet. (Érdekes, hogy a konkurens üzemmód sem Babbagenél, sem Neumann Jánosnál, sem Turingnál nem merült fel! Teljesen a mi korunk terméke, akár a megszakítás vagy a veremtár.) +----------------------------------+ | | | A f e l h a s z n á l ó | | t e r ü l e t e | | | | | | | | | +----------------------------------+ | V e z é r l ő á r a m | | o l v a s ó | +----------------------------------+ | M u n k a s o r | +----------------------------------+ | F i z i k a i B / K | | r u t i n o k | +----------------------------------+ | M e g s z a k í t á s i | | v e k t o r o k | +----------------------------------+
A M O N I T O R
3.1. ábra. Egyfelhasználós rendszer tárfelosztása A hatékony használatot kötegelés alkalmazásával próbálták elérni. A megoldandó munkákat (job) lyukkártyára rögzítették, és a megfelelő vezérlő információval együtt csomagokba összerakva a feldolgozás indulásakor a kártyaolvasóba helyezték. A munkaköteget viszonylag egyszerű operációs rendszer (amit gyakran monitornak is neveztek) fogadta. Egy tipikus munka volt például a FORTRAN fordító hívása, majd az assembler hívása és a kapott tárgyprogram elindítása. Minden munka befejezése után a monitor kapta vissza a vezérlést, és beolvasta a kötegből (batch) a következő munkát. A kötegelést a gépteremben az operátor tovább folytatta, összegyűjtve külön kötegbe a FORTRAN, külön kötegbe a COBOL stb. munkákat, hogy ne kelljen annyit cserélgetni a gépben a fordítóprogramokat. Ez a kézi előütemezési lehetőség alapozta meg a géptermi operátorok szakmáját, és az üzemeltetési osztály létjogosultságát. A gépteremben otthonosan mozgó operátor aztán a hatékony gépkihasználásra hivatkozva kiszorította a gépteremből, a korábban a gépi futásoknál mindig jelenlévő, programozót. A kötegelt rendszer tehát kezdettől fogva akadályozta a
programozási munka interaktivitását. A ma használatos technikák közül már az egyfelhasználós kötegelt rendszerekben megjelent a könyvtárszervezés, a programok áthelyezhetősége és a perifériafüggetlenség elve is. A programkönyvtár kártyán, papír-, majd mágnesszalagon tárolt és egy konkrét programozási nyelvhez tartozó általános szubrutinokat tartalmazott. Az áthelyezhetőség azt tette lehetővé, hogy a könyvtári programokat a tár tetszőleges helyére betöltve végre lehetett hajtani (a különböző méretű programok mellett mindig máshol maradt szabad hely a könyvtári rutinnak!). A fejlődés során ezek a rendszerek elavultak, helyüket átadták a többfelhasználós rendszereknek, de érdekes módon -- mint korábban már említettük -- a személyi számítógépek megjelenése óta (természetesen új formában) ismét használatba kerültek. Mivel a hardver ma már olcsó, nem a gép munkával való ellátása, hanem a felhasználó minél jobb kiszolgálása a cél. Ezt párbeszédes, barátságosan működő, segítőkész operációs rendszerrel lehet a legjobban elérni. Az egyfelhasználós rendszerek reneszánszában a CP/M (8 bites processzorok), az MS--DOS és a CP/M-86 (16 bites INTEL processzorok) terjedt el legjobban. Különösen nagy kényelmet (de kisebb hatékonyságot) nyújtanak a többszintű menürendszerrel, a menü tételeit ábrákkal (ikonokkal) kifejező, a feladatválasztást pedig egyszerű rámutatással megoldó, grafikus interfésszel felszerelt rendszerek (például Apple Macintosh). Ezek különösen kezdő felhasználóknak adnak gyors sikerélményt.
3.3. A multiprogramozás alapelve Már a hatvanas évek elején nyilvánvalóvá vált, hogy a felhasználók soros kiszolgálása nem képes sem a központi egység, sem a perifériák folyamatos leterhelésére. Keresték a kiutat. Az alapötlet a kötegelt üzem keretei között született meg: megfigyelték, hogy egy munka (job) végrehajtása folyamán gyakran várni kell valamire (pl. B/K művelet befejezése). Monoprogramozásnál a központi egység ilyenkor egyszerűen nem csinál semmi hasznosat, multiprogramozásnál viszont az operációs rendszer átkapcsol a következő munkára. Az átkapcsolás -- amennyiben az új munka is várakozási állapotba kerül -- további munkák indítását is eredményezheti. Amikor a felfüggesztett munkák közül valamelyik folytathatóvá válik, akkor azt folytatni kell -- esetleg az éppen aktív munka felfüggesztése árán is. Mivel a multiprogramozásnál gyakori, hogy a tárban több program tartózkodik, de ezek közül csak egy aktív, az épp futó program többitől való megkülönböztetésére bevezették a "folyamat" (angolul: process) fogalmát. Ez a program dinamikus megfelelője a számítógéprendszerben: program működő állapotban. A multiprogramozás alapelve: a kényszerű várakozási idők kihasználása úgy, hogy a központi egység használatát átkapcsolgatjuk a futóképes munkák között valamilyen ütemezési stratégiával. Így a helyzet pontosan olyan, mint amit a Bevezetésben a szimultán konkurens folyamatok kapcsán már említettünk. Van egy vezérlőfolyamat, az operációs rendszer (alsó szintű) ütemezője, ami a vele párhuzamosan futó folyamatok (futó programok) haladását irányítja. A folyamatok a közös, de csak egyszeresen használható központiegység-erőforráson osztozkodnak. Az operációs rendszernek más erőforrások elosztását is meg kell oldania. A többszörösen felhasználható erőforrások ütemezése érezhetően elég bonyolult. Foglalkozni kell két hagyományosan elterjedt multiprogramozási fogalom jelentésével. Multitaskingnak (többfeladatos üzemnek) nevezzük azt, ha egyfelhasználós környezetben lehet multiprogramozást megvalósítani. Ilyenkor az operációs rendszer egyazon felhasználó több feladatának konkurens végrehajtását támogatja, ezért szokták magyarra többfeladatos üzemmódként fordítani, de ez nem fejezi ki az egyfelhasználós jelleget. Mi úgy érezzük, hogy csak az
egyfelhasználós, többáramú jelzőkkel lehet elég jól jellemezni ezt az (OS/2 kapcsán a PC világban is hirtelen elég nagy jelentőségre szert tett) üzemmódot. Az irodalom úgy definiálja a multitaskingot, mint amely ugyanazon alkalmazáshoz tartozó rutinok aszinkron végrehajtására képes, de a futások tervezéséért, és a szinkronizálásért a felhasználó a felelős(!). (Az OS/2 multitasking lehetőségei azonban már az itt meghatározott, hagyományos fogalomhoz képest fejlettebbek, mert az OS/2 segíti az aszinkron környezet szinkronizálását.) Ezzel szemben a multiuser (többfelhasználós) multiprogramozás olyan operációs rendszeri üzemmód, amely különböző alkalmazásokhoz tartozó rutinok aszinkron végrehajtására képes, és a futások tervezését és szinkronizálását az operációs rendszer végzi. Vannak olyan operációs rendszerek, amelyek mind a két típust támogatják egyidejűleg (IBM 360/370 OS, UNIX stb.).
3.4. Multiprogramozott rendszerek 3.4.1. Spooling technika Bár multiprogramozás már mágnesszalagos rendszereknél is létezett (pl. az ICT 1900-as gépcsalád a 60-s évek első felében), igazi fejlődés akkor következett be, amikor a lemeztárak elterjedtek. Ez főleg annak köszönhető, hogy a mágneslemezeken nagy, gyorsan elérhető és közvetlenül címezhető állományokat lehetett tárolni. Általános fejlődés indult a rendszerek aszinkron működése terén is. A megszakítás, a privilegizált állapot és a védelem jórészt átkerültek a hardverrétegbe, és ezzel nagymértékben gyorsultak. ’Hardver’ (off-line) SPOOLING ________ Lassú beolvasás __ / Kártya-| +-------+ / \ Mágnesszalag | olvasó |---->>| CPU 1 |---->>( 1 ) tekercs (spulni) .________| +-------+ \__/___ | +---------------------------+ Átvitel nagygépre | V_ Gyors BE/KI-vitel __ / \ +-------+ / \ Mágnesszalag ( 2 )---->>| CPU 2 |---->>( 3 ) tekercs \__/___ +-------+ \__/___ | +---------------------------+ Átvitel kiíróra | V_ Lassú kiíratás +----------+ / \ +-------+ | Sor| ( 3 )---->>| CPU 3 |---->>| nyomtató | \__/___ +-------+ \____----\| ’Szoftver’ (on-line) SPOOLING .-----------. \___________/ | Diszk | \__^_|__^_|_/ ^ | ^ | | | | |
| | | | | V | V .----------+ +--|-V--|-V--+ +----------+ | Rendszer-|-->>--. (2) .-->>---->>| Rendszer-| | olvasó | |(1) CPU (3)| | nyomtató | +----------+ +------------+ \____----\| Három folyamat fut párhuzamosan: . rendszerolvasó (1) . feldolgozó program (2) . rendszernyomtató (3) Ez már (csak kicsit) multiprogramozás 3.2. ábra. Spooling Történetileg elsőként az egyfelhasználós rendszereknél már bevezetett ún. "spooling" technikát kell megemlíteni, amely egy lassú perifériára (pl. sornyomtatóra) való kivitelnél úgy küszöböli ki a központi egység állandó tétlenségét, hogy a kivitel először egy gyorsabb háttértárra (célszerűen lemezre) történik viszonylag rövid idő alatt, majd a főprogram tovább fut, és maga a nyomtatás más feladatokkal párhuzamosan, a központi egység "hulladék idejében" hajtódik végre. (A SPOOL egy betűszó, amely az IBM-től ered: a "Simultaneous Peripheral Operation On-Line" rövidítése, azaz egyidejű, on-line perifériaműködés, ami a korábbi időszak off-line üzemű nyomtatásának ellenpontjaként hangsúlyozza ki a nyomtatás programfutással párhuzamos, on-line voltát.) +-64 K--------------------------------+ | | | 22 K | | | +-------------------------------------+ | 6 K | | | +-------------------------------------+ | 4 K | +-32 K--------------------------------+ | | | | | O p e r á c i ó s | | r e n d s z e r | | 32 K | | | | (kicsit torzított méretek) | +-------------------------------------+ 3.3. ábra. Az IBM OS/MFT tárkezelése
+-256 K---------------+ Programmezőre 192 K maradt | Rezidens terület | Gyakran használt tranziensek +---------------------+ | 3. régió | +---------------------+ | | Munkasor táblázat | 2. szabad mező | | | Sorszám Tár Idő +---------------------+ | 2. régió | 1 60 K 10 +---------------------+ | | 2 120 K 8 | 1. szabad mező | | | 3 24 K 40 +---------------------+ | 1. régió | 4 160 K 30 +--64 K---------------+ | | 5 70 K 12 | S u p e r v i s o r | | | +---------------------+ 3.4. ábra. Az IBM OS/MVT ütemezési viszonyai Ez tulajdonképpen már multiprogramozás, azzal a megszorítással, hogy az egyik program egy speciális rendszerkomponens, a spooling rutin. A világon a legelterjedtebb spooling rendszert az OS/360 alrendszereként Houstonban fejlesztették ki, és HASP-nak (Houston Automatic Spooling Program) nevezik. A HASP mind a kártyaolvasót, mind a nyomtatót kezeli, sőt a távfeldolgozó vonalak késleltetett üzenettovábbítása is a feladatkörébe tartozik (RJE). A multiprogramozott rendszerek meglehetősen bonyolultak. Ha több munkát akarunk futáskész állapotban tartani, akkor azoknak egyszerre kell a tárban lenniük, tehát az eddigieknél komplexebb tárkezelőre van szükség. Ha több munka is készen áll a végrehajtásra , ki kell választani közülük azt, amelyik a központi egység ütemezését megkaphatja. Ezen túlmenően a multiprogramozás vezérlése során gazdálkodni kell a külső egységekkel, kezelni kell a "holtpont" helyzeteket (amikor több felfüggesztett munka olyan eseményre vár, amit csak a munkák valamelyike tudna előidézni, de nem tud), a párhuzamos folyamatok szinkronizálását és különböző védelmi kérdéseket. 3.4.2. Tárkezelési problémák A tárkezeléssel a 10. fejezetben foglalkozunk részletesebben, most inkább csak a megoldandó problémákat vetjük fel. Az természetesnek tűnik, hogy a futtatandó programoknak áthelyezhetőknek kell lenniük. Ezt általános formában a logikai és a fizikai címtartományok bevezetésével lehet megoldani. A kulcskérdés a kettő közötti leképezés. Megoldható a multiprogramozás úgy is, hogy egyidejűleg csak egy munkát tartunk a tárban, amely így az operációs rendszer által szabadon hagyott teljes területet uralhatja. Az ilyen esetben használt technikát "swapping"-nak nevezik (magyarul: cserebere). A swapping lényege, hogy munkaváltáskor a felfüggesztett munkához tartozó teljes tárterületet a háttértárra másolják, és onnan behozzák a következő munkát. Itt háttértárként csak mágneslemez jöhet szóba, bár az első ilyen rendszerekhez még mágnesdobot használtak.
Amikor a swappingnál bevezették a több puffer használatát és a B/K tevékenységek idejét hasznos központiegység-munkával fedték át, eljutottak a többpartíciós multiprogramozáshoz. A tárat több, különböző méretű, egybefüggő részre (partíciókra) osztották, melyek mindegyikében egy végrehajtásra váró munka foglalt helyet. Attól függően, hogy a felosztás rögzített vagy változtatható, beszélünk fix vagy változó particionálásról. Prototípusként az IBM OS/360-ban megvalósított algoritmusokat szokták említeni, melyek megfelelő angol nyelvű rövidítése az MFT (fix partíciók) és az MVT (változó partíciók). Az MFT algoritmus egyszerűbb, de csak akkor hatékony, ha számítógép-rendszerrel folyamatosan majdnem egyforma munkakeverékeket akarunk megoldani. Az MVT bonyolultabb ütemezést és védelmet igényel, viszont bármilyen munkakeverékhez képes alkalmazkodni. Bármilyen ügyes algoritmusokat is dolgoztak ki a particionált tár kezelésére, a tár elaprózódása ellen nem lehetett hatásosan védekezni. Egy bizonyos idő elmúltával, a tárban sok, össze nem függő, apró terület alakult ki, melyeket bár együttes méretük számottevő volt, mégsem lehetett hasznosítani. A megoldást a virtuális tárkezelés megvalósításával bevezetett lapkezelés jelentette. A tárat azonos méretű lapokra osztják (a tipikus lapméret 2 Kbájt). Minden munkához annyi -- nem szükségképpen folytonos fizikai címeken elhelyezkedő -- lapot rendelünk, amennyit igényel. A lapkezelő alrendszer fő feladata a felhasználó logikai tárigényét leképezni a fizikai lapokra. A lapkezelés általánosítása a szegmentálás volt, ami tulajdonképpen változó méretű lapokkal folytatott gazdálkodást jelent. Bevezetésének másik oka az, hogy a lapozás néha az algoritmusokat kellemetlen ponton vágja ketté, így a programrésznek állandóan két lap között kell ugrálnia. Egy új szegmens használatával biztosítható, hogy a kritikus rutin egy lapra kerüljön. Max +-Fizikai tár-+ Változatlan marad | | +---------------+ | | | [3]| | | +-----+ . | [2] v [5]d | | | CPU |->|p|d| +->|f|d|------>| -*-Végcím - | +-----+ | | | | | Eltolás | p|Pointer | | | d|(Displace-| | +---+ | | [4]f | | ment) | |[1]+---+ | +--------->+==*=Alapcím==| | +---+ | A fizikai | | | +---+ | lap címe | | Index +-->+-f-+---+ | | (Pointer) +---+ Címtranszformáció| | +---+ [1]-[5]lépés | | +---+ | | +---+ | | Laptáblázat 0 +-------------+ 3.5. ábra. Lapkezelés
LOGIKAI SZEGMENTÁLÁS
.--------------------PROGRAM--------------------. +----------+ \ +-----------+ | Szubruti-| (1)-(5) | | | | nok | program- | | Főprogram | +--------+ | (4) | szegmens | | (1) | |Verem(2)| +----------+ | +-----------+ +--------+ +----------------+ | +---------------------+ | Szimbólumtábla | | |Dinamikus változók(3)| | (5) | | +---------------------+ +----------------+ / .-----------------------------------------------. HARDVER MEGOLDÁS Max +-Fizikai tár-+ Változatlan marad | | +---------------+ | 2. szegmens | | [3]| |=============| +-----+ . | [2] v [5]d | 5. szegmens | | CPU |->|p|d| +->|f|d|------>| -*-Végcím - | +-----+ | | | | | Eltolás | p|Pointer | | | d|(Displace-| | +-9-+ | | [4]f | | ment) | |[1]+-8-+ | +--------->+==*=Alapcím==| | +-7-+ | A fizikai | | | +-6-+ | szegmens címe| 4. szegmens | Index +-->+-5-+---+ |=============| (Pointer) +-4-+ Címtranszformáció| 3. szegmens | +-3-+ [1]-[5] lépés |=============| +-2-+ | | +-1-+ | 1. szegmens | Szegmenstáblázat 0 +-------------+ / | | | | | | | \
3.6. ábra. Szegmensek
3.4.3. Központi egység elosztás A központi egység ütemezése a számítógép-rendszer legfontosabb erőforrásával való gazdálkodást jelent. A központi egység ütemezése a folyamatok vezérlésére vonatkozik. Első közelítésben egy folyamat új, aktív, várakozó, holtponti vagy befejezett állapotban lehet. *------* *-------* *----------* ( ÚJ ) =======> ( AKTÍV ) =======> ( BEFEJEZETT ) *------* *-------* *----------* ^ | | *---------* | | +---> ( HOLTPONTI ) | | *---------* | v *-------* (VÁRAKOZÓ ) *-------* 3.7. ábra. Folyamatállapot diagram Az ütemezést a folyamatok különböző sorokba való rendezésével és a megfelelő sorkezelő algoritmusok segítségével oldják meg. Az aktív és várakozó folyamatok az ún. készenléti sorba kerülnek. Ezenkívül minden B/K egységhez tartozik egy sor, amely az egységre váró folyamatokra mutat. Az ütemezés két, esetleg három szinten megy végbe. A magas szintű ütemező a külső tárolón várakozó munkákból kiválasztja a készenléti sorba kerülőket, az alacsony szintű (központi egység) ütemező pedig ebből a sorból aktivizál egy-egy folyamatot. A magas szintű, és az ún. közbenső ütemező célja megfelelő, vagyis a rendszert egyenletesen terhelő munkakeverék összeállítása, amelyből azután a központi egység (alacsony szintű) ütemezője hatékonyan ellátja munkával a rendszert. Erre sokféle algoritmus létezik: * * * *
előbb jött -- előbb fut, a legrövidebb előnyben, prioritás alapú vezérlés, körbenjárásos üzem.
Az algoritmusok a 9. fejezetben megtalálhatók. Amint az várható, nincs optimális központiegységütemező, amely tetszőleges munkakeverékre egyformán jó eredményt adna. A központi egységhez hasonlóan a külső egységek ütemezése is sorok alapján történik. Az ütemezésnek elsősorban a nagy kapacitású, mozgófejes mágneslemezeknél van nagy jelentősége. Több algoritmus ismeretes, közös vonásuk, hogy a működés során igyekeznek a fejmozgatást minimalizálni, mert ez a legidőigényesebb tevékenység. A rögzített fejes lemezek, illetve mágnesdobok ütemezésénél fejmozgás nincs, itt az ún. holt időt (ami alatt a lemez kívánt pontja az olvasófej alá fordul) kell minimalizálni. 3.4.4. A holtpontok problémája A holtpont elkerülése meglehetősen bonyolult algoritmust igényel. Első lépésben meg kell keresni azon feltételeket, amelyek együttes teljesülése szükséges a holtpont beállásához. Amint ezt a 8. fejezetben látni fogjuk, egy négy feltételből álló, kissé redundáns szabályhalmaz elegendő erre a célra. Ezután a holtpontokat két alapvető stratégia szerint kezelhetjük: a szükséges feltételek ellenőrzött elkerülésével biztosítjuk, hogy holtpont ne álljon be; vagy csak a holtpont esetleges bekövetkezését figyeljük, és ebből megpróbáljuk a rendszert feléleszteni. A párhuzamos folyamatok kezelésének alapproblémája: mikor lehet egy programban két utasítást
párhuzamosan végrehajtani úgy, hogy a program a végrehajtási sorrendtől függetlenül azonos eredményeket produkáljon? A gyakorlati megoldások a programozási nyelvek körében keresendők. A két legismertebb megoldás a "fork -- join", illetve a "parbegin -- parend" utasítások használata (ld. 12. fejezet). Ha a párhuzamos folyamatok programozása megoldott, felmerül a folyamatok holtpontjának problémája, amit "kölcsönös kizárás"-nak neveznek, és a párhuzamos folyamatok szinkronizációjával kerülhető el, amelynek eszközei a Dijkstra által bevezetett szemaforok lehetnek. 3.4.5. Védelmi kérdések A védelmi kérdések az operációs rendszeren belül azért játszanak fontos szerepet, mert a sok, egymástól függetlenül vagy együttműködve lezajló folyamat mindegyikét meg kell védeni a többiek nemkívánatos mellékhatásától. E célra több mechanizmus szolgál (ld. 11. fejezet), amelyek azt igyekeznek lehetővé tenni, hogy az állományokat, a társzegmenseket, a központi egységet és egyéb erőforrásokat csak olyan folyamatok kezelhessék, melyek az operációs rendszertől kaptak erre megfelelő "felhatalmazást". Például az állományok rendszerében a hozzáférést úgy kell szabályozni, hogy az állomány tulajdonosának a joga legyen azt előírni, hogy ki férhet hozzá az állományaihoz. A rendszer órája pedig azt hivatott biztosítani, hogy egyetlen folyamat se sajátíthassa ki korlátlan időre a központi egységet.
3.5. Kötegelt (batch) rendszerek A kötegelt elnevezés tulajdonképpen -- az egyfelhasználós rendszerek korai időszakából származó üzemmódot figyelembe véve -- a számítógépes rendszerhez való hozzáférés módjából ered. Az operációs rendszer egymástól független munkák végrehajtására vonatkozó igényeket fogad, s ezekből olyan kötegeket (angol nevük batch) hoz létre, melyeket azután a körülményeknek megfelelő időpontban hajt végre. Az igények közlésére kezdetben lyukkártyákat (3.8. ábra), később más eszközöket (terminálokat, távközlési vonalakat stb.) használtak. ------------------------------------+ /$END . . . . . . . . . . . . . . . .| / A PROGRAM ADATAI /|| -------------------------------------+ || /$RUN | || --------------------------------------+ | |+ /$LOAD | | + ---------------------------------------+ | |/ / . . . . A PROGRAM . . . . . . . . . ./| |-+ / . . . . FORRÁSKÓDJA . . . . . . . . ./ | | ---------------------------------------+ |-+ /$FTN | | | | + --------------------------------------+ | / /$JOB | |/ | |--+ | | | | +--------------------------------------+ 3.8. ábra. Kötegelt rendszert vezérlő kártyacsomag
A kötegelt rendszerek alapvető sajátsága, hogy a programozókat elválasztja a géptől -- általában a géptermekből is kitiltották őket -- a számítógépes rendszer kezelését pedig az e célra kiképzett gépkezelők (operátorok) végzik. A programozó dolga az, hogy egy futás eredményeiből minél gyorsabban előállítsa a következő gépi futás anyagát, hiszen elsődleges cél a számítógéprendszer folyamatos leterhelése. Ezt már az egyfelhasználós rendszereknél is meg tudták közelíteni, de csak a multiprogramozás elterjedése, valamint egyes tevékenységek párhuzamossá tétele hozott igazi eredményt. A programozó által összeállított köteg tulajdonképpen "vezérlőnyelven" (munkavezérlő nyelv) írott program, amely a végrehajtásához szükséges adatokat vagy az ezek tárolási helyét megadó utalásokat is tartalmazza. A kötegelt rendszerek vezérlőnyelve horizontális jellegű, mert kevés számú parancsból építkezik (vertikális struktúra), de az egyes parancsok igen bonyolultan paraméterezhetők (horizontális struktúra). A kötegelt rendszerek fejlettségi szintjét elég jól jellemzi az erőforrás-kezelés automatizálásának, és dinamikusságának mértéke (ld. 8. fejezet), s ezen belül különösen fontos a tárkezelés (ld. 10. fejezet). A fix, majd a változó partíciók használata után a virtuális címzés jelentette a fejlődést. A kevésbé fejlett rendszerek túl hosszú ideig lekötik a folyamatok számára az általuk igényelt erőforrásokat, ami rontja az erőforrások kihasználtságát, de javíthatja az átbocsátó képességet az alacsonyabb rendszeradminisztrációs terhelés miatt. A kötegelt rendszerek azonban a fejlesztők minden igyekezete ellenére sem tudták kielégíteni a változó felhasználói igényeket és ezen még a nagy rendszerekhez illesztett telekommunikációs lehetőségek sem segítettek. Egyes területek, elsősorban az új szoftver rendszerek fejlesztései nem tudták elviselni azt a két forduló közötti néhány órás várakozást sem, amit csak a jól felszerelt és jól szervezett számítóközpontok biztosítottak. A fejlesztők teljesítményét és munkájuk minőségét egyaránt javítja, ha a számítógéprendszerrel állandó közvetlen kapcsolatban (angolul: on-line) vannak. Ilyenkor ugyan a hardver nagyrészt tétlenkedik, de az ebből származó anyagi veszteséget azonban meghaladja a fejlesztett termék jobb minőségéből és rövidebb fejlesztési idejéből származtatható nyereség. Amikor a hardverárak ezt már lehetővé tették -- nem véletlenül először a kisgépek körében --, megjelentek a különböző interaktív rendszerek, illetve a meglévőket on-line hozzáféréssel igyekeztek kiegészíteni. Ilyen bővítést hajtott végre például az IBM is a TSO (Timesharing Option) alrendszerének bevezetésével. Ma a nagygépes operációs rendszerekre általában a kötegelt -- interaktív vegyes üzemmód a jellemző. Az üzemszerű, ismétlődő feldolgozások kötegelt módon futnak, a fejlesztés pedig jórészt on-line formában zajlik.
3.6. Időosztásos rendszerek A kötegelt rendszerek számára is sokat jelentett a kizárólag soros hozzáférést biztosító lyukkártya és mágnesszalag után a közvetlen elérést nyújtó lemezek elterjedése. A kötegelést az operációs rendszer végezhette, hiszen biztosított volt a munkákhoz való tetszőleges sorrendű hozzáférés. Ennek dacára a kötegelt rendszerek két alapvető hátránya megmaradt: * Nincs interakció a programozó és a rendszer között a munka végrehajtása közben. Mivel sok esetben egy feladat következő lépése az előzőtől függ (egy program futása pl. a fordítás sikerétől), a programozónak minden eshetőségről előre intézkednie kell, ami többletmunka és gyakran igen bonyolult. * A programok hibáit statikusan, tárkivonatokból (angolul dump) kell megtalálni, ami ugyan inspirálhatja a fegyelmezett, módszeres programírást és tesztelést, de mindenképpen csökkenti a fejlesztők teljesítményét.
Ezeken és egyéb problémákon igyekeznek segíteni az interaktív rendszerek, ahol a felhasználó állandó és folyamatos kapcsolatban áll a programjával annak írása és végrehajtása során. A rendszer általában billentyűzetből és képernyőből álló terminálon át bevitt parancsok segítségével vezérelhető. A parancsok azonnal végrehajtódnak, és az eredménytől függően a programozó "online" dönt a következő lépésről. A hangsúly a gyors válaszon van. Az on-line rendszerek vezérlőnyelvét inkább parancsnyelvnek nevezik, mert kiadásuk után a rendszer rögtön reagál. Ez olyan, mintha csak a parancsoknak engedelmeskedne. Az on-line parancsnyelvek abban különböznek a kötegelt rendszerek vezérlőnyelvétől, hogy vertikális jellegűek. Sok parancsból építkeznek (vertikális struktúra), és az egyes parancsok paraméterezése általában egyszerű (horizontális struktúra). (Lehet, hogy a VAX/VMS és a TSO ismerői egy kicsit ingatják a fejüket. Sajnos, mindkét vezérlőnyelv korai, kötegelt vezérlőnyelvi beidegzések nyomait viseli magán. A "tiszta" példa a UNIX, illetve a még frissebb MS--DOS. – Azóta a UNIX is elhorizontálosodott!! – ZSP, 2001). Az időosztásos (angolul: time-sharing) operációs rendszer célja, hogy a számítógéprendszer interaktív használatát több felhasználó számára párhuzamosan (és ezért csökkentett költséggel) lehetővé tegye. Ennek érdekében az operációs rendszer a központi egység megfelelő ütemezésével és multiprogramozás alkalmazásával a gép idejét több felhasználó között osztja meg. Különösen programfejlesztésnél igaz, hogy az éppen aktív folyamat egy rövid időn belül befejeződik, vagy B/ K műveletet igényel. Mivel az interaktív adatbevitel gyakran billentyűzetről folyik, ami a gép szempontjából igen lassú, a rendszer gyakran váltogathatja a felhasználók kiszolgálását, mégis mindenki úgy érzi, hogy egyedül dolgozik. Az időosztásos rendszerek az erőforrások igazságos elosztása érdekében védekeznek az ellen, hogy egy folyamat (véletlenül vagy szándékosan) korlátlan ideig aktív maradhasson. Erre a célra általában a gép órájának megszakítását használják olymódon, hogy az órajel valamilyen többszörösével kifejezhető "időszelet" elmúltával másik folyamatra kapcsolnak át. Az időszelet nagysága függhet az alkalmazási környezettől és a pillanatnyi terheléstől is. Az időosztás elve már 1960-ban ismert volt, de a szoftver bonyolultsága és a technikai színvonal miatt elterjedni még nem tudott. Általános gyakorlattá válása mintegy tíz évig váratott magára, azóta viszont népszerűsége egyre növekszik. A kötegelt rendszerek időosztásos alrendszerrel való bővítése mellett természetesen az időosztásos rendszerekben is gyakran gondoskodnak kötegelt üzemmódról a rutinszerűen ismétlődő munkák végrehajtásának egyszerűsítése érdekében. (Ilyenek például a PDP 11-es RSX-ben végrehajtható ".CMD" kiterjesztésű állományok, amelynek ötletét később átvették az egyfelhasználós, egyáramú, interaktív mikrogépes operációs rendszerek -CP/M, MS-DOS -- is. Az RSX-ben speciális kötegelt vezérlő alrendszert (Batch and Queue Manager) lehet használni a háttérben futó alkalmazások kezelésére. Amíg ezek a háttérmunkák az alkalmazó segédlete nélkül függetlenül futnak, addig az alkalmazó a terminálon (tehát az előtérben) interaktív üzemmódban dolgozhat. Az első közismertté vált időosztásos rendszert, a MULTICS-ot 1965 táján, egy amerikai egyetemen fejlesztették ki a General Electric GE--645 típusú nagygépére PL/1 nyelven. A fejlődés következő állomása a kisgépes kategória volt. Itt az időosztásos rendszerek "prototípusa" a UNIX, sok eredeti megoldás mellett jócskán merített a MULTICS ötleteiből és más, korábbi DEC operációs rendszerekből is. A Bell Laboratóriumban kidolgozott rendszer első elterjedt változata eredetileg a DEC PDP--11 családjára készült. Azóta a UNIX-szerű operációs rendszerek halmaza nagyon kibővült; a mikrogépek megjelenésekor pedig a CP/M, MP/M majd az MS--DOS egyaránt sokat kölcsönzött a UNIX-tól. A szintén időosztásos OS/2 sajnos újabb ötleteket nem vett át, programozói interfésze pedig már merész, új utakon jár (magasszintű-nyelv orientált szolgáltatáshívások), bár a futás alatti szubrutinkönyvtárát a UNIX bináris programkönyvtári elvének továbbfejlesztéseként vehetjük.
3.7. Valós idejű rendszerek Egyes, speciális feladatok gépesítése támasztotta azokat az igényeket, amelyek a valós idejű operációs rendszerek kialakulásához vezettek. Ezek a rendszerek tulajdonképpen, egyedi alkalmazások vezérlő mechanizmusainak tekinthetők. Az adatok a gépbe érzékelőkről (általában mérőműszerekről) érkeznek. Az operációs rendszer feladata az adatok elemzése és -- szükség esetén -- olyan vezérlő mechanizmusok aktivizálása, melyek befolyásolhatják az érzékelők által mért értékeket. Tipikus valós idejű alkalmazás például a forgalmi rendszerek (közlekedési lámpák) vezérlése, ipari folyamatok, tudományos kísérletek irányítása stb. A valós idejű operációs rendszerek közös jellemzője, hogy a munkák elvégzését szigorú időkorlát köti. Rendszerhibával egyenértékű, ha egy munka nem hajtódik végre a hozzárendelt időkorláton belül. Amíg a kötegelt operációs rendszereknél lényegtelen, az időosztásos rendszereknél fontos, de nem meghatározó, addig a valós idejű rendszereknél az időkorlát döntő jelentőségű. A valós idejű környzetek további fontos tulajdonsága az eseményvezérelt (angolul: event driven) jelleg. Az operációs rendszer nem vezérli a feldolgozást, hanem fogadja és teljesíti a kérelmeket. A kérelmek teljesítését biztosító programokat elterjedt DEC szóhasználattal taszkoknak hívják, de ezek megfelelnek az általunk korábban definiált folyamat fogalmának (programok működés közben). Bár a valós idejű rendszerek logikája az emberi beavatkozással kapcsolatos követelményeket minimalizálni igyekszik, ezek teljesen mégsem nélkülözhetők. Különösen a rendszer paramétereinek beállításakor, az értékhatárok túllépésénél vagy hibás működés esetén van emberi beavatkozásra szükség. A hangsúly nem az erőforrások optimális kihasználásán, hanem a biztonságos üzemen van. A teljesítményparamétereket úgy kell választani, hogy az idő korlátok csúcsterhelés esetén is tarthatók legyenek. A méretezést tehát a csúcsterhelésre végzik. Ennek érdekében gyakori a hardverredundancia és az, hogy a szabvány processzorok egy speciális, módosított változatát alkalmazzák. A teljes alkalmazási rendszerben a számítógépes alrendszer néha alig vehető észre, a programokat általában máshol fejlesztik, ide gyakran már csak megváltoztathatatlan végrehajtható formában, ROM-ba égetve kerülnek. A valós idejű alkalmazások szoftvere a szokásosnál több szempontból is bonyolultabb. Egyrészt az egész programrendszernek -- legalább gyakorlatilag -- hibamentesnek kell lennie, másrészt a programok belövését nem lehet a megszokott módon elvégezni, mivel a próbához szimulálni kell a teljes környezetet az összes bekövetkezhető eseménnyel együtt. Erre azért van szükség, mert hiába működik egy program hibátlanul egy laboratóriumi környezetben, arról is meg kell győződni, hogy minden folyamat akkor is időkorlátján belül marad, ha a rendszer teljes terhelés mellett üzemel.
3.8. Többprocesszoros rendszerek Az igazi többprocesszoros operációs rendszerek felügyelete alatt egynél több központi egység működik, melyek osztoznak a táron és a perifériákon. Az ilyen rendszer nyilvánvaló előnye a nagyobb teljesítmény és a biztonság lenne. Jelenleg azonban sajnos a teljesen általános többprocesszoros operációs rendszerek még váratnak magukra. A meglevő megoldások két fő irányt követnek: * Egy központi processzor több, alárendelt gépet vezérel, amelyek csak korlátozott tevékenységre képesek (master/slave kapcsolat); *
Számítógép-hálózatok, melyekben több számítógéprendszer áll kapcsolatban
egymással üzenetek és adatállományok cseréje útján. Minden gép -- a többitől függetlenül -- a saját operációs rendszerével működik. Az első megoldást már rég alkalmazzák, például úgy, hogy a központi géptől távol elhelyezett kis processzorokat csak a terminálok vezérlésére, és a munkák központba küldésére használnak, ahol azok kötegelt üzemmódban végrehajtódnak. E kihelyezett gépeket RJE (Remote Job Entry) állomásoknak nevezik. Időosztásos rendszereknél is szokásos, hogy egy nagy teljesítményű központi gép köré több kisebb, ún. front-end processzort telepítenek, amelyek csak a terminálokon folyó információ be- és kivitelét bonyolítják. Viszont back-end processzorokat is használnak speciális, bonyolult algoritmusok gyors kiszámítására (ilyenek pl. az INTEL 8086/80?86-os család aritmetikai koprocesszorai, a harci eszközök becsapódási pályáját gyorsan kiszámító berendezések, a mátrixprocesszorok, vagy a sejtszámítógépek stb.).
3.9. Hálózatok és elosztott rendszerek A számítógép-hálózatokban önálló számítógépes rendszerek vesznek részt, melyeket különböző adatátviteli vonalak kapcsolnak össze: közvetlen adatbuszok, telefonvonalak stb. A hálózat célja a feladatok ésszerű megosztása a tagok között, ami nyilvánvaló kölcsönös előnyökkel jár. Erre utal az elosztott vagy osztott (angolul: distributed) elnevezés. Egy számítógép-hálózatot azonban csak akkor mondunk elosztott rendszernek, ha az összekapcsolás nem véletlenszerűen, hanem előre meghatározott cél alapján történik. Az elosztott rendszerben résztvevő számítógép-erőforrások méretüket, teljesítményüket és funkciójukat tekintve igen változatosak lehetnek: mikroprocesszorok, terminálok, kisgépek, nagy, univerzális számítógépek stb. Az egyöntetűség kedvéért ezekre, mint a hálózat csomópontjaira vagy egyszerűen csak mint gépekre hivatkozunk majd. Elosztott rendszerek létrehozását négy fő cél indokolja: az erőforrások megosztása, a sebességnövelés, a megbízhatóság megalapozása és a kommunikáció. Mivel ezek a célok minden elosztott rendszerre vonatkoznak, a tárgyalást velük kezdjük. * Erőforrás-megosztás: Mivel sok, különböző lehetőségekkel felszerelt csomópont kapcsolódik össze, az egyik csomóponton használni lehet olyan erőforrásokat, amelyek helyileg egy másik csomóponton vannak. Például az A gép használhatja a B géphez kapcsolt lézernyomtatót, miközben B dolgozhat az A-ban tárolt adatállományból. * Sebesség növelés: Ha egy nagy volumenű számítási feladatot konkurens módon futtatható részekre lehet bontani, az egyes részek szétoszthatók a csomópontok között és párhuzamosan hajthatók végre. Ezen túlmenően, a túlterhelt csomópontokról a munka egy része más gépekre irányítható (load sharing). * Megbízhatóság: Ha az elosztott rendszer egyik csomópontjában géphiba lép fel, a többi csomópont elvileg működőképes marad. Ha a rendszer több nagy, önálló számítógépből áll, az egyik kiesése nem nagyon zavarhatja a többit. Ha viszont a hálózat sok kis gépből épül fel, melyek mindegyike egy speciális funkciót lát el (pl. állomány kezelés, terminál B/K), egy gép hibája megbéníthatja az egész rendszert. Általában igaz, hogy ha a rendszerbe elegendő redundanciát építettek (mind a hardver, mind az adatok szempont-
jából), egy vagy néhány gép kiesését a hálózat jól elviseli. Különösen bonyolult kérdéskör a hiba automatikus észlelése, áttérés a sérült rendszer üzemére, majd -- a hiba elhárítása után -- visszatérés a normális működésre. * Kommunikáció: Az összekötött csomópontok közötti adatcserét általában a postahivatalok mintájára szervezik meg, és "elektronikus postá"-nak hívják. A hálózat minden felhasználója kap egy "postaládát", amelyhez a csomóponton egyedi név tartozik. Postát bárki küldhet bárkinek a csomóponton belül vagy más csomópontra is. A cím a postaláda és a csomópont nevéből tevődik össze. Az elküldött postákat az operációs rendszer a címzett postaládájában tárolja. Elolvasás után a címzett intézkedhet az üzenet törléséről, tárolásáról, esetleg további címekre való továbbításáról vagy a válaszról. Az elosztott rendszerek csomópontjait többféleképpen lehet összekapcsolni. A különböző konfigurációk kialakításánál elsősorban három fő szempontot szoktak figyelembe venni: * Létesítési költség: Mennyire költséges az egyes csomópontok közötti kapcsolat kiépítése? * Kommunikációs költség: Mennyi ideig tart egy üzenet két csomópont közötti átvitele? * Megbízhatóság: Ha hiba lép fel egy csomópontban vagy egy összekötő vonalban, a rendszer maradék csomópontjai még kapcsolatban maradnak-e egymással? A különböző konfigurációkat gráfokkal ábrázolják, melyek csúcsai a csomópontok, élei pedig a direkt kapcsolatokat reprezentálják. A teljes kapcsolású hálózatban az összes csomópont között közvetlen kapcsolat van. A létesítési költségek nagyok, de a rendszer igen megbízható, és a kommunikációs költségek minimálisak. -{C}----|\ \ / | \ \ / | \ \ / | \ \ {B}----|---------{D} \ \ | \ / | \ ----|----- \/ | \ | \/\ | \ | /\ \ | \ | --- \ \ | \ | / \ \| {A}--------{E} /
3.9. ábra. Teljes kapcsolású hálózat
-{C}----\ \ / \ \ / \ \ / \ \ {B}--------------{D} \ \ | \ \ | \ \ | \ \ | \ \ | \ \| {A} {E} /
3.10. ábra. Részleges kapcsolású hálózat
A részleges kapcsolású hálózatban több direkt kapcsolat hiányzik. Az üzeneteket esetleg közbenső csomópontokon keresztül kell továbbítani. A létesítési költség kisebb, de az üzemelés lassúbb és a megbízhatóság is csökken. A részleges kapcsolású hálózatok speciális esete a csillag- és a gyűrűs hálózat. Mindkettő létesítési költsége a csomópontok számával lineárisan nő. A csillaghálózatban egy központi géphez kapcsolódik a többi csomópont (3.11. ábra). Az üzenetek átvitele egyszerű, de gyakran lassú a központi gép túlterhelése miatt. Ezért ez gyakran kizárólag üzenetkapcsolással foglalkozik. A gyűrűs hálózatban mindegyik csomópont pontosan két másikkal van közvetlen kapcsolatban
(3.12. ábra). Ha a gyűrűben az üzeneteket csak egy irányba lehet küldeni, akkor a kommunikációs költség igen magas lehet; ellenben ha minden csomópont üzenhet mindkét szomszédjának, akkor az üzenetátvitel felgyorsul. {B} | | | | | {H}-------{A}--------{F} / \ / \ / \ / \ / \ {X} {D} 3.11. ábra. Csillaghálózat {D}----{E} \
/ /
\
/
\
/ {C} | | | {B} \
\ {F} | | | {G} / \
/ \
/ \
/ {A}----{H} a)
{D}----{E} / |\ \ / | \ \ / | \ \ / | \ \ {C} | ------{F} | | /| | | / | | | /--- | {B} | / {G} \ | / / \ | / / \ | / / \ |/ / {A}----{H} b)
3.12. ábra. Gyűrűs hálózatok. a) Egyszeres, b) Többszörös Külön meg kell említeni a közös információs busszal rendelkező hálózatokat, ahol a csomópontok közös vonalon át kommunikálnak. A telepítési költség a csomópontok számával arányos, a kommunikáció meglehetősen olcsó, de a busz átbocsátó képessége könnyen szűk keresztmetszetté válhat. A rendszer működését egy-egy csomópont hibája nem zavarja, azonban a közös vonal megbízhatósága létfontosságú. {A} {B} {C} {D} {E} {F} {G} {H} | | | | | | | | | | | | | | | | +-------+--------+-----+------+-----+-------+----+ 3.13. ábra. Busszal rendelkező hálózat
A hálózati rendszereket két nagy csoportra oszthatjuk: számítógép-hálózatok és helyi hálózatok. Bár a felosztás elsősorban a csomópontok földrajzi eloszlására vonatkozik, az eltérő igények nyomot hagytak az operációs rendszerek felépítésén is. A számítógép hálózatok több, önálló gépből állnak, melyek nagy területen (pl. egy ország vagy földrész) szóródnak szét, a helyi hálózatok pedig csak egy épületben vagy épületcsoportban telepített processzorokból állnak.
3.10. Mintapéldák A régi egyfelhasználós rendszerek csak történelmi érdekességgel bírnak. A világszínvonalat már az 50-es években is az IBM képviselte, például a 7094-es rendszerével. Magyarországon az első gépek csak 1960 körül jelentek meg igen változatos összetételben. A többi között angol (Elliott 803), francia (Bull Gamma), szovjet (M3, Ural, Minszk--22) és dán (GIER) gépekkel felszerelt, egyfelhasználós üzemben működő számítóközpontok üzemeltek. A kötegelt rendszerek között klasszikusnak számít -- mint azt már a 2. fejezetben is elemeztük, -- az IBM DOS, illetve OS/360. Ezek sajnos a felhasználók összes lehetséges igényét ki akarták elégíteni, ezért azután jóformán sehol nem adtak különösebben jó megoldást. Az állományrendszerben különböző állománytípus tartozott a fix és változó hosszúságú rekordokhoz, valamint a blokkolt és nem blokkolt állományokhoz. Az állományokat folyamatos címek szerint tárolták, ezért a felhasználónak előre meg kellett becsülni az állomány hosszát. Az igen horizontális munkavezérlő nyelv (JCL) az összes lehetőségre paraméterekkel igyekezett felkészülni, ezért az átlagos felhasználó számára jóformán érthetetlen volt. (Az emiatt fellépő tipikus JCL használat: ellesünk egy-egy vájt fülűtől egy "jó jobot", és azt használjuk nyakra főre, ha jó, ha nem. A nyelv lehetőségeiről pedig lemondunk. De lemondhat az operációs rendszer is arról, hogy nem fogunk pazarolni az erőforrásaival! A felhasználó visszavág a "birodalomnak"!) A tárkezelés alapvető ellentmondásba került az architektúrával: a címzéshez bázisregiszter lehetett használni, de a programok módosíthatták a bázisregisztert, ezért a központi egység abszolút címeket generált. Ez lehetetlenné tette a programok dinamikus áthelyezését, a betöltéstől kezdve a program helyhez kötötté vált. Az OS/MFT fix, az OS/MVT pedig változó partíciókkal dolgozik. Az IBM/370 architektúra virtuális tárral jelent meg, amely szegmentált-lapozott virtuális tárat biztosított. Az OS új változatai azonban ezt a tárat különböző módon kezelték. Az OS/VS1 egyetlen nagy virtuális címtartományt hozott létre, amelyben az OS/MFT-t futtatta. Ebben az operációs rendszer is lapozva futott, akárcsak a felhasználói programok. Az OS/VS2 először az OS/MVT-t futtatta egyetlen virtuális tárban, majd az MVS-nek nevezett második változat (ami még mindig csak egy kötegelt rendszer) adta meg végre minden felhasználónak a saját virtuális tárát. Minden kritika ellenére tény, hogy nagygépeken legnagyobb számban valószínűleg ma is az OS operációs rendszer működik a világon. A többi kötegelt rendszer közül a következőket érdemes kiemelni: Az Atlas operációs rendszert a Manchesteri Egyetemen tervezték az 50-es és 60-as évek fordulóján. Több szép (azóta már közkinccsé vált) technikai megoldást tartalmazott, de tárkezelése különösen előremutató volt. Az akkor még ritka és drága ferrittárból csupán egy kis (16 Kszó), gyors tárat alkalmazott, és egy 98 Kszavas dobbal igen hatékony lapkezelő algoritmust valósított meg. A hardver egy 48 bit szóhosszúságú Ferranti gép volt. A THE operációs rendszer, amely egy EL X8 nevű holland gépen működött (32 K 27 bites szó), Dijkstra és társai nevéhez fűződik. A rendszer szép szoftverstruktúrájával tűnt ki, ami különösen a konkurens folyamatok szemaforokkal való szinkronizációjában és holtpont elkerülő algoritmusában
öltött testet. A THE egyetlen magas szintű programozási nyelve az ALGOL volt. Az időosztásos rendszerek írott történetét általában a MULTICS-al kezdik, pedig ez már egy korábbi, CTSS-nek hívott rendszer továbbfejlesztése volt a 70-es évek elején. A helyszín az MIT (Massachusetts Institute of Technology), a hardver egy GE 645-ös gép, szegmentált lapkezeléses tárral. A MULTICS jóformán teljesen PL/1-ben készült, a forrásszöveg mintegy 300.000 sort tett ki. Több processzoros környezetre is kibővítették, hogy a felhasználók kiszolgálása a központi egység karbantartása alatt is biztosítható legyen. A legsikeresebb időosztásos operációs rendszer a Bell Laboratóriumban PDP gépekre kifejlesztett UNIX, amely sok tekintetben a Multics barátságosabb kisgépes változata. A fejlesztők egyike (D. Ritchie) korábban a MULTICS témán dolgozott. A másik kulcsember, K. Thompson, a PDP gépek elismert szakértője volt. A UNIX tulajdonképpen csak harmadik változatában került a nagyobb nyilvánosság elé, miután a szerzők az általuk erre a célra kidolgozott és C-nek nevezett rendszerprogramozási nyelven újraírták, elsősorban az átvihetőség javítása céljából. Ezzel megnyílt az út a nagyobb PDP modellek, a 11/45, 11/70, majd a VAX-ok felé. A UNIX először az egyetemeken terjedt, és csak 1976-ban került ki szélesebb körbe a Bell Laboratóriumból. A UNIX sok, azóta is korszerűnek számító megoldást tartalmaz. A felhasználóval egyszerű nyelvű, és könnyen cserélhető parancsértelmező (Shell) tart kapcsolatot. Adatkezelése a több szintű faszerkezetet mutató állományrendszeren alapul, amely minden felhasználónak saját alkönyvtár létesítését teszi lehetővé. Az állományokat védeni lehet írás, olvasás és végrehajtás, a katalógusokat írás, olvasás és keresés ellen. Minden adatállomány egyszerűen karakterek sorozata. A perifériák kezelése annyira egységes, amennyire ez megoldható. A UNIX a párhuzamos folyamatok általános kezelését teszi lehetővé. Minden folyamat könnyen hoz létre új folyamatokat. A virtuális tárat a rendszer lapkezeléssel valósítja meg az ún. igény szerinti lapváltás (angolul: demand paging) módszerével. A UNIX-ot programozók tervezték programozók számára, ezért erősen interaktív, és elsősorban a programfejlesztők igényeit igyekszik kielégíteni. A UNIX, bár a minigépekre született, jól megállja a helyét személyi számítógépes operációs rendszernek is. A UNIX tervezői saját igényeik szerint dolgoztak, az algoritmusokat egyszerűségük és nem hatékonyságuk szerint választották. A jól strukturált felépítés sok módosítást motivált, és sok utánzatot ihletett. Ezek közül a professzionális személyi számítógépeken legismertebb a XENIX. A PDP gépek másik -- inkább csak a családon belül népszerű -- operációs rendszere az RSX, melyet VMS néven fejlesztettek tovább a VAX-ra. Ezek is interaktív parancsnyelvű rendszerek, és mindent tudnak, ami egy időosztásos rendszertől elvárható. Az időosztásos operációs rendszerek területéről természetesen az IBM sem szorulhatott ki. Már a 360/67-es (virtuális tárral rendelkező) modellre elindult 1968 körül a TSS/360 fejlesztése. A feladat azonban túl nagynak bizonyult és a késés miatt kiadták az OS/360 egy időosztásos bővítését, a TSO-t, majd az eredetileg egyfelhasználós CMS-t (Cambridge Monitor System). A TSS végül 1973 táján készült el, de megbukott, mivel túl nagy volt és lassú. Amit egy kötegelt rendszernél még elviseltek a felhasználók, az időosztásos rendszernél már nem volt eladható. Azt már korábban említettük, hogy a nagygépek univerzális alkalmazási filozófiája is aláásta a külön időosztásos rendszer létjogosultságát, mert kényelmetlen, és gazdaságtalan állandóan váltogatni a gépen az operációs rendszereket. Az IBM rendszerekben az időosztást ma is főleg a TSO vagy a CMS segítségével valósítják meg.
3.11. Gyakorlatok 3.11.1.
Hogyan jellemezné a következő típusú operációs rendszereket? a) kötegelt b) valósidejű c) időosztásos
3.11.2.
Mi a spooling?
3.11.3.
Mit jelent a kötegelés?
3.11.4.
Mi a multiprogramozás lényege?
3.11.5.
Mit nevezünk swappingnak?
3.11.6.
Melyek a particionált tárkezelés alapesetei?
3.11.7.
Vesse össze a program és a folyamat fogalmát!
3.11.8.
Mi a lapkezelés és a szegmentálás?
3.11.9.
Mit jelent a központi egység ütemezése?
3.11.10.
Hányféle ütemező használatos?
3.11.11.
Mi a virtuális tár és hogyan kezelik az operációs rendszerek?
3.11.12.
Mi a holtpont helyzet és hogy oldhatók meg az ezzel kapcsolatos problémák?
3.11.13.
Ismertesse a párhuzamos folyamatok problémakörét!
3.11.14.
Mi az elosztott rendszerek alapvető célja?
3. Milyen fontosabb hálózatkonfigurációkat ismer?
OS04V06.RTF,2ki.4.16,ZSP
4. MŰVELETI FÁZISOK
Ebben a fejezetben megvizsgáljuk, hogyan oldható meg egy feladat a számítógépes rendszerben, és hogyan viselkedik ezalatt az operációs rendszer. Meghatározzuk a feladat egységét, a munkát, majd elemezzük a jellemző műveleti fázisokat. Megjegyezzük, hogy egy-egy konkrét munka kapcsán nem minden műveleti fázis merül fel.
4.1. A feladat egysége: a munka Az operációs rendszereket alaposan felkészítik arra, hogy szét tudják választani az egyes felhasználók feladatait. Sőt arra is, hogy az egyes felhasználóknak is lehetővé tegyék a különálló feladatok elhatárolását, hogy azok ne keveredhessenek össze. Azt a feladategységet, amelyet a felhasználó különállóan akar kezelni, munkának (angol szóval: job) nevezzük. A kötegelt operációs rendszerekben a korábban már tárgyalt munkavezérlő nyelvek alkalmasak arra, hogy kijelöljék egy munka elejét és végét, valamint a munka végrehajtási lépéseit. Minthogy a korai számítógépeken a kötegelés széleskörűen elterjedt, a számítógépes rendszerekben a munka egységének fogalmát a kötegelt rendszerekben kialakult gyakorlatnak megfelelően alakították ki. A munkát az operációs rendszernek valahogy azonosítania kell. A kötegelt rendszerekben ez a munka elejét jelző munkavezérlő utasításban megadott névvel (job-név, munkanév) történik. Az interaktív környezetben a felhasználók szétválasztását (elvileg) automatikusan biztosítja, hogy minden terminálon más felhasználó jelentkezik be. Így a felhasználó azonosítható azzal a terminállal, amelyen bejelentkezett. Ez viszont olyan megkötéssel járna, hogy egy felhasználó több terminálon nem jelentkezhet be. Emiatt az interaktív rendszerekben a felhasználók azonosítása két adattal történik: egyrészt a terminálszámmal, másrészt a bejelentkezési-, más néven számlázási (account) névvel, amelyet a számítóközpont üzemeltető személyzete ad a felhasználónak akkor, amikor gépidőt vásárol. Az interaktív környezetben a munkák kezdetét nem kell kijelölni. A felhasználó maga határozza meg, hogy mikor kezd új munkába, és azt milyen lépésekre bontja. Így a munkáknak interaktív környezetben nincsen azonosítója sem. Ez akkor is igaz, ha egyes operációs rendszerekben létezik a háttérmunka, a multitasking lehetősége, ami megengedi egy terminálnál ülő felhasználónak, hogy elindítson egy programot, és ne várja ki annak végrehajtódását. Ilyenkor az operációs rendszernek egyidejűleg kell vezérelnie a terminálnál ülő felhasználó több programját, ami ismét azonosítási problémát okoz. Ezért az ilyen interaktív környezetekben szükség van valamilyen más azonosítóra is, amelyet rendszerint sorszámozással szoktak megoldani. Az operációs rendszer a programok indításakor a következő sorszámot jelöli ki azonosítónak. Ezt nevezzük folyamatazonosítónak vagy folyamatsorszámnak. A folyamatsorszám azonban nem egy egész munkát, hanem csak egy munkalépést azonosít.
Interaktív környezetben tehát a munka egységét végül is egyedül a felhasználó határozza meg. Emellett a parancsnyelvek rendszerint lehetővé teszik, hogy több munkalépést egyetlen paranccsal is tudjunk aktivizálni. Ennek módja a parancsállományok készítése, amelyekben egy munkához tartozó tipikus lépések parancshívásai találhatók (lényegében ez teszi lehetővé a kötegelést az interaktív környezetekben). A parancsállomány neve az összefüggő feladatrészeknek konkrét azonosító nevet ad, ami felfogható munkanévként, de ilyenkor is a felhasználó dönt arról, hogy mit tesz a parancsállományokba, és hány parancsállományra bontja a teljes feladatot. Többcélú operációs rendszerekben az egyedi alkalmazásokhoz úgynevezett alrendszereket (pl. OS/TSO) hoznak létre. Ezekben az alrendszerekben a munka fogalma elég változó lehet, és eltérhet az alapoperációs rendszerben értelmezettől. Ugyanakkor az alrendszeri szolgáltatások az alaprendszer szolgáltatásaira épülnek. Következő fejtegetéseinkben, tipikus programozási szituációból kiindulva, a munka egységeként tekintjük egy feladat megoldását a forrásprogram lefordításától az eredmények kiszámításáig.
4.2. Munkafogadási fázis Munkafogadási fázisnak nevezzük azt, amikor a munka számítógépre kerül. Ez kötegelt feldolgozás esetén más időpont a felhasználónak, más az operációs rendszernek, minthogy a kötegelt feldolgozásnál a feladat gépre vitelét az üzemeltető személyzet manuálisan ütemezi. Ezt nevezik off- line ütemezésnek, ami jókora veszteségidőt okozhat a felhasználó szempontjából. A távoli munkabeviteli (RJE) támogatás és interaktív környezet esetén ilyen veszteségidők nincsenek. A kötegelt környezetek munkafogadási fázisában a munka egy bemeneti várakozó sorba kerül. Ha az operációs rendszer több bemeneti sort tud kezelni egyszerre, akkor a felhasználónak kell megadni, hogy melyik bemenő áramba akarja helyezni a munkáját. A munkák felvételét a várakozó sor(ok)ba a beolvasó és/vagy parancsértelmező program(ok) végzi(k). A beolvasók bemenetét a bemenő áramonként feladott munkák (job-ok), kimenetét pedig a bemenő várakozó sorok képezik. Funkciójuk lényegéből kiindulva a beolvasókat vezérlőáram-olvasóknak, az operációs rendszerben játszott fontos szerepük miatt pedig rendszerolvasóknak is nevezik. Programozó
Operátor
JOB --------> Off-line -------> ütemezés > RJE-JOB ---------------------->
Beolvasó
Bemenő sor
Beolvas, értelmez ---> Sorba állít
4.1. ábra. Munkafogadás A beolvasók a bemenő áramokból érkező munkákat azért helyezik el a bemenő várakozó sorokba, mert ritkán fordul elő, hogy a számítógépes rendszer azonnal képes őket kiszolgálni. Rendszerint sok munka összetorlódik, amit valamilyen módon kézben kell tartani. A már emlegetett szoftver spooling technika alkalmazásával az operációs rendszerek háttértáron eltárolják a várakozó munkák adatait, és azok legfontosabb jellemzőit az operatív tárban is nyilvántartják. Ezt az adatszerkezetet, mint nyilvántartási eszközt hívják bemenő sornak.
A rendszerolvasó parancsnyelven érti meg, hogy mit akarunk kérni a számítógépes rendszertől. Kötegelésnél ez a már korábban említett munkavezérlő nyelv (angolul: JCL), amellyel megadható: * a munka azonosítója (munkanév, job-név), és esetleg a munka egyes lépéseinek azonosítója, amiről a 4.1.-ben a munka definíciója kapcsán már volt szó; * a program(ok) végrehajtását kérő neve és munkaszáma; * a hívott program neve és helye az adattárakban; * az adatok vagy azok helye; * a szükséges perifériák adatai; * futásidő-korlát; * tárkorlát; * prioritás, határidő stb. A vezérlőnyelven írt munkát a beolvasó szintaktikusan kielemzi, és ha formai hibákat nem talál benne, akkor helyezi el a spooling bemenő sorában. A spooling állományban elfoglalt helyet feljegyzi a megfelelő sort nyilvántartó adatszerkezetekben. Ez biztosítja, hogy a későbbi munkafázisok hozzá tudjanak férni a munka eredeti adataihoz.
4.3. Munkakiválasztás A kiválasztási fázisban az operációs rendszer eldönti, hogy be tud-e ütemezni egy feladott munkát végrehajtásra. A döntés lehet elutasító is, ha a döntés pillanatában az operációs rendszer nem tudja biztosítani a szükséges erőforrásokat. Az ütemezőnek dönteni kell arról is, hogy több várakozó esetén kit részesít előnyben. Ezt tipikusan a munkák prioritása, és az előírt terhelési politika határozza meg. A kötegelt rendszerekben a kiválasztó program a főütemező. (Azért nevezik főütemezőnek, hogy megkülönböztessék az operációs rendszerben használatos más (alacsony szintű, közbenső) ütemezőktől, amelyeket később tárgyalunk.) A főütemező bemeneti adatait a bemeneti várakozó sorok képezik, kimenete pedig egy munkavezérlő blokk, amely a munkát azonosítja az operációs rendszer számára. A munkavezérlő blokkok reprezentálják a végrehajtási sort, vagy rövidebb néven munkasort, amely az éppen végrehajtás alatt álló munkákat tartja nyilván. Interaktív rendszerekben kiválasztási fázis nincs. A többcélú operációs rendszerekben a kompatibilitás végett a terminálkapcsolatot egy végtelen hosszúságú munkának tekintik. Bemenő sor
Főütemező
Munkasor
JOB11 MVBxx JOB12 -----------> Kiválaszt ----------------> MVB12 JOB13 0 (láncvég) JOB14 0 (láncvég) 4.2. ábra. Munkakiválasztás
4.4. Programfordítás A fordítási fázisban a munka végrehajtásához szükséges forrásnyelvű programok lefordítása történik. A fordítást befolyásolni lehet opcionális paraméterek megadásával. A fordítóprogramok bemenetei a munkában megadott forrásnyelvű programok, -- amelyeket spooling esetén átmenetileg háttértáron a bemeneti adatok között tárolnak, -- kimenetei pedig a korábban említett tárgymodulok. Fordítási fázis csak akkor kell, ha a munkához forrásprogramot is használunk. +----------------+ | Forráskönyvtár | +-------+--------+ | +---------------+ +----+----+ +------------+ | Forrásprogram |--->| Fordító-|------->| Tárgymodul | +---------------+ | program | +------------+ +---------+ 4.3. ábra. Programfordítás
4.5. Programszerkesztés A programszerkesztési fázisban az egységes belső formátumú tárgymodulokból és a tárgymodulkönyvtárakból származó szubrutinokból végrehajtható program jön létre. Az összeszerkesztést a programszerkesztő (angolul: linkage editor) végzi, amelynek a működését opcionális paraméterekkel (szerkesztő utasítások) a fordítóprogramokhoz hasonlóan tudjuk befolyásolni (tárhelyek definiálása, működésmód-paraméterek: kell-e kereszthivatkozási lista, a kód újrabeléphető stb.). A szerkesztő bemenetei a fordítási fázisban keletkezett tárgymodulok, a bennük hivatkozott tárgymodul--könyvtári szubrutinok, és a szerkesztésvezérlő utasítások. Kimenete egy vagy több betölthető programmodul, amely az operatív tárba betöltve végrehajtható. Ez a munkafázis sem minden munkához szükséges. +-------------+ | Tárgymodul- | | könyvtár | +------+------+ | +--------------+ +------v------+ | Tárgymodulok +--->| Program| +------------+ |--------------+ | szerkeszt ő |----->| Betölthet ő | +--------------+ | (Linkage | | modul | | Szerkeszt ő |--->| editor) | +------------+ | utasítások | +-------------+ +--------------+ 4.4. ábra. Programszerkesztés
A programszerkesztési fázis fő célja az, hogy a különböző programnyelveken megírt programokat is össze lehessen kapcsolni egyetlen programmá. Ennek feltétele, hogy a forrásprogramokat a fordítóprogramok egységes tárgymodul formátumra fordítsák. Az így lefordított rutinok könyvtárakban is tarthatók. A programszerkesztőket fel kell tehát készíteni szubrutinkönyvtárak kezelésére is. A programszerkesztés típusai: * fordítóprogram-szolgáltatás (vezérlőutasítások, paraméterek), * nyelvi támogatás (CALL szubrutinhívásokkal), * betöltőprogram-támogatás, * külön szerkesztőmenet szerkesztőprogrammal (ez a legelterjedtebb). A programszerkesztő bemenetei: * Szerkesztésvezérlő utasítások (direktívák), amelyek érkezhetnek a szabványos bemenetről vagy -- főleg interaktív üzemmódban -- a programhívás paramétereiből; * Átcímezhető programmodulok, amelyek az előző fordítási menetekből származnak; * Áthelyezhető (szubrutin)könyvtári modulok, rendszerint nyelvspecifikus, esetenként több, különféle tárgymodul-könyvtárból. A programszerkesztő kimenete(i): * Működőképes, de esetleg még mindig átcímezhető programmodul(ok) (szegmentált, átfedési {overlay} technikát alkalmazó programoknál mindig több modul keletkezik). A programszerkesztés eredménye háttértárba kerül: * vagy szekvenciális állományként, * vagy egy bináris programkönyvtár elemeként. A programszerkesztési művelet részletei: * A lineáris modulcím-tartományokat, amelyek mindegyikének a kezdőcíme rendszerint nulla (0) (a fix helyre címzett rendszerprogramok esetét kivéve), le kell képezni egy vagy néhány összefüggő, esetleg előírt átfedést mutató címtartományra. * A függetlenül fordított modulok más modulok belsejében szereplő belépési pontokra vagy külső címkékre történő külső címhivatkozásokat használhatnak. Ezeket a kereszthivatkozásokat a szerkesztőprogramnak fel kell oldania a modulokban szereplő belépési pontok és a külső hivatkozások összepárosításával (ilyenkor hiba is felléphet, ha a párosítást nem lehet teljes körűen és ellentmondásmentesen elvégezni: feloldatlan külső hivatkozási hiba, angolul: unresolved address, external error stb.). * Az átfedő modulok közötti közlekedést többnyire a programozónak kell megoldania. Megjegyezzük, hogy az átfedési (overlay) technika abból az időből származik, amikor a
hardverben az operatív tár igen szűk kapacitás volt (a drágaság miatt kis méretű tárakat szereltek a gépekbe). Manapság a RAM áramkörök olcsósága és a virtuális tárkezelés miatt egyre kevésbé gazdaságos a programfejlesztőket arra ösztökélni, hogy átfedési technikával korlátozzák a kifejlesztendő program címtartományát. Az átfedő szegmensek közötti közlekedés elbonyolítja az algoritmust, és rendkívül sok, kifejezetten l'art pour l'art számítástechnikai elemet kever a programba. Gondolni kell arra, hogy a programozóknak ezeket a programrészeket is be kell lőni, ráadásul ez igen mély operációs rendszeri ismereteket igényelhet, ami az alkalmazói programozóktól tömeges méretekben nem várható el. Más a helyzet, ha valaki rendszerprogramot ír, vagy nincs virtuális címzési lehetőség, vagy az adott hardveren címkorlátok vannak (az ilyen hardverek szerencsére rohamosan kihalnak -- így a jó nekünk, programozóknak!). Vegyük észre továbbá, hogy a szerkesztőprogramok működési elveinek megalkotásakor a strukturált és moduláris programozás támogatását tűzték ki fő célul. A külön fordítható kis méretű programmodulokat külön-külön is be lehet lőni, majd a végén a szerkesztőprogram segítségével integrálni lehet egyetlen monolit programmá. Megjegyezzük azonban, hogy ma már a monstre programok írásának kora is lejáróban van. Jóval gyorsabban dolgozhatunk, ha kis méretű, de rafináltan paraméterezhető segédprogram-készletre alapozzuk feladatunk megoldását. A konkrét feladatot bináris programkönyvtári rutinokra alapozva próbáljuk megoldani, és csak akkor írunk új programot, ha egy probléma a meglévő könyvtári elemekkel egyáltalán nem, vagy gazdaságosan nem oldható meg. Várható, hogy ilyen esetben is csak kis méretű programokat kell írni. Ezek belövése elég gyors, mert elmarad a monolit programoknál felmerülő, olykor igen keserves integrációs teszt. Ez a módszer igen jól támogatja a strukturált és a moduláris programozást, beleértve a programozói csoportmunkát is. Épp ezért választották a UNIX alapfilozófiájaként. A programszerkesztő direktívái sok operációs rendszerben bonyolult programozási nyelvet képeznek. A számítástechnika rohamos társadalmiasodása folytán egyre több az olyan programozó, akitől nem lehet elvárni ilyen bonyolult (és helytelen alkalmazás esetén nagy veszélyeket rejtő) ismeretek megtanulását. A szerkesztőmenet ezért az alkalmazók felé egyre szegényesebb arcot mutat, jobbára teljesen elfedi őket a fordítóprogram, amely automatikusan megszervezi a lefordított program összeszerkesztését. Nem is beszélve az igen magas szintű nyelvi rendszerekről (mesterséges intelligencia, szakértői rendszerek stb.)! A programszerkesztő profi használata megmarad szűk körű vájt fülűek (így 2000. tájékán: hackerek, guruk -- ZSP/2K.9.21.) privilégiumának. Ezek erőfeszítéseit sem kíséri arányosan nagyobb eredmény. Az utóbbi három bekezdésből megítélheti az olvasó, milyen mértékben egyszerűsödik a programozói munka a hardver és a rendszerszoftver fejlődésével. Egyszerűen nem kell annyit erőlködni, mint régen. Nem is szabad! Ne dőljünk be az idősebb korosztályok izzadságszagot kedvelő munkastílusának! Biztonságos megoldásokra kell törekedni, de a szükségesnél bonyolultabbakra nem.
4.6. Programaktiválás és erőforrás hozzárendelés Az aktiválási, hozzárendelési fázis a munka egy lépésének elvégzéséhez szükséges program futási környezetét teremti meg a JCL-utasításokban jelzett erőforrásigények (perifériák, adatállományok, tármezők) alapján. Az aktiválást az operációs rendszermag moduljaira támaszkodó speciális program, az iniciátor, végzi. Fontos kérdés, hogy az erőforrások lekötése mikor történik. Egy operációs rendszert annál rugalmatlanabbnak tekinthetünk, minél korábban köti le -- a felhasználás időpontjához képest -- a szükséges erőforrásokat. A rugalmatlanság következménye az lehet, hogy a munka hosszú időre megfog egy perifériát, jóllehet csak egyetlen, apró bemenőadathoz használja mindjárt a futás kezdetén. Helyes, ha a lefoglalásra vonatkozó döntések minél későbbre lehet halaszthatók, vagy át lehet helyezni a végrehajtási fázisba. A dinamikusabb kezelés ára a nagyobb rendszeradminisztrációs erőforrásigény (overhead).
Az iniciátor program készít egy bejegyzést az operációs rendszer nyilvántartásában, és esetleg adhat neki egy belső azonosítót: folyamatazonosítót, illetve folyamatsorszámot. A vonatkozó nyilvántartást folyamatsornak vagy taszksornak, a bejegyzést pedig folyamatvezérlő blokknak (angolul: Process Control Block -- PCB), vagy taszkvezérlő blokknak (angolul: Task Control Block -- TCB), szokták hívni. (Ha egy program a futása során egy másik programot (alprogramot) aktivizál, akkor ez új azonosítót és új bejegyzést kap. Ezeket gyermekfolyamatoknak vagy szubtaszkoknak hívjuk.) Munkasor
Iniciátor
MVBxx -------->
Taszksor
TCB(nnnnn) Er őforrás ---------------> TCB(nnnnn+1) lekötés 0 (láncvég)
4.5. ábra. Programaktiválás és erőforrás hozzárendelés
4.7. Programbetöltés A betöltési fázisban az operációs rendszer helyet biztosít az operatív tárban a munkalépés programjának (kivéve, ha az eleve fix címre akar töltődni), és betölti. A betöltést vagy külön betöltőprogram, vagy az operációs rendszer betöltő-modulja végzi. A betöltőprogram bementét a betölthető programmodulok képezik, kimenete pedig az operatív tárba kerül. A betöltés során a modulok címeit a betöltőprogram -- ha szükséges -- átcímezi úgy, hogy a program az adott helyen végrehajtható legyen. A betölthető programmodulok programszerkesztés eredményeként keletkeznek. A betöltőprogramnak ezeket többnyire újra át kell címeznie, mert multiprogramozott környezetben és valós tárak használata esetén előre nem lehet tudni, hol lesz szabad tármező, amikor a betöltő helyet foglal a programnak (ismét kivéve a fix helyre töltődőket). Az átcímzési műveletet programáthelyezésnek nevezzük. A programáthelyezést statikusnak nevezzük, ha az csak betöltéskor történhet, később már nem. A dinamikus programáthelyezés lehetővé teszi, hogy a program szükség esetén működés közben is áthelyezhető legyen az operatív tár más tartományába. Ez biztosíthatja a legrugalmasabb tárgazdálkodást. Amíg nem voltak hardver virtuális tárak, addig a programáthelyezés a betöltőkkel szoftver úton történt. Virtuális tárak esetén más a helyzet. Igazi virtuális címzést biztosító operációs rendszerek használatával ugyanis minden programnak rendelkezésre áll a hardverrel címezhető teljes címtartomány (nullától a maximumig!, ha nem kell kerülgetni rendszerprogramoknak lefoglalt címtartományokat vagy a hardver speciális működését kiváltó címeket). Virtuális tárkezelés esetén tehát átcímzésre a betöltéskor elvileg nincs szükség, de még mindig gondokat vethet fel a lapokra tördelt programrészek működésének biztosítása a fizikai lapokon. Emiatt a virtuális tár technika egyáltalán nem biztos, hogy egyszerűbb megoldást eredményez. (Mégis, ha a virtuális tárakat korábban felfedezték volna, talán másképpen alakult volna az operációs rendszerek egész tárkezelése.)
4.8. Programvégrehajtás A végrehajtási fázis jellemzője, hogy a munkalépés programja aktív a rendszerben, a
multiprogramozott környezetben versenyez az erőforrásokért. Egyáramú rendszerben a munka folyamatosan fut, a számlázandó idő akár "faliórával" is mérhető. Multiprogramozott környezetben viszont a végrehajtási idő és a felhasznált idő szükségszerűen eltérő. A végrehajtási idő olykor lényegesen hosszabb lehet, mint multiprogramozás nélkül. Ez a felhasználó szempontjából veszteségidő. Ezalatt azonban a munka nem állandóan aktív, és a számlázórendszer feladata, hogy csak azokat az időket és erőforrásokat számítsa fel a felhasználónak, amit ténylegesen felhasznált. Előfordul, hogy két olyan munka kerül össze a multiprogramozott környezetben, amelyek "egymást ütik". Tipikus példa erre az olyan eset, amikor két program ugyanazt a mágneslemezes adatállományt olvassa aszinkron módon. Ilyenkor a lemezegység olvasófeje oda-vissza rángatódzik, ami igen nagy időveszteségeket okoz. Ha a két program eltérő időintervallumban futhat, akkor érthető okoknál fogva gyorsabban befejeződhetnek, sőt a hardver igénybevétele is kedvezőbb. Az adott szituációt elég nehéz programozottan kiszűrni, ezért még mindig sok függ az alkalmazók odafigyelésétől, és az üzemeltetés manuális ütemezési tevékenységétől. Jellemző, hogy az említett szituációban az operációs rendszer a rossz hatásfokú működésből eredő terheket könyörtelenül leszámlázza a két program indítójának, holott ők esetleg nem is tehetnek róla.
4.9. Záró fázis Amikor egy program lefut, az operációs rendszernek még egy sereg teendője marad. A program befejeződése után vissza kell venni tőle a lefoglalt erőforrásokat, és különféle adminisztratív műveleteket kell végrehajtani. Ezt vezérli a terminátor program. A további tipikus feladat a háttértárra vitt nyomtatókimenet átadása a nyomtató spooling rendszernek, azaz elhelyezés a kimeneti sorban. Ha a spooling rendszer végez a munka eredményének kilistázásával, akkor az operációs rendszer véglegesíti a munkára vonatkozó számlázási adatokat, és a munkához tartozó táblázatokat törli, hogy a már érdektelen információk ne terheljék a rendszer táblázatait.
4.10. Rendszerfolyamatok Az operációs rendszer saját feladatai szintén munkaként merülnek fel a számítógépes rendszerben. Ezeket a speciális feladatokat rendszerfolyamatoknak, rendszertaszkoknak nevezzük (több elnevezés is használatos). A tipikus rendszerfolyamatok: * * * * * * * *
beolvasó (spooling munkafogadó), főütemező (munkakiválasztó), iniciátor (aktivizáló), terminátor (befejező), nyomtató (spooling listázó), nyelvi fordító, programszerkesztő, betöltő stb.
Ezek a munkák többé-kevésbé szintén átmennek a fejezetben tárgyalt munkafázisokon. Ezeket is fogadni kell, ki kell választani végrehajtásra, aktivizálni kell stb. A rendszerfolyamatok esetében ez privilegizált módon, előnyök biztosításával, esetenként speciális üzemmódban történik. Egyes rendszerfolyamatok a rendszertöltéskor automatikusan elindulnak (például a főütemező), míg mások (például a beolvasók, a nyomtatók) csak operátori beavatkozásra indulnak. A kapcsolódó vezérlőblokkok (PCB, TCB stb.) állandóan megmaradnak az operációs rendszer
nyilvántartásaiban, és rendszerint a táblázatok elején foglalnak helyet. A megfelelő programok munkahiány esetén elalszanak (de nem halnak meg), és amint valami történik, rögtön felébrednek. Ez tipikus real-time (eseményvezérelt) jelleg.
4.11. Mintapéldák Példa gyanánt elsősorban ismét az IBM kötegelt operációs rendszerei említhetők, amelyekről a 2. fejezetben részletesen volt szó. Így például az OS munkafogadási fázisát a READER beolvasóprogram valósítja meg. A kiválasztást az OS magas szintű ütemezője, a MASTER SCHEDULER főütemező program végzi. Az OS akkor indít egy programot, ha van olyan (szabad) INITIATOR (iniciátor) program, amely indítani képes. Az iniciátor lefoglalja az igényelt erőforrásokat, és az OS SUPERVISOR-ával betölteti a behívandó programot. A SUPERVISOR megfelelő tármezőt foglal le, betölti és elindítja a programot. Az OS a nyomtatóra szánt kimenetet félreteszi mágneslemezre. Amikor a program jelzi, hogy véget ért, akkor a TERMINATOR program intézi el a záróteendőket. Felszabadítja a még foglalt erőforrásokat, és gondoskodik a kinyomtatásra szánt adatok átadásáról a WRITER nyomtatóprogramnak. Miután a nyomtatóprogram sorra kerítette és kinyomtatta a munka eredményét, a munka teljesen törlődik a rendszer táblázataiból. A terminátor program behívja maga után az iniciátort (ez csak logikailag értendő, az OS-ben az iniciátor/terminátor fizikailag egyetlen program). Ilyenkor az iniciátor szabaddá válik újabb program indítására. A multiprogramozás fokát az OS-ben tehát elsősorban az határozza meg, hogy hány INITIATOR-t indítottak el az üzemkezdet óta. Az operátorok a multizás növelésére indíthatnak újabbakat, de le is állíthatnak egyeseket, ha túl nagy a rendszerterhelés. Az interaktív rendszerekről azt írtuk a főszövegben, hogy azoknál a felhasználónak magának kell megszerveznie a munkát. Így munkafogadó program nincs, az erőforrások lefoglalásáról, és a kiválasztásról a felhasználó maga dönt. A programindítást a parancsértelmező program végzi a felhasználó direkt utasítására. Az ilyen operációs rendszerekben a programszerkesztő és betöltő program tér el legkevésbé a kötegelt rendszerekben szokásosaktól. Az utóbbi időben azonban a számítástechnika erős társadalmiasodása olyan helyzetet teremtett, hogy egyre több olyan interaktív felhasználó jelentkezik, akire nem lehet rábízni a munka megszervezését az interaktív környezetben. A szoftvergyártók ezért foolproof (bolondbiztos) ún. dedikált szoftverek létrehozására törekednek, amelyek a felhasználónak természetesebb -- nem túl "komputerszagú" -kapcsolattartási nyelvet biztosítanak: menüből választható, előre megszervezett, munkameneteket támogatnak. Ezekben a programokban persze sok hasonló elem van. Ha ezeket jól kielemezzük, akkor készíthetünk általános menüvezérlő szoftvereket, amelyeket már számítástechnikailag kevésbé kvalifikált alkalmazók is felhasználhatnak interaktív feladataik racionális megszervezésére. Érdekes, hogy ilyen szoftverek előszeretettel éppen a PC-k körében terjednek. Ennek az az oka, hogy a mai nagy teljesítményű személyi számítógépeknél sem annyira magánügy már, hogy milyen a gép kihasználtsága. Itt is cél, hogy a lehető legtöbbet hozzuk ki belőlük (ebből a szemszögből nézve az OS/2 ugyan csak egy kicsi, de fontos lépés lehet előre a multitaskingjával!). Tipikus PC-s munkaszervezők: PathMinder, XTREE, FRAMEWORK, GEM Desktop, WINDOWS, valamint a sokáig várva várt Presentation Manager az OS/2-ben, és az MS--DOS 4.0-s változata, hogy csak néhányat említsünk. (Azóta jött a tisztességesen multiprogramozható W9x, WNT és W2K -- anno 1995-2000-ig, ZSP.2K.9.25. 2001: WXP.) A PC-ken továbbá még egy "kór" terjed, az ún. integrált szoftverek filozófiája. Ezek nemcsak a munkafogadást és indítást, hanem egy típusfeladat teljes lépéshalmazát igyekeznek magukba integrálni és támogatni. Az alkalmazókat a maximális mértékben mentesítik a munkaszervezés viszontagságaitól, amiért a nem számítógépes alkalmazók igen hálásnak mutatkoznak. Ilyen típusú szoftverek (a fentiekkel átlapolva): a TURBO PASCAL, a LOTUS 1-2-3, a SYMPHONY, a
DBASE az ASSIST-tal, a FRAMEWORK, a GEM moduljai, a WINDOWS, de a felsorolás persze nem teljes. Már a segédprogramokat is ilyen stílusban szervezik. Ez látható a PCTOOLS-nál, ami a hajdani nagygépes IBM DITTO segédprogram filozófiájának jól elkapott interaktív, menüvezérelt, bár karaktergrafikás és billentyűzetről kezelhető megfelelője (legalább a MICROSOFT egerét ismerhetné, mint annyi más jó szoftver, pl. a NORTON programok). Megjegyezzük, hogy az integrált szoftverkörnyezet egyáltalán nem mai ötlet. A UNIX már 1969-ben ezen az elven alapult. Az IBM TSO továbbfejlesztett változatai (SPF stb.) szintén ezt a filozófiát igyekeztek megvalósítani még a 70-es években.
4.12. Gyakorlatok 4.12.1.
Mi a feladatok egysége a számítástechnikában?
4.12.2.
Van-e tipikusan megkülönböztetett feladategység interaktív környezetben?
4.12.3.
Mi történik a munkafeladási fázisban?
4.12.4.
Mi van a bemenő sorban?
4.12.5.
Mi az off-line ütemezés?
4.12.6.
Van-e veszteségidő az RJE-JOB-oknál?
4.12.7.
Mi a munkavezérlő blokk?
4.12.8.
Hogyan történik a munkakiválasztás?
4.12.9.
Mit csinál a főütemező?
4.12.10.
Hogyan történik a programok fordítása?
4.12.11.
Mi a tárgymodul?
4.12.12.
Milyen bemenő adatokkal dolgozik a szerkesztőprogram?
4.12.13.
Mi a betölthető modul?
4.12.14.
Hogyan teremtjük meg a program futtatási környezetét?
4.12.15.
Mi az iniciátor?
4.12.16.
Mi az előnye és hátránya a rugalmas erőforrás kezelésnek?
4.12.17.
Hogyan vesszük nyilvántartásba az elindított programokat?
4.12.18.
Mi történik a programbetöltéskor?
4.12.19.
A futtatási időben támadhat-e veszteségidő? Mikor? Miért? Kell-e érte fizetni a felhasználónak?
4.12.20.
Mi történik egy program lefutása után?
4.12.21.
Mit nevezünk rendszerfolyamatnak?
4. Milyen kezelésmódot igényelnek a rendszerfolyamatok?
OS05v08,2K.9.24,ZSP
5. RENDSZERSZOLGÁLTATÁSOK
5.1. Alapkoncepció A számítógépes rendszer pár szolgáltatását operációsrendszeri szolgáltatásnak (rövidebben rendszer-szolgáltatásnak) nevezzük. Ez a kör függ attól, hogy az adott számítógépes rendszer szoftverének mely elemeit soroljuk az operációs rendszer elemei közé. Általában a rendszerszolgáltatásokhoz soroljuk az alkalmazók elég széles körében használt szoftverelemeket. A nem operációs rendszeri szolgáltatások egy része is lehet elég széles körben használható. Ez a már említett rendszerközeli szoftver, amelyet inkább segédprogramoknak nevezünk. A rendszerszolgáltatások nem feltétlen kötődnek a rendszermaghoz, de megvalósításuk a rendszermag szolgáltatásait intenzíven használó, rendszerfolyamatokként futó ún. rendszerprogramokkal történik, amelyek az operációs rendszerben kifejezetten nekik biztosított privilégiumokat élveznek. Az operációs rendszer felügyelete alatt működtetendő programokat tekintve vannak futtatás előtti és futtatás alatti rendszerszolgáltatások. Speciális eset, amikor az operációs rendszer egy szolgáltatást saját magának nyújt.
5.2. Vezérlőáram-kezelés Mint arról már többször beszéltünk, a kötegelt üzemű operációs rendszerek bemenetére érkező munkákat a vezérlőáram-olvasó, vagy más néven rendszerolvasó (angolul: system reader) fogadja. A kötegelt üzemmódban a parancsokat kötegekben összegyűjtjük, és átmenetileg mágneslemezen tároljuk. Ez a szoftver spooling technika, amelyről már szintén volt szó. A mai vezérlőáramkezelők teljesen a szoftver spoolingra alapozva működnek. Az összegyűjtött parancsok végrehajtása külön menetben történik. (Interaktív üzemmódban a parancsok egyenként, azonnal végrehajtódnak, de a rendszerolvasók ritkán használhatók interaktív üzemmódban.) A kötegelt üzemmód rendszerolvasóit operátori kezdeményezéssel kell indítani. A beolvasott munkák a bemenő várakozó sorba kerülnek, amiről az előző fejezetben már volt szó. A futási eredmények a szoftver spooling elvei szerint szintén sorba állnak. Ez a nyomtatósor. A nyomtatósorból az eredményeket a rendszernyomtató program nyomtatja ki. A rendszernyomtatókat szintén operátori kezdeményezéssel kell indítani. Operátori kezdeményezésre a rendszerolvasók és -nyomtatók le is állíthatók majd újraindíthatók. A rendszerszolgáltatások esetében tipikusan igaz, hogy a rendszerfolyamatok vezérlése, mivel
különleges elbírálást igényel, az üzemeltető személyzet feladata. A szintaktikus ellenőrzés többé-kevésbé a rendszerolvasók feladata, de olykor ezt későbbi rendszerelemek végzik (a főütemező vagy az iniciátorok). A felhasználónak nem öröm, ha a JCLhiba csak a futáskor derül ki, de a dinamikus erőforrás-foglalási stratégia időnként nem teszi lehetővé, hogy elég messzire lássunk előre. Kompromisszumos megoldásokra törekednek. A rendszerolvasót általában elválasztják az ütemezőktől, mert külön-külön rendszerfolyamatkénti aszinkron működésük kedvezőbb "munkakeverék" (angolul: jobmix) összeállítását teszi lehetővé. Sőt, a főütemezővel konkurens több rendszerolvasót is működtetni lehet (több bemenőáramú rendszerek). Így a nagy teljesítményű hardverek számára kellő mennyiségű munkát lehet a számítógépes rendszerbe vinni.
5.3. Tárkijelölés és programbetöltés A programok betöltése multiprogramozott környezetben szinkronizálást igényel. Ezt az operációs rendszer tárkezelési szolgáltatásaira épülő betöltőprogrammal lehet kézben tartani. A programokat fordításkor csak akkor lehet fix címre elhelyezni, ha azon a tárterületen más program általában nem futhat. Ez csak a rendszerprogramoknál fordulhat elő. A normál programokat mindig átcímezhetőre kell fordítani, alacsonyszintű programnyelveken pedig a programozónak áthelyezhető programokat kell írnia. A betöltőprogram gondoskodik róla, hogy, ha szükséges, a program az általa igényelt fix címre kerüljön. Általánosabb esetben, ún. normál programoknál viszont inkább helyet foglal a programnak az operatív tárban, majd a program kritikus részeit átcímezi úgy, hogy az adott tárterületen működőképes legyen. A programok átcímzése egyszerűbb, ha a hardver programáthelyezési támogatást tud nyújtani. Ennek hiányát csak bonyolultabb betöltőprogrammal lehet kompenzálni. Az IBM 360/370-es hardvereknek például nincs ilyen szolgáltatásuk, ami azzal a "krónikus" következménnyel jár nemvirtuális tárkezelésű operációs rendszerek használata esetén, hogy a tár a munka során felaprózódik sok kis méretű szabad területre, amelyeket nem lehet menetközben összegyűjteni. A problémát sokszor leggyorsabban csak a rendszer átmeneti leállítása árán lehet feloldani. Ennek megfelelően nagyra értékelhető, hogy a ma -- de még inkább a jövő -- számítógépkorszakát talán meghatározó INTEL 80286/80386-os mikroprocesszorok, és a VAX-kategóriájú miniszámítógépeknek van automatikus programáthelyezési architektúrája. Virtuális tárkezelésnél teljesen az operációs rendszer magánügye lehet egy programszegmens elhelyezése. A programok a szegmenseikre nem azok címével, hanem egy táblázatindexszel hivatkoznak. A táblázatbeli címeket megszakításkor az operációs rendszer az üzemi körülményektől függően bármikor megváltoztathatja. A program újabb beütemezésekor a hardver a vezérlést a virtuális tárkezelés dinamikus címfordítójára támaszkodva automatikusan az új helyre adhatja. Így virtuális tárkezelésnél a valós tárban szabadon maradó helyek is könnyedén összegyűjthetők egy darabba, mert csak az összegyűjtés során útba került, és eltologatott szegmensek új kezdőcímeit kell bejegyezni a megfelelő indextáblázatokba. A virtuális tárkezelésű rendszerekben elvileg teljesen lineáris címmező áll a programok rendelkezésére. Néhány rendszerben azonban még belezavarnak a képbe a hardverarchitektúra sajátosságai. Előfordul például, hogy bizonyos tárterületeket kerülgetni kell. Ez többnyire a fordítók és a betöltőprogramok feladata. Tipikusan ilyen eset az INTEL 80286/80386-os családot használó IBM PC architektúra, amelyben az alsó 1 megabájtos címtartományt (igen fix kiosztásban) a tárba
ágyazott perifériakezelés és az MS--DOS operációs rendszer "őskövületei" zavarják. Ezért a PC-s operációs rendszerekben vagy kerülgetni kell az alsó 1 megabájt fix címeit, vagy -- ahogy az OS/2 tervezői is tették -- az egészet odadobjuk egy MS--DOS partíciónak (DOS kompatibilitási doboz). (Szerencsére, még marad további 15 megabájtnyi címmező! -- I80286 korlát, ZSP. 2K.9.24.)
5.4. Szerkesztőmenet A programszerkesztő programok (angolul: linkage editors) különálló programmodulokból a futóképes programok összeállítását végzik, mint azt korábban és részletesebben a 4. fejezetben megtárgyaltuk. A programszerkesztők erősen igénylik az alsóbb operációs rendszeri szolgáltatásokat, ezért nem sima segédprogramoknak, hanem rendszerelemeknek tekintjük őket. (Szemben a forrásprogramok írásához használatos szövegszerkesztőkkel, más néven editorokkal, amelyeket segédprogramoknak tekintünk akkor is, ha egy-egy editor sokszor igen mélyen beépül némely operációs rendszerbe.) A programszerkesztők annyiban mégis segédprogram jellegűek, hogy nem a rendszermag részei, ezért normál folyamatként futnak, nem úgy, mint a főütemező és más rendszerfolyamatok. A segédprogram jelleget támasztja alá még az a körülmény is, hogy amíg más rendszerfolyamatok működését elsősorban az operációs rendszerben kitűzött politikák vezérlik, addig a programszerkesztő működését szinte teljes mértékben az alkalmazó befolyásolhatja a szerkesztésvezérlő utasításokkal.
5.5. Magas szintű ütemezés Kötegelt üzemmódban a bemenő áramból (más néven: vezérlő áramból) érkező és a végrehajtási sorba helyezett munkák végrehajtását külön operációs rendszeri modul, az ütemező végzi. Az operációs rendszerben azonban több ütemező is működik, ezért a munkák végrehajtását beütemező programot megkülönböztetésül főütemezőnek (angolul: Master Scheduler) nevezzük. Az 1.2. fejezetben a számítógépes rendszer üzemeltetői szemszögből vizsgált rétegződésével kapcsolatban említettük az ütemezési réteget (lásd: 1.3. ábra), amely az operációs rendszeri réteg felett van. A főütemező ebben a rétegben helyezkedik el, tehát az operációs rendszernél magasabb hierarchia szinten. Ezért mondjuk, hogy a főütemező magas szintű ütemező. A magas szintű ütemező így nem az operációs rendszermag része, hanem egy rendszerfolyamat a számítógépes rendszerben, ami más folyamatok működését vezérli aszinkron konkurens üzemmódban.
Az ütemező aktivizálódhat: * induláskor automatikusan, * operátori kezdeményezésre, * eseményvezérelten (valós idejű és tranzakciós környezetekben, megszakításokra reagálva), * folyamatvezérelten (a programok megkapják a vezérlést az ütemezőtől, amit visszaadnak neki; ez az egyfelhasználós egyáramú üzemmódra jellemző, de alkalmazása ott is egyre ritkább, például a programozott/sorrendi vezérlőkben fordul elő). Üzemindításkor (betöltéskor, angolul: boot), amikor az operációs rendszer a főütemezőt indítja, annak folyamata többnyire első folyamatként, az inicializálási folyamat során keletkezik (a folyamatok táblázatában ezért automatikusan az övé az első hely). Ezután a főütemező gondoskodik további folyamatok létrehozásáról, amelyek egyike lehet a rendszer indításakor az operátorral kapcsolatot tartó rendszerindító folyamat. Ennek segítségével az operátor is kezdeményezheti különböző folyamatok indítását (például a már említett rendszerszolgáltatásokat, a beolvasó és nyomtató programokat). A rendszer akkor működik a leggazdaságosabban, ha a főütemező minél ritkábban aktivizálódik, és működéséhez nem von el túl sok erőforrást a számítógépes rendszertől (angolul: overhead). Az ütemezést a főütemező előírt politika szerint hajthatja végre. Ez igen erősen rendszerfüggő. A munkakiválasztás a pillanatnyi munkasortól és az erőforrás-kapacitásoktól függ. A dinamikus erőforrás-kezelő(ke)t olykor beépítik a főütemezőbe, de a dinamikusabb rendszerműködés csak különálló, aszinkron konkurens módon működő kezelőprogramokkal oldható meg. Ezek sem a rendszermag részei -- akár a főütemező, -- hanem magasabb rétegekben találhatók, de az erőforrások foglalásához igen alapvető rendszermag-szolgáltatásokat vesznek igénybe. Indításuk részben automatikus a rendszer indításakor, részben pedig az operátor vagy valamelyik ütemező kezdeményezheti indításukat. Ebbe a kategóriába tartoznak a korábban már emlegetett iniciátor és terminátor programok.
5.6. Működésoptimalizálás A főütemező a rendszerolvasó programok által a végrehajtási sorba helyezett munkák indítását vezérli. Az ilyen vezérlési rendszerben néha zavarok támadnak, mert a munkakeverék egyik eleme olykor túl agresszíven birtokba veszi a rendszer erőforrásait. A főütemező ezen nem tud változtatni, hiszen ő már átadta a munkát végrehajtásra az alacsony szintű ütemezőnek, amely a központi egység használatát ütemezi. Ezt az ütemezőt a továbbiakban megkülönböztetésül (az angol dispatcher elnevezés nyomán) diszpécsernek fogjuk hívni. A diszpécsernek igen sok dolga van ezen az alacsony szinten, ezért vigyázni kell arra, hogy mit veszünk bele az algoritmusába. Ha túl bonyolult az algoritmus, akkor az egész számítógépes rendszer erősen lelassul. Az egyszerű algoritmus viszont nem teszi lehetővé elég széles látókörű ütemezési politika megvalósítását. A gyakorlat az, hogy a diszpécser csak lokális optimumokat vizsgál a kiválasztási döntésekben. Nagyteljesítményű rendszerek gazdaságos működtetéséhez ez nem elegendő. Ezért bevezettek egy további ütemezőt, a közbenső (szintű) ütemezőt, amely a rétegszerkezetben valahol félúton helyezkedik el a magas- és az alacsony szintű ütemező között. A közbenső ütemező feladata -- mint a mondottak után várható -- a globális optimalizálás. Ennek
megoldására állandóan figyeli a munkák előrehaladását. Ha egy munka nem halad elég gyorsan a rendszerben, akkor például prioritásának ideiglenes megemelésével segíthetünk rajta, mert a prioritás növelésével nő annak az esélye, hogy -- mások rovására -- beütemeződjön. Bonyolultabb optimalizálási algoritmusok súlyos esetben lehetővé teszik egyes munkák ideiglenesen kiiktatását az alacsony szintű ütemezésből, hogy az erőforrásra éhező más munkák egyáltalán szóhoz tudjanak jutni. Amint az éhezés megszűnik, a közbenső ütemező a kivételezéseket sorra megszünteti, nehogy ellenhatásként a korábban elsőbbséget kérő munkák kerüljenek hátrányos helyzetbe. A közbenső ütemezők általában segíteni szokták a kis erőforrás-igényű munkákat, hogy azok minél gyorsabban átjussanak a rendszeren, de támogatják a túlzottan lassan haladó munkákat is (például az idő előrehaladtával arányosan növeli prioritásukat), hogy siettesse a kijutásukat. Bonyolítja a helyzetet, ha a számítógépes rendszer univerzális üzemmódban dolgozik. Ha például valós idejű környezete is van, akkor a valós idejű feladatokat mindig ki kell szolgálni az előírt időkorláton belül, és minden más igény kiszolgálása csak ezután jöhet. Az OS/2 operációs rendszerben például 32 prioritási szint van. A 0 -- 15-ös prioritásszinteken időosztásos üzemmód működik, míg a 16 -- 31-es magas prioritásokat a valós idejű alkalmazásoknak tartották fenn. Ez a módszer a valós idejű alkalmazások elsőbbségét -- tulajdonképpen kifejezett kivételezés nélkül, automatikusan -- biztosítja. Ugyancsak a prioritások alkalmas kiosztásával szabályozzák az IBM 360/370-es OS operációs rendszerekben a TSO időosztásos alrendszer működését. A rendszergeneráláskor beállítható prioritásintervallumba eső folyamatok (IBM terminológiával taszkok) kiválasztásakor az alacsony szintű ütemező időszeleteléses kiválasztási algoritmust követ, míg az intervallumon kívül eső prioritások esetén prioritásvezérelten működik, ami a kötegelt feldolgozások üzemeltetésénél fontos.
5.7. Alrendszerek kezelése Az alrendszerek az operációs rendszerekben speciális jelentéssel bírnak. Homogén alkalmazói kör speciális igényeinek egyszerűsített kiszolgálását teszik lehetővé. Szolgáltatásaik alapja az operációs rendszeri interfész, amelyre egy új réteget borítanak. Ez az ún. alrendszeri réteg, amelynek a szolgáltatásait az alrendszeri interfészen át lehet elérni. Olyan részrendszer, amelyik egy magasabb szintet képező rétegben van: +-------+-------+-------+----------+----------+----------+ | | | | | | | | A l r e n d s z e r i | | | | |a l k a l m a z á s o k| | | | | | | | Al| Al| Al| +-------+-------+-------+ kal| kal | kal| | Alrendszeri interfész | ma| ma| ma| +-----------------------+ zá| zá| zá| | Alrendszeri | sok | sok | sok | | funkciók | | | | +-----------------------+----------+----------+----------+ | Futtatási környezet interfész | +--------------------------------------------------------+ | M E G A G É P | +--------------------------------------------------------+ 5.1. ábra. Alrendszeri rétegződés
Tipikus alrendszerek az univerzális operációs rendszerek programfejlesztő alrendszerei. Ilyen volt például az IBM BASIC és APL nyelvi alrendszere az IBM DOS-ban, és ilyen a TSO az OS-ben. Az alrendszerek tipikus szolgáltatásai: * szövegszerkesztők (esetleg nyelvspecifikusak), * interpreterek, * fordítók, szerkesztők, betöltők egy nyelvhez. Az IBM ebben a kategóriában emlegeti a JES(OS)-t és a POWER(DOS)-t, mint integrált kötegelést támogató alrendszert, bár ez egy kicsit sántít. A JES és a POWER az alábbi fázisokat vonja össze: * * * *
beolvasó (feladatfogadó), spooling, kiválasztás, aktiválás.
Így a JES (= Job Entry Subsystem -- munkabeviteli alrendszer) és a POWER (nem jellemző jelentésű akronim) a fenti definíció szerint azért nem alrendszer, mert nem csak egy szűk felhasználói kört érintenek, hanem egy általános célú munkafogadó és spooling programrendszert takarnak. Az JES az OS/VS rendszerek olvasó, nyomtató, magas szintű ütemező, sőt erőforrásfoglaló szolgáltatásait foglalja magában, amelyre minden számítógép felhasználó támaszkodik, akár kötegelt, akár időosztásos üzemmódban dolgozik. Ezzel szemben az OS rendszerek időosztásos opciója (ahogy az IBM nevezi, angolul: TSO = Time-sharing Option) nem más, mint egy igazi operációsrendszeri alrendszer. Speciálisan a programfejlesztést végző programozók munkájának hatékony támogatására kihegyezett alrendszer. A technikai megvalósítást tekintve egy alrendszer: * "integrált" programcsomag egy funkcióhalmazra, amely összefüggő feladatkört fed le; * a felhasználóknak az eredeti operációs rendszer interfészétől eltérő -- egyszerűbb -interfészt biztosít. A JES tehát azért sem alrendszer, mert nem képez integrált futási környezetet, hiszen lényegében csak a beolvasásra szakosodott részrendszer. Elemezhetjük ennek kapcsán a rendszerszolgáltatások és az alrendszeri szolgáltatások viszonyát. A rendszerszolgáltatások: * általánosan, relatíve ritkán használt szolgáltatások, amelyeket minden felhasználó elérhet. Alrendszeri szolgáltatások: * intenzíven használt, de csak a felhasználók szűk köre érheti el. A számítógépek hardver és szoftver fejlődését érdemes elemezni, mert kimutatja, hogyan váltak az alrendszerek egyre bonyolultabbá. Az operációs rendszerek tervezésénél eleinte nem gondoltak alrendszerekre, mindent egy közös operációs rendszeri interfésszel akartak kiszolgálni. Új szolgáltatási igények bevezetése azonban ebben a filozófiában egyenlő volt az operációs rendszer folytonos turkálásával, ami nem túl üdvös dolog. Rájöttek, hogy elég egy egyszerűbb szolgáltatáshalmazt biztosító interfészt készíteni, a
különleges eseteket pedig alrendszeri szolgáltatásokra kell bízni. Új igények kielégítését elvileg három módon biztosíthatjuk, amit az 5.2. ábra elemez. +-------------------+-------------------+----------------------+ | Beépítés a régi | A régi interfész |A régi interfész fölé | | interfészbe | teljes cseréje |alrendszeri interfész | | | | kiépítése | |(bonyolult, lassú | (veszélyes, |(egyszerű, de hatásfok│ | funkciók) | fáradságos) | csökkenés léphet fel)| +-------------------+-------------------+----------------------+ 5.2. ábra. Az alrendszer kiépítés elemzése A legrugalmasabb megoldást az alrendszeri interfész kiépítése tudja biztosítani, mert: * a rendszerkiterjesztés problémája a minimumra csökkenthető; * az alkalmazók kiszolgálásának szervezése optimalizálható; * új alkalmazások implementálása felhasználó-specifikus alrendszeri interfész kiépítésével érhető el.
A fejlődési tendenciákat, architektúrákkal jellemezve, az 5.3. ábra mutatja: A/ Egymenetes rendszer
B/ Multiprogramozás
+--------------+ | alkalmazó | +--------------+ |szolgáltatások| +--------------+ | rendszermag | +--------------+ | hardver | +--------------+
+-------------------+ |alk1.| alk.2 |alk3.| +-------------------+ | szolgáltatások | +-------------------+ | rendszermag | +-------------------+ | hardver | +-------------------+
C/ "Alrendszer"
D/ Virtuális gép
+--------------------+ +--------------------+ |a-l-k-a-l-m-a-z-ó-k | |a-l-k-a-l-m-a-z-ó-k | +-----+-----+--+--+--+ +-----+-----+-----+--+ | TSO | DB |X |Y |Z | |ETSS | CMS | TSO |OS| +-----+-----+--+--+--+ +-----+ +-----+ | | OS szolgáltatások | | DOS | | - OS - | +--------------------+ +-----+-----+--------+ | OS Supervisor | | Hipervisor | +--------------------+ +--------------------+ | hardver | | hardver | +--------------------+--------------+--------------------+ E/ Géphálózat +-------------+-------------+-------------+-------------+ | alkalmazók1 | alkalmazók2 | alkalmazók3 | alkalmazók4 | +-------------+-------------+-------------+-------------+ |alrendszerek1|alrendszerek2|alrendszerek3|alrendszerek4| +-------------+-------------+-------------+-------------+ |op. rendsz.1 |op. rendsz.2 |op. rendsz.3 |op. rendsz.4 | +-------------+-------------+-------------+-------------+ | hardver 1 | hardver 2 | hardver 3 | hardver 4 | +-------------+-------------+-------------+-------------+ 5.3. ábra. Számítógépes rendszerek strukturálódása Mint látható, az alrendszeri strukturálódás egyre mélyebbre hatol. Az operációs rendszereket általában speciális szolgáltatásokkal látják el, hogy támogatni tudják alrendszereiket. Emiatt előfordul, hogy a rendszermaghoz is hozzányúlnak egy új alrendszeri interfész kiépítésekor, de ez korántsem okoz akkora problémát, mintha az egész alrendszeri interfészt akarnák bepasszírozni az eredeti operációsrendszeri interfészbe.
5.8. Mintapéldák 5.8.1. Az IBM OS TSO alrendszere Mint korábban már említettük, az IBM cég a TSO alrendszert a TSS időosztásos operációs rendszer ideiglenes kiváltására tervezte. A TSS bukása folytán azonban a TSO végleges megoldássá vált az OS MVT keretén belül. Az OS így legalább egy alrendszer keretéig tud időosztásos szolgáltatásokat nyújtani a terminál-felhasználóknak. Az OS eredeti kötegelt jellege természetesen megmaradt, így az az állapot, hogy a TSO csak alrendszerként szerepel, hátrányokat jelent a kötegelt felhasználókhoz képest. A TSO alrendszerben nincs külön alrendszeri ütemező az időosztásos működés biztosítására, hanem közvetlenül az OS alacsonyszintű ütemezője, a diszpécser oldja meg ezt a taszkok egységes kezelhetősége végett. A konkrét megoldást korábban már emlegettük: a teljes prioritásszám tartományból ki szoktak jelölni egy keskeny intervallumot, amelyen belül a taszkok ütemezéséhez a diszpécser időszeletelési algoritmust használ, az intervallumon kívül esőket pedig prioritásvezérelt alapon ütemezi. A fő probléma ezzel kapcsolatban az, hogy a TSO taszkok nem a legmagasabb prioritásokat kapják, tehát lehet -- és rendszerint szokott is lenni -- olyan kötegelt munka a rendszerben, amelynek nagyobb a prioritása. Az ilyen munkák aztán alaposan megakaszthatják a TSO munkák végrehajtását. A terminálnál ülők csak malmoznak a meg sem moccanó ernyőkép előtt. Mindenesetre a felhasználók a TSO szolgáltatások mellett koránt sem érzik azt, hogy egyedül használják a gépet, amit egy időosztásos környezetben joggal elvárhatnának. Sőt, az a benyomásuk, hogy a gépet valami elűzhetetlen szellemek állandóan "meg-megfogják". A TSO szolgáltatást a felhasználók természetesen parancsnyelven vehetik igénybe. A TSO parancsok vertikalitása azonban még koránt sem olyan erős, mint például a UNIX-é. A várható reakció az, hogy a parancsok paraméterezése bonyolult, amiben örökölte a JCL nyelv e hátrányos tulajdonságát. A dolgon az IBM úgy próbált segíteni, hogy a vertikalitást a parancsokon belül növelte meg. A parancsok jó része olyan, hogy először alparancsokat kell vele aktivizálnunk, és azokat kell tovább paramétereznünk. Ez a hierarchia tulajdonképpen elég kényelmes kezelésmódot ad a kontextusfüggően működő Help (segítségnyújtás) funkcióval együtt, amely utóbbi a meghívásakor mindig az adott alparancs környezetében aktuális segítségszöveget írja ki a terminálra (de többek sajnálatára nagyon tömör yankee nyelven!). Ez annak idején forradalmian új dolog volt, ma viszont egy ilyen Help nélküli szoftvert nem is vesznek igazán komolyan. A TSO interaktív programfejlesztő alrendszer céljára készült. A szolgáltatásait tehát a programozók kiszolgálásához igazították. Ezt mutatja az, hogy az EDIT szövegszerkesztő parancs -- számos alparancsával együtt -- kifejezetten a programírás támogatására van kitanítva. A szövegszerkesztő például ügyelni tud a forrásnyelv szintaxisára, ha jelezzük neki, hogy milyen nyelven írjuk a programot. Sajnos az editor még a régi írógépes terminálokat tételezi fel, ezért sororientált. A mai képernyős terminálokon már nem is szokták használni, hanem valamilyen videoeditorral helyettesítik (pl. a GUTS editorral). A TSO más oldalról azt is hivatott biztosítani, hogy a TSO felhasználó szükség esetén igénybe tudja venni az OS alaprendszer különféle szolgáltatásait is. Ez a SUBMIT parancson keresztül valósítható meg, amivel egy szövegszerkesztővel összeállított munkát (job-ot) fel lehet adni kötegelt feldolgozásra. Az eredményt visszakérhetjük a terminálra. Az ilyen jellegű kapcsolat igénye azzal a következménnyel jár, hogy az interaktív rendszerben az adaterőforrásokkal való gazdálkodást nem választhatjuk meg akárhogyan. Bele kell illeszkedni az OS állománykezelési szisztémájába. Az adatterület allokálás szabályait ezért erősen a kötegelt rendszer követelményei motiválják. A terminálfel-használótól kicsit is bonyolultabb feladat esetén olyan szabályok ismeretét kívánják meg, amelyeket normálisan csak a kötegelt alkalmazónak kell ismernie.
Az interaktivitást a SUBMIT parancs nem biztosítja, az lényegében csak a korábbi RJE távoli kötegelt feldolgozás kiváltását jelenti. A programok interaktív használatát a CALL paranccsal érhetjük el. A CALL paranccsal kérhetjük az OS-t, hogy az aktivizálni kívánt programot töltse be a tárba, és működése közben kapcsoljon össze bennünket a programmal. A TSO parancsnyelv további parancsai rendszerinformációk kilistáztatását, erőforrások (adatállományok, könyvtárak stb.) lefoglalását, hozzárendelését, és segédprogram funkciók végrehajtását teszik lehetővé. Speciális alkalmazása a TSO-nak, hogy a TSO terminálok -- korlátozott jogkörökkel -- operátori konzolként is használhatók. Ezzel a többkonzolos üzemmóddal el lehet kerülni például a rendszerleállítást egy elromlott főkonzol esetén. Más lehetőség, hogy a jelszavakat külön erre a célra rendszeresített konzolon lehet csak beadni, amely ráadásul egy elzárható teremben van (ajtókulcsos védelem). A TSO kulcsszoftverei a következők: * üzenetvezérlő program, ami a távkapcsolatot bonyolítja le a központi gép és a terminálok között; * időosztás-vezérlő taszk (ez maga a TSO), amelyet az operátor indít el, felépíti az időosztásos környezet vezérlőblokkjait, és gondoskodik a TSO-résztvevők taszkjainak indításáról, az ezzel kapcsolatos tárgazdálkodásról (swappinggal ki-be cipel programokat a korlátozott számú aktív területen); * régióvezérlő taszk (RCT) egy adott aktív terület vezérlési feladatainak lebonyolítására (ez például elnyomja, és félreteszi a kiswappolandó taszk függőben lévő B/K igényeit, majd visszahozáskor gondoskodik azok újbóli feladásáról stb.); * LOGON ütemező a terminál-felhasználók előtéri munkáival való kapcsolattartásra (a terminál-kapcsolatot úgy indítja, mintha egy végtelen hosszúságú JOB lenne, és ehhez a JCL kártyákat maga generálja); * terminálmonitor program képezi magát az alrendszeri interfészt, amely a felhasználó parancsainak értelmezésére behívja a megfelelő parancsértelmezőt, és lekezeli a speciális eseményeket (hibákat); * parancsértelmezők a felhasználó üzeneteinek értelmezésére és a kívánt szolgáltatások aktivizálására; * rendszermeghajtó, amely az egész TSO alrendszeri környezet, és az alapoperációs rendszer kapcsolattartását szabályozza, és amelynek paraméterezésével hangolható be a TSO alrendszer az adott installáció speciális igényei szerint. A TSO tehát belülről is elég bonyolult hierarchiát mutat, ami a dinamikus erőforrás-kezelés megvalósításához és a felhasználók minél jobb kiszolgálásához szükséges. A TSO-t, ha nem kértek rendszergeneráláskor automatikus indítást, akkor a rendszeroperátornak kell elindítania. Utána felépül a terminálhálózaton át a terminálkapcsolat, amelynek meglétét a terminál-felhasználók a képernyőn megjelenő üzenetből vehetik észre. Ekkor lehet beadni a LOGON parancsot, melynek paraméterei a bejelentkezési név és jelszó. Bejelentkezés után már működik a Help rendszer, ami a parancsnyelv megtanulását jelentősen megkönnyíti. A TSO parancsnyelv használata ugyan nem sokkal, de könnyíti az OS használatát. A könnyítést azonban még fokozták a TSO-hoz csatlakozó újabb szoftverekkel, amelyek már a képernyős terminálok sajátosságait és a menütechnikát is kihasználták. Ilyen szoftver az SPF (Structured Programming
Facility) és annak továbbfejlesztett, módosított változatai (pl. magyarított UNI).
5.8.2 Nyilvános adatbázis szolgáltatások Az adatbázis--kezelő rendszereket többnyire szintén úgy szokták kiépíteni, hogy azok alrendszert képezzenek. Az adatbázis alkalmazók ugyanis rendszerint elég elhatárolt felhasználói kört jelentenek, többnyire egy szervezet ezzel megbízott ügyintézői tartanak vele kapcsolatot. Ez a feltétel tipikusan olyan, mint amit az alrendszerek kapcsán emlegettünk (szűk alkalmazói körnek kell egyszerűsített szolgáltatásokat nyújtani). A profi adatbázis-kezelő környezetekben van egy szűklétszámú csapat, az adatadminisztrátorok csoportja (ez sokszor egyetlen embert jelent, ami biztonságtechnikai szempontból nem mondható szerencsésnek!). Ez a csoport felelős az adatbázis szerkezeti jellemzőinek kézbentartásáért. A többi alkalmazó ilyen kérdésekbe nem szólhat bele, sőt, nem is ajánlatos, hogy beleszóljon, mert az anarchiához vezetne. Az alrendszeri interfésznek tehát ilyen esetben meg kell akadályoznia azt, hogy az adatbázis szerkezetét illetéktelenek megváltoztathassák. Alapvetően fontos szerep jut tehát a védelmi rendszernek, de ez az erőszakos rendszer a felhasználók érdekeit szolgálja. Ennek egyik tipikus következménye, hogy az alkalmazói programozók csak az adott problémához szükséges adatokhoz férhetnek hozzá az adatbázisból, másokhoz nem. Ez a korlátozásnak tűnő körülmény végeredményben komoly programozási könnyebbséget jelent. A programozónak nem kell terjedelmes adatrekordokból kibogarásznia az algoritmusához szükséges adatokat, mert közvetlenül az algoritmushoz szükséges adatokat kapja kézhez. Kifejezetten a problémára koncentrálhat. Az adatbázis--technika az ügyviteli feldolgozásban jelentős sikereket ért el, különösen a nem számítástechnikai képzettségű alkalmazói körrel tartható jó kapcsolatteremtés tekintetében. Nagyon hatásos eredménye az is, hogy a problémákat adatfüggetlen módon lehet számítástechnikai modellé alakítani, és az adatstruktúrák hatásait ki lehet küszöbölni az algoritmusokból. Ezek persze inkább programozás-technikai tárgyhoz tartozó témakörök. Minket az egészből az érdekel, hogyan szeparálja alkalmas alrendszeri interfészekkel az adatbázis--technika az alkalmazókat: az adatadminisztrátorokat, a programozókat és a végfelhasználókat. Az adatbázis--technika sokáig csak az ügyviteli adatfeldolgozások körében könyvelhetett el magának ilyen sikereket. Kicsit késve, de a mérnöki munkában is teret kapott a bonyolult számítógéppel segített rendszerekben (pl. CAD), amelyekben az egyedileg megoldott részfeladatok algoritmusainak integrálása az egységes interfész hiánya miatt sok gondot okozott a korábbiakban. A helyzeten a műszaki számításokban is csak az egységes interfészt biztosító adatbázis--technika igénybevételével lehetett segíteni. Ezeknek az adatbázis interfészeknek biztosítania kellett, hogy az őket felhasználó mérnököknek, kutatóknak ne kelljen rettenetes mennyiségű számítástechnikai ismeretet elsajátítania ahhoz, hogy használni tudják őket, különben a sutba dobták volna. Manapság az információéhség egyre jobban növekszik, és igen széles néptömegek kezdenek adatbázis szolgáltatások után érdeklődni. Ez a szituáció azt igényelte, hogy az adatbázis--kezelő rendszerek tervezői az ilyen széleskörű alkalmazói körhöz igazodó interfészeket dolgozzanak ki. Ezeket hívják nyilvános adatbázis szolgáltatásoknak. Nyilvános adatbázis szolgáltatásokat ma már otthon, a lakásból, a házi telefonon át igénybe lehet venni, ahol ezek a szolgáltatások már beindultak (a Magyar Posta jóvoltából nálunk is, csak az árfekvés nem tesz lehetővé túl széles alkalmazói kört -- még 2000 tájékán sem!, ZSP,2K.9.24.). A terminálbillentyűzetet --ha nem éppen a telefonkészülékkel, akkor -- valamilyen egyszerű, olcsó eszközzel oldják meg, a megjelenítés pedig a házi TV készüléken történik. Ez nagyon
ökonomikusnak tűnik, de a kapcsolathoz tartozik még egy elég bonyolult vezérlő elektronika is. Ezt azonban általában nem kell megvenni, hanem a postáktól lehet bérelni. A vezérlő elektronika építi fel a kapcsolatot az adatbázissal, amelyből adatokat hívhatunk le, sőt, el is helyezhetünk benne adatokat. A tárolt adatok között szerepelhet például az elektronikus csekkszámlánk, amelynek terhére vásárolni lehet az adatbázisból kiolvasott hirdetések alapján. Franciaországban ilyen nyilvános adatbázisba helyezték el a telefonkönyvet, amelyet ezek után elektronikusan állandóan naprakészen lehet tartani, és ráadásul évente egy kiserdőnyi fát lehet megmenteni azzal, hogy nem kell az egészet könyv alakban megjelentetni. Közben a világháló nálunk is elkezdett tért hódítani, rettenetesen sok információt zúdítva a hétköznapi alkalmazókra. Továbbá segíti őket szinte az élet minden területén. Talán kiegyenlíti a világ gazdaságilag különböző fejlettségű régióiban élő népek lehetőségeit is. Különösen, ha élnek vele! (2001-04-16, ZSP)
5.9. Gyakorlatok 5.9.1.
Mit nevezünk rendszerszolgáltatásoknak?
5.9.2.
Milyen a viszony a rendszerszolgáltatások, a rendszermag és a segédprogramok között?
5.9.3.
Mi a feladata a rendszerolvasónak?
5.9.4.
Hogyan indulnak a rendszerszolgáltatások folyamatai?
5.9.5.
Mit csinál a rendszernyomtató, és honnan veszi a bemenetét?
5.9.6.
Mi a szoftver spooling szerepe a mai operációs rendszerekben?
5.9.7.
Miért kellenek a betöltőprogramok?
5.9.8.
Hogyan történik a programbetöltés?
5.9.9.
Milyenek a fix, és az áthelyezhető programok?
5.9.10.
Miért nem segédprogram a szerkesztőprogram?
5.9.11.
Hogyan indul, és hogyan működik a főütemező?
5.9.12.
Mi a szerepe a közbenső szintű ütemezőnek?
5.9.13.
Mi az alrendszerek feladata?
5.9.14.
Milyen elemekből épül fel egy programfejlesztő alrendszer?
5.9.15.
Milyen feladatokat lát el az IBM JES és a POWER?
5.9.16.
Mi a TSO feladata?
5.9.17.
Hogyan kell a TSO munkát megkezdeni és befejezni?
5.9.18.
Milyen főbb TSO parancsokat ismertünk meg?
5.9.19.
Hogyan lehet TSO alatt ASSEMBLY programokat belőni?
5. A házi TV készüléken keresztül milyen számítógépes szolgáltatásokat vehetünk igénybe?
OS06v21.rtf,2001-04-16,ZSP,végleges
6. BELSŐ ARCHITEKTÚRA
A következő fejezetekben az operációs rendszeri réteghez tartozó szoftver működési és megvalósítási elveivel foglalkozunk. Ahol lehet algoritmus mintapéldákat is adunk. A mintapéldák megértése a PASCAL nyelv elemi ismeretére támaszkodik, de valószínűleg a PASCAL-t nem ismerők is azonnal átlátják az algoritmusok lényegét.
6.1. A rendszermag (kernel) A számítógépes rendszer hierarchikus strukturálódása az operációs rendszeri rétegben tovább folytatódik. A probléma gyökere az, hogy vannak olyan közös rutinok, amelyeket a számítógépes rendszer minden eleme célszerűen közösen használ (az operációs rendszeri réteget megvalósító szoftverrutinok is, természetesen). Minthogy ezekhez minden felhasználónak hozzá kell férnie, csak megfelelően alacsony szinten helyezkedhetnek el. Az operációs rendszeri réteg ennek folytán de facto hierarchikusan strukturált architektúrájú (tehát akkor is, ha eredetileg nem terveztek bele ilyenfajta struktúrát!). A felsőbb szoftverrétegek rutinjai az alsóbb (al)rétegek szolgáltatásaira épülnek. Az operációs rendszeri réteget megvalósító szoftver igen változó méretű szokott lenni az operációs rendszertől elvárt szolgáltatáshalmaz nagyságának függvényében. A bináris programméretek 1 kilobájttól akár több megabájtig terjedhetnek, és emellett igen sok programmodulból tevődhetnek össze. 6.1.1. A rendszermag szerepe Az operációs rendszeri réteg felsőbb rétegeiből intenzíven használt közös rutinokat a rendszermagnak (idegen szavakkal: kernelnek, supervisornak, monitornak, master control programnak stb.) nevezett szoftvermodulba szokták integrálni. Mint látni fogjuk, ez nem egyetlen, összefüggő algoritmusú program. Inkább azt mondhatjuk, hogy kényszerűségből összeötvözött szubrutin- és adattáblázat--együttes, amelynek komponensei azonban ténylegesen csak együttesen képesek a rendszermagtól elvárt szolgáltatásokat nyújtani. A már többször emlegetett, közösen használható rutinok alapvetően kétfélék: * a hardver utasításkészlet bővítményei (melyeket korábban mikroprogramokként emlegettünk); * a hardver sorrendképző (prioritási) és multiprogramozást támogató mechanizmusainak a kiterjesztései. A rendszermagok mérete ugyanúgy erősen változó, mint az operációs rendszereké. Szintén a szolgáltatáshalmaz függvényében 1 kilobájttól akár 1 Mbájtig terjedhet.
A nagyméretű rendszermagok tipikus funkcióhalmaza: * mikroprogramok (nem létező hardverutasítások emulátorai: decimális, lebegőpontos aritmetika stb.); * megszakításkezelés; * hívó- és hívott folyamatok állapotának vezérlése, követése; * folyamat-szinkronizáció; * a védelmi rendszer működtetése; * erőforrás--kezelés; * ütemezések; * eseménystatisztika és -elemzés; * a rendszerkönyvtárak kezelése stb. Ez a felsorolás láthatóan átfedést mutat a 2.1.-ben elemzett rendszeradminisztrációs funkciókkal. A rendszermagot megvalósító szoftverelemek jó része tárrezidens, más része tranziens rutin (tehát csak szükség esetén -- átmenetileg -- kerül be az operatív tárba). Egyes megvalósításokban a tranziens rutinokat szorosan a rendszermaghoz tartozónak veszik. Ennek az az alapja, hogy ezek az operációs rendszerek a hardvererőforrások függvényében konfigurálhatók úgy is, hogy a sűrűn használt tranziens rutinok állandó helyet kapnak az operatív tárban az úgynevezett rezidens területen, akárcsak a rendszermag fixen címzett része (ez a helyzet az IBM 360/370 OS rendszerekben, mint ezt a 2.5.-ben már említettük). Más megvalósítások rendszermagon csak a CPU által állandóan elérhető rutinokat értik. A rendszermag szolgáltatásait megvalósító rutinok -- működésüket tekintve -- két csoportba sorolhatók: * Rendszerprimitívek: rövid, egyszeri lefutású, általában nem megszakítható programok, amelyek igénybevétele során nem keletkezik bejegyzés a rendszernyilvántartásokban; * Folyamatként futó rendszerrutinok: rendszerszubrutinok, melyeket több folyamat szimultán, konkurens módon közösen használ, és amelyek minden megkezdett felhasználása bejegyzést okoz a rendszernyilvántartásokban, nevezetesen: külön folyamatvezérlő blokkot kap. A rendszermag rutinjai -- akár primitívként, akár folyamatként futnak, -- privilegizált üzemmódot igényelnek, hogy más rutinok ne zavarhassák meg véletlenül a működésüket. Ha a hardver több, nem egyenrangú, privilegizált állapottal is rendelkezik, akkor a rendszermag rutinjainak működtetéséhez a legmegfelelőbb privilégiumokat biztosító állapotot kell kiválasztani. 6.1.2. A rendszermag struktúrája A rendszermag strukturálódását több szempont befolyásolja. Ezek közül a leglényegesebbek a védelmi rendszer megszervezésének igényei. Ennek az az oka, hogy a rendszermagon belül -- ahol sajnos a privilegizált állapot miatt "mindent szabad csinálni" -- az egyes rutinokat valahogy egymás ellen is védeni kellene, nehogy szoftverhiba esetén a hibás rutin korlátlanul
"garázdálkodhasson", és óriási károkat okozzon. Sajnos erre a szempontra a korai operációs rendszerekben nem eléggé ügyeltek, ami szoftverhibák javítása ürügyén újabb hibák tömkelegét okozta az újabb és újabb verziókban. (Tipikus példaként mesélik, hogy az IBM OS--ben egy-egy módosításban kb. 3000 hibát próbáltak kijavítani, miközben újabb 2000-t okoztak. Ezért járja a szólás: "Mik az újak egy új operációs rendszeri verzióban?" -- "A hibák!" A felhasználóknak persze csak ezek fájnak.) A korai operációs rendszerek rossz szoftverarchitektúrája miatt volt ilyen nehéz a módosítás. Egy adott ponton végrehajtott változtatás hatása igen sok szinten jelentkezhetett, és az időbeli dinamikát is figyelembe véve az eredmény beláthatatlan volt. Ez ellen hosszas teszteléssel próbáltak védekezni, de hasztalan. A körülmények a matematika indirekt bizonyítási módszeréhez hasonlatosak, ahol már egyetlen ellenpélda is megdönti egy tétel igazságát, hiába sorolunk fel ezer olyan konkrét esetet, amely a tételt nem sérti. A programműködés helyességének bizonyítása sem oldható meg sikeres tesztfutásokkal. A működés helyességének bizonyítására pedig csak akkor lehet egyáltalán vállalkozni, ha minél kisebb önálló részekre tudjuk bontani a vizsgált programcsomagot. A felbontás célja, hogy az egyes rutinok működése minél áttekinthetőbb legyen, és ne függjön össze gátlástalanul minden mindennel. Az egyes modulok között jól rögzített interfészeket kell definiálni, amelyeket nem szabad megkerülni. A rétegzési filozófiát az IBM OS/2 operációs rendszer szoftver-architektúrájának példáján mutatjuk be. Mint már említettük, az OS/2 az INTEL 80286/80386-os mikroprocesszorok hardver-lehetőségeire épül. Ezek a mikroprocesszorok négyszintű privilegizált állapothalmazzal rendelkeznek (l. 1.5.-ben). Az OS/2 architektúrája ennek alapos kihasználásával az alábbi négyrétegű struktúra: +-------------------------------+ | Alkalmazói szint | 3 |-------------------------------| | Parancsértelmező szint | 2 |------------A-P-I--------------| | B/K szint | 1 ^ |-------------------------------| | Kernel | Rendszerhívások szintje | 0 v +-------------------------------+ (API = Application Programming Interface) A rétegek jobb oldalán a 0--3 szintszámok jelzik, hogy az adott réteg melyik hardvervédelmi szintet használhatja. A 0-s védelmi szint biztosítja a legnagyobb privilégiumokat, míg a 3-as szint a processzor nem vezérlő, normál felhasználói állapotát jelenti, amely minden védelmet bekapcsol. A normál állapotban minden védelmi szabály megsértése hardvermegszakítást okoz. A rétegezés célja pont ez: ki akarjuk venni a felhasználó kezéből a "veszélyes" utasítások végrehajtásának jogát azért, hogy a multiprogramozott környezetben "igazságot tudjunk tenni" a futó programok között. Mint látható, a további rétegszinteken az OS/2 saját rutinjai között is szabályozza a privilégiumokat. Még a kernel is két szintet használ: a B/K rutinok kevesebb joggal rendelkeznek, mint az alapvető rendszerhívások. A 2-es parancsértelmező szint felhasználható arra, hogy a profi alkalmazók speciális parancsértelmezőt írhassanak. Ez a parancsértelmező rendelkezik bizonyos privilégiumokkal, de még mindig a kernel ellenőrzése alatt működik, tehát védekezni lehet az esetleges hibás működése ellen. Az OS/2 specialitása, hogy -- vélhetően kifejezetten rendszerprogramozók számára -lehetőséget ad arra is, hogy közvetlen B/K szinten dolgozhassunk. Ez olyan, mintha "le tudnánk szállni" eggyel mélyebb védelmi szintre is, de a valóságban a B/K műveletek védelmi szintszámát emelik magasabbra ideiglenesen. Erre azért van szükség, mert bizonyos perifériák kezelését
máshogyan nem lehet gazdaságosan megoldani (pl. fullscreen videomonitor funkciók). Az OS/2 még ebben a "nagyon veszélyes" állapotban is kézben tudja tartani a dolgokat, hiszen a 0-s szintű rutinok védelmei még mindig működnek. Az OS/2 kernel szolgáltatásai az Alkalmazói programozási interfészen (angol rövidítése: API, l. fentebb) keresztül érhetők el. Azonban nem minden kernelrutin működik hívható szubrutinként. A kernelrutinoknak kell lekezelnie a megszakításokat, vezérelnie kell az OS/2 környezetben futó konkurens folyamatokat stb. A megszakítások időnként nem igazi hibaként lépnek fel, hanem "kiprovokálják" az OS/2 speciális rutinjainak működésbe lépését. Ilyen eset a virtuális tár lapozási igénye, azaz mikor egy program olyan programrészre hivatkozik, amelyik nincs benn a valós operatív tárban. Az OS/2 ezt a hibát megpróbálja elhárítani a hiányzó programrész vagy adat "belapozásával", és ha ez sikerül, akkor újraindítja a programot annál az utasításnál, ahol a szegmenshiba megszakítás jelentkezett. Ezeknek a rutinoknak persze a kernel legalsó rétegében kell elhelyezkedniük, hiszen működésükhöz minden védelmen át kell tudni lépniük. A B/K rutinok működtetését azonban már célszerű bizonyos védelmek fenntartásával végezni, ezért a B/K rutinok magasabb rétegbe kerültek. (A B/K rutinoknak az alacsonyabb szinten lévő zárkezelő rutinokat kell használniuk, amelyről itt csak később lesz szó.) Összességében elmondható, hogy az OS/2 az INTEL hardver igen alapos kihasználásával megkonstruált, korszerű architektúrájú szoftver. (Ez azonban még nem ad neki feltétlen és főleg azonnali piaci sikert!) Az OS/2 négy hardvervédelmi szintre támaszkodhat. Ez nem jelenti azt, hogy belső rétegződésének feltétlen erre a négy szintre kell korlátozódnia. Az egyes védelmi szinteken további finomabb rétegezést is alkalmazni kell az egyes funkciókban kezelt adatstruktúrák védelmére. Az operációs rendszerekben ezért szoftver védelmi szinteket is szervezni szoktak. Ezek működése azon alapul, hogy a kapcsolattartó rutinok betartják az előírt interfész szabályokat. Ez -- emberi tévedések miatt -- tökéletesen nem valósítható meg, tehát a szoftver alapú védelmek sérülékenyek. Korábban, amikor még "elhitték", hogy az operációs rendszeri rutinok nem szegik meg ezeket a szabályokat, csak az alkalmazók elleni védelmek szervezésére koncentráltak. Ma már programhelyesség-bizonyítási módszereket is be lehet vetni a küzdelembe. Használják az adatrejtés módszerét is, amely a magasabb rétegek elől elfedi a rutinok működtetéséhez használt adatszerkezeteket, szemben a korai állapotokkal, amikor a programozók az operációs rendszer ezernyi táblázatában "turkálhattak". Nem kell talán indokolni, mekkora előny, ha tapasztalatlan alkalmazók nem forgathatják fel a rendszer vezérlőadatait. 6.1.3 A T.H.E. architektúra Most bemutatjuk azt az operációs rendszeri architektúrát, amelynek konstrukciós elvei a világon először adtak olyan reményt, hogy azok alapján megbízhatóan működő operációs rendszereket lehet tervezni. A sokat ígérő megoldás Dijkstra-tól származik, és a T.H.E. operációs rendszerről írt cikkében szerepel. A T.H.E. rövidítés a szülőhelynek, a hollandiai Eindhoveni Műszaki Főiskolának nevét takarja. Dijkstra a T.H.E.-ben a következő fő elvet dolgozta ki: Az operációs rendszeri funkciókat jól definiált rétegekbe kell csomagolni, és ezek a rétegek hierarchikusan épüljenek egymásra, tehát a felsőbb rétegek csak az alsóbb szintű rétegek szolgáltatásait vegyék igénybe. Dijkstra másik jelentős eredménye a T.H.E. operációs rendszer kapcsán a csak szekvenciálisan felhasználható erőforrások zármechanizmussal védett használatának megoldása szemaforokkal és szemaforműveletekkel. Ez a szinkronizálás, amiről később bővebben is szó lesz a konkurens
folyamatoknál (l. 12. fejezet). Mint már korábban is szóba került, az operációs rendszer alapvetően kétféle ütemezési feladatot lát el: (1) a CPU ütemezését, azaz megosztását a multiprogramozásban részt vevő programok között (ezt nevezzük CPU multiplexelésnek), és (2) a rendszer összes többi erőforrásának koordinált szétosztását a versengő felhasználók között. Ennek megfelelően az operációs rendszer legmélyebb rétegének minimum egy CPU ütemezőt (alacsony szintű ütemezőt, elterjedt elnevezéssel: diszpécsert) és az erőforrás--gazdálkodáshoz szükséges zármechanizmust kell tartalmaznia. A többi réteg működése ezekre épül. A diszpécser olyan algoritmus, amely a központi feldolgozó egységet (CPU--t) kiveszi az egyik program uralma (angolul: control) alól, és átadja egy másiknak. A diszpécser "vezénylete" alatt működő programok, amelyeket ilyenkor folyamatoknak tekintünk, úgy viselkednek, mint az 1.1.ben már említett, ütemezett párhuzamos (szimultán konkurens, azaz versengő) folyamatok. A diszpécser az ütemezést a felügyelt programok működésére való (bármilyen) tekintet nélkül végzi. A programok nem is avatkozhatnak bele "sorsukba". A legtöbb operációs rendszerben azonban van arra lehetőség, hogy a programok kérhessék működésük felfüggesztését, amíg valami miatt várakozásra kényszerülnek. Nem lenne üdvös ugyanis, ha ilyenkor a program valamilyen CPU-időt pazarló, üres ciklusban "malmozna". Így egy program "eleresztheti" a CPU-t, de maximum ez, amivel az ütemezésbe beleszólhat. A diszpécser többféle ok miatt veheti el a CPU-vezérlés jogát egy futó programtól: * a program, mint említettük, önmaga lemondhat a vezérlés jogáról; * a program B/K műveletet kezdeményez, amire úgyis várni kell; * a megszakítási esemény kiértékelése alapján a működést vissza/át lehet/kell adni valamely korábban megszakított, adott erőforrásra várakozó programnak; * időosztásos üzemmódban lejárt a programnak szánt időszelet. Az ütemezés algoritmusa eseményekhez fűződik, amelyek az előbb említettekhez kapcsolódva az alábbiak lehetnek: * hardvermegszakítások; * "óramegszakítás", mint a CPU időszeletelés lebonyolítását lehetővé tevő speciális hardvermegszakítás; * szoftvermegszakítások, amellyel az operációs rendszeri szolgáltatásokat speciális, megszakítást okozó hardverutasítással lehet igénybe venni; * operátori beavatkozás, ami a kezelőpulton elhelyezett gomb hatására hardver úton aktivizálódik; * terminál-felhasználói kérelem, amit a hardver rendszerint a terminálok ciklikus figyelése alapján vesz észre stb. Az események után a diszpécser mindig körülnéz, hogy el kell-e venni az utoljára futó programtól a vezérlést, és ha igen, ki a következő jogosult (időosztásos vezérlésnél), vagy kinek a munkája sürgősebb (prioritásos vezérlés), akinek oda kell adni a vezérlés jogát. A konkrét algoritmusok persze bonyolultabbak az itt vázoltnál. Ezekről bővebben a 9. fejezetben lesz szó.
A diszpécser a felsőbb szintű ütemezőkkel (l. 4. fejezet) beütemezett munkák folyamatvezérlő blokkjainak (angolul: PCB) várakozó sorát kezeli. A programot a diszpécser felé egy PCB képvisel, amelyben a program megszakítási állapotvektora, üzemi állapota, folyamatazonosítója és más jellemzői szerepelnek. A zármechanizmus (mint említettük), a CPU-n kívüli többi számítógépes erőforrásokra vonatkozó felhasználási igények sorba állításának (szekvencializálásának) eszköze. A zármechanizmus a programok megbízásából hol megszerez (lezárás), hol szabaddá tesz (felszabadítás) bizonyos erőforrásokat. A zármechanizmusok működéséhez igen erős privilégiumokra van szükség. Működésük közben le kell tiltani még a megszakításokat is, mert egy alkalmatlan időpontban érkező megszakítás kritikus helyzetet teremthet. A 12. fejezetben erről még részletesebben lesz szó. A fentiekből azonban világos, hogy a zármechanizmus rutinjainak a rendszermag legalsó, legtöbb privilégiummal rendelkező rétegében kell elhelyezkedniük. A kritikus helyzet szemléltetésére bemutatunk egy tárfoglalási szituációt. Tegyük fel, hogy számítógépes rendszerünkben két CPU van, amelyek közös operatív táron osztozkodnak. A két processzoron természetesen izokron folyamatként párhuzamosan futhat két program. Tegyük fel, hogy mindkettő éppen tárigényt jelent be. Az 1. CPU-n futó program mondjuk 20 Kbájtot, a 2. processzoron futó pedig 32 kilobájtot kér. A két processzort közös operációs rendszerrel üzemeltetjük, ami azt jelenti, hogy a tárkezelés mindkét program számára közös. Mindkettő ugyanazt a tárfoglalási kódot fogja aktivizálni. A kód (amely az operációs rendszerekben feltétlenül megosztható szokott lenni) a két processzoron (izokron módon) nagyjából egyformán halad. Az egyik ponton a tárkezelő előveszi a szabad tármezőre vonatkozó adatokat a rendszertáblázatokból, hogy megnézze, honnan elégíthető ki a kért tárigény. A lefoglaláshoz ezután módosítania kell a vonatkozó táblázatok adatait. Amíg az egyik gépen futó tárfoglaló folyamat ezt végzi, addig a másiknak nem szabad hozzá sem nyúlnia a táblázathoz, mert esetleg félig aktualizált adatok alapján kezdene dönteni arról, hogy hol foglaljon le tármezőt a hívó program számára. Az különösen nagy zavart okozna, ha a két tárfoglaló folyamat egyidejűleg kezdené módosítani ugyanazokat a táblázati adatokat. A probléma megoldására a szabadhely táblázatokhoz való hozzáférést zárral védeni kell. Ha például az 1. gépen futó tárfoglaló folyamat ér előbb a táblázatok elővételéhez, akkor a zárat le kell zárnia, és egészen addig zárva kell tartania, amíg az összes szükséges módosítást végre nem hajtotta a táblázatokon. A 2. gépen futó tárfoglaló folyamat ily módon észreveheti, hogy a táblázatok foglaltak, és várakozik, amíg a zár ki nem nyílik. Az algoritmusok ilyen szakaszait kritikus szakaszoknak nevezik. A zárakat Dijkstra szemaforok alkalmazásával oldotta meg, amelyekre két műveletet vezetett be, a P és V műveletet. (A P és V két vonatkozó holland szó kezdőbetűje.) Szemafor legegyszerűbben bináris változóként valósítható meg (a neve legyen S), amely tehát két értéket, 0-t vagy 1-et vehet fel. Jelentse az 1-es a szabad (zöld) jelet, a 0 pedig a tilos (piros) jelet (közlekedési jelzőlámpáktól vett analógiával). Amikor egy program egy szemaforral védett erőforráshoz akar hozzáférni, akkor egy P(S) művelettel a szemafort (amelynek kezdeti értéke 1, vagyis szabad, zöld volt) átállítja 0-ra, azaz tilosra (pirosra), jelezve, hogy az erőforrás le van foglalva. A P műveletet vagy úgy programozzák, hogy addig nem hajtódik végre teljesen, amíg a szemafort valaki vissza nem állítja szabadra; vagy úgy, hogy visszaad egy válaszkódot, hogy sikerült-e a foglalás. Az utóbbi esetben a programnak addig kell ciklusban várakoznia, amíg a foglalás nem sikerül. A zárat a V(S) művelettel lehet kinyitni, esetünkben S-nek az 1-re (szabadra, zöldre) állításával, jelezve, hogy az erőforrás már szabad. Ezt a felszabadítást a lehető leggyorsabban végre is kell hajtani. A zárral védett erőforrásokat csak a kritikus szakaszon illik zárva tartani, mert különben túl sok felesleges várakozás léphet fel.
A szemaforokat a gyakorlatban nem bináris, hanem többnyire egész változókkal szokták megvalósítani. Ennek oka részben az inkrementáló/dekrementáló hardver utasítások elterjedt használatában, részben az általánosíthatóság lehetőségében keresendő. Vannak ugyanis olyan erőforrások a számítógépes rendszerben, amelyből esetleg egynél több is van, vagy korlátozott számban használható egyidejűleg. Ilyenkor a zárat csak akkor kell bezárni, ha a felső korlát kimerült. Ez egész értékekkel való számlálgatással figyelhető meg. A XENIX operációs rendszerben az alkalmazói programokban néhány szemaforokkal foglalkozó rendszerhívás alkalmazásával lehet zárakat használni. Magát a szemafort érdekes módon egy speciális állományként (szemaforállomány) valósítják meg. Az operációs rendszer a szabad/tilos információt a szemaforok állományleírásában helyezi el a megfelelő szemaforműveletek hatására. E módszer előnye, hogy független, de együttműködő programok erőforrás-kezelése is szinkronizálható ilyen zárak alkalmazásával. Ezt a példát csak azért említettük, hogy rámutassunk a szemafor elv általános céljára, és konkrét megvalósításának igen eltérő lehetőségeire. A megvalósítás módját befolyásolja, hogy milyen sebességgel kell "kapcsolnia" a szemafornak, és hogyan tudnak hozzáférni az erőforrásért versengők a szemafor állapotához. A továbbiakban betekintünk a T.H.E. architektúra rétegeibe, amelyeket a 6.1. ábrán mutatunk be. +-------+-------------+--------------------------------+ | Szint | Főfunkció | Alfunkciók | +-------+-------------+--------------------------------+ | | | | | 4. | JOB-kezelők | 1. Felhasználói folyamatok | | | | 2. Vezérlőáram--olvasó | | | | | |-------|-------------|--------------------------------| | | | | | 3. | Berendezés- | 1. Logikai/fizikai B/K | | | kezelők | 2. Pufferkezelés | | | | | |-------|-------------|--------------------------------| | | | | | 2. | Operátori | 1. Operátori kommunikáció | | | interfész | 2. Vezérlőpult--kezelés | | | | | |-------|-------------|--------------------------------| | | | | | 1. | Lapkezelő | 1. Tárkezelés | | | | 2. Virtuális tár | | | | | |-------|-------------|--------------------------------| | | | | | 0. | Mag | 1. Folyamatvezérlés | | | | 2. Szinkronizálás (zárkezelés) | | | | | +-------+-------------+--------------------------------+ 6.1. ábra. A T.H.E. architektúra rétegei. A T.H.E. operációs rendszer ötrétegű struktúrát mutat (az egyes rétegeket a 0-tól 4-ig terjedő szintszámok kódolják). A rendszermagot az alsó négy szint képezi, jóllehet a legalsó, 0. szint is a megtévesztő Mag elnevezést kapta.
A T.H.E. architektúrában a tárkezelés az 1-es szinten található. Az 1-es szint -- a helyes struktúrára adott alapelvünk szerint -- csak a 0. szint szolgáltatásait használhatja. Ugyanakkor a 0. szint egyedül önmagát hívhatja csak. Ebből az egyszerű tényből következik, hogy a 0. szintű rutinoknak abszolút tárrezidenseknek kell lenniük. Ha tranziens rutinokat is használnának, akkor azoknak tárat kellene igényelni a betöltés előtt, ami az eggyel magasabb rétegben elhelyezkedő tárkezelő szolgáltatásainak igénybevételét eredményezné. Ez sérti a struktúrára vonatkozó alapelvünket. (A Mag elnevezés tehát itt főként a 0. szint rezidens tulajdonságára utal.) Még egy érdekes következmény, hogy mivel a folyamatvezérlés a 0. szinten található, a magasabb rétegek rutinjait akár primitívként, akár folyamatként is meg lehet valósítani, hiszen folyamatvezérlési szolgáltatásra mindegyik támaszkodhat szükség esetén. A 0. szintű rutinok viszont többnyire megszakíthatatlanul, primitív műveletként futnak. Az 1-es szinten futó tárkezelő a T.H.E. architektúrában például folyamatként fut, és működéséhez használja a 0. szintű P és V zárkezelő primitíveket. A T.H.E. architektúra 2-es szintjének feladata az operátori kommunikáció támogatása. Ha megfigyeljük, ez a körülmény az egyébként szintén perifériának minősülő operátori konzolnak kiemelt kezelést biztosít. Ehhez tudni kell, hogy a T.H.E. operációs rendszer tipikus kötegelt rendszer, amelyben persze az üzemeltető személyzetnek jelentős szerepet szántak. Több érdekes következménye van annak, hogy a 2-es szintet az operátori interfésznek szánták. Mivel a perifériakezelés eggyel magasabb rétegben van, az operátori konzol kezelését a rétegen belül külön kellett megoldani. Ez némi redundanciát jelent, de mondhatnánk erre azt is, hogy elvtelen kompromisszum. (Mellesleg vegyük észre, hogy ugyanez a helyzet az 1-es szintű Lapkezelés virtuális tárkezelőjével is.) A magasabb rétegek rutinjai ezzel szemben igénybe tudtak venni operátorkonzol--szolgáltatásokat. Az operátori interfészt úgy programozták, hogy a valós konzolt virtuális konzolokra ossza fel, és az összes szolgáltatást kérő úgy érezhette, hogy neki külön operátori konzol áll a rendelkezésére. Ez akár az egyes perifériakezelő rutinok folyamataira is igaz volt, amit elég jól ki lehetett használni. A valódi konzolt lekötés/felszabadítás műveletpárral lehetett birtokba venni. A 2-es szinttől felfelé található rutinoknak már nem kellett feltétlen tárrezidensnek lenniük, hiszen betöltésükhöz igénybe lehet venni az alacsonyabb szintű Lapkezelő szolgáltatásait. A 3-as szinten elhelyezkedő Berendezéskezelők biztosítják a magasabb rétegeknek a B/K szolgáltatásokat. Ezek a T.H.E.-ben ütemezett folyamatokként futnak. Használhatják az alsóbb szintek összes szolgáltatását. Így például a B/K hibák kezelésére virtuáliskonzol--szolgáltatásokat kérhetnek a 2-es szinttől, tárigényt jelenthetnek be az 1-es szintnek az átviteli pufferek lefoglalására, és 0. szintű zármechanizmust használhatnak az ütköző B/K igények szinkronizálására. A T.H.E. architektúra legfelső, 4-es szintjén találjuk a rendszerfolyamatokat (vezérlőáram-olvasó) és az alkalmazói folyamatokat (munkákat). A vezérlőáram-olvasó gondoskodik a munkák (JOB-ok) felvételéről és indításáról, ahogy erről már a 4.10.-ben már szó volt. A munkákból létrejövő folyamatok csak az alsóbb rétegekbe csomagolt funkciók szolgáltatásainak igénybevételével jutnak hozzá a kívánt erőforrásokhoz. A rétegek interfészein át azonban a látható erőforrások gyökeresen eltérhetnek a fizikailag létező eredeti erőforrásoktól. Ezek közül példaként a virtuális tárat és a virtuális konzolt említhetjük a T.H.E. kapcsán. A rendszerfunkciók szigorúan vett hierarchikus strukturálása számos előnnyel jár az operációs rendszerek fejlesztésekor. Elvileg lehetséges az egyes rétegek független fejlesztése az előírt interfészek rögzítése után. Így kisebb modulok belövését kell végezni, és programhelyességvizsgálatok is használhatók.
A T.H.E. architektúrából talán nem azonnal világos, de a rétegekkel kapcsolatban fontos követelmény, hogy az egyes rétegek funkcióinak megvalósításához szükséges táblázatokat, adatszerkezeteket egymás elől el kell zárni, ha a hierarchiát komolyan gondoljuk. Ez a stukturált programozásban emlegetett adatrejtés módszerével érhető el. Ehhez ma a legjobb nyelvi eszközöket talán a C programozási nyelv biztosítja. A T.H.E. architektúra tervezési elveit még egyszer összefoglaljuk: * Minden szint úgy kezeli a közvetlenül alatta levő szintet, mintha huzalozott (hardwired), invariáns funkció lenne, amely mereven rögzített interfészeken keresztül érhető el. * Mindegyik szintnek csak a közvetlenül alatta levő szinthez van direkt elérése, és a mélyebb szintekről nincs tudomása. * Az információ "elrejtése" tökéletes annyiban, hogy egy adott szint számára ismeretes adatstruktúrákat csak azon a szinten lehet kezelni. Valamely szinten levő adatokra vonatkozó funkciót csak az adott szint valósít meg. Így például a kipakoló rutin semmit sem tud a pufferolásról, de a pufferkezelő sem tud semmit a berendezésekről stb. A szigorú hierarchia, és a funkciók rétegekbe csomagolása persze csak közelítésekkel és kompromisszumokkal valósítható meg. Abban az operációs rendszerek tervezői mindenesetre egyetértenek, hogy törekedni kell a hierarchikus rétegelésre. A T.H.E. architektúra 1-es és 2-es szintjéről már említettük, hogy "inognak" a majdnem elvtelen kompromisszumok miatt. A konzol kiemelt kezelésével kapcsolatban az igazság kedvéért meg kell jegyezni, hogy a konzolt szinte minden operációs rendszerben kiemelten kezelik (jellemző "kórtünet"). A T.H.E. esetében a virtuális konzol elv bevezetésének igénye érthetőbbé válik, ha figyelembe vesszük, hogy akkoriban terminálok még nem voltak. Így a virtuális konzol az interaktív eszközök irányába tett progresszív törekvésként értékelhető. Ami a virtuális tárkezelést illeti, más operációs rendszerekben is előfordul külön B/K kezelő a virtuális tár háttértárának kezelésére. A T.H.E. alapját képező hardverben kimondottan erre a célra szentelt mágnesdobot alkalmaztak virtuális háttértárnak, amelynek extra kezelése ezért nem volt olyan nagy probléma. Megjegyezzük még, hogy az operációs rendszerek legerősebb struktúraromboló képződménye a megszakításkezelés. A megszakítás-kezelők ugyanis előszeretettel igénylik a különböző rétegekbe rejtett táblázatokhoz való hozzáférést. 6.1.4. A szolgáltatáskérések formái A 2. fejezetben említettük, hogy alacsony és magas szintű rendszerszolgáltatások vannak. A magas szintű szolgáltatásokat részben a rendszermaghoz csatlakozó rendszerfolyamatok (vezérlő-áram-olvasó, főütemező, listázóprogram, iniciátorok és terminátorok stb.), részben a rendszerközeli szoftver (segédprogramok, angolul: utilities) biztosítják. A rendszerfolyamatokat a 4.10.-ben tárgyaltuk, most részletesebben a rendszerközeli szoftverre térünk ki. A rendszerközeli szoftver olyan általánosan használható programok halmaza, amelyet általában az operációs rendszer, mint szoftvercsomag részeként szállítanak. Ezért "gyári szoftvernek" is nevezik. Ezek a programok egyszerűen és jól paraméterezhetők, és így idomíthatók konkrét adatfeldolgozási feladatokhoz. A következő főbb funkciókat szokták megvalósítani: * állománymentő és visszaállító programok adat- és rendszervédelmi feladatokhoz;
* állománymásoló és -konvertáló programok; * rendszerkatalógusok karbantartását és listázását végző programok; * program- és adatkönyvtárak kezelésére szakosodott programok; * rendező-, össze- és szétválogató programok; * alacsony szintű operációs rendszeri szolgáltatások ellenőrzött és rendszabályozott elérése magas szintű interfészen át (például: jelszómódosítás, hozzáférési jogkörök változtatása stb.); * szövegszerkesztők (editorok), amelyek a terminálok megjelenésével váltak döntő fontosságúvá; * egyéb, univerzálisan használható program(csomag)ok. Minthogy ezek a segédprogramok a rendszermagnak csak a felhasználói, itt részleteiben most nem velük, hanem inkább az alacsony szintű interfésszel foglalkozunk. Az alacsony szintű szolgáltatásokat nem a végfelhasználók, hanem a szoftverfejlesztők, a programozók használják (illetve munkájuk eredményeként azok a programok, amiket megírnak). Az alacsony szintű szolgáltatásokat csak programokból lehet igénybe venni. Az igénybevétel módját rendszerhívásoknak nevezzük. Ezek -- lényegüket tekintve -- eljáráshívások, de az eljárások törzse a rendszermagban helyezkedik el, és ezért privilegizált üzemmódban dolgozhat. A hívások megvalósítási módja programnyelvenként változhat. A magas szintű programozási nyelvekben olykor a normál eljárások hívásával azonos előírások szerint lehet őket kódolni, de elterjedtebb az, hogy a rendszerhívások módja eltérő, és egyes hívások implicit módon hajtódnak végre egyes programnyelvi objektumok hatására (például: OPEN, CLOSE stb.). Az alacsony szintű programozási nyelvekben a rendszerhívás erősen eltér a normál eljárások hívásától. A rendszerhívásokhoz más hardver gépi utasítást kell használni, mint a normál szubrutinhívásokhoz. Ennek oka a tárvédelemben keresendő. A normál programnak a rendszermag területére tilos belépnie. Ez a tiltás csak úgy oldható fel, ha van olyan hardverutasítás, amely a processzort átlendíti vezérlőmódba. A megoldás a már többször említett szoftver megszakító utasítás (l. 2.2.). A helyzet az, hogy akár alacsony szintű, akár magas szintű nyelven programozunk, a lefordított, összeszerkesztett, futóképes programok végső fokon mind a szoftver megszakító utasításra támaszkodnak. A szoftver megszakító utasítás behívását a magas szintű nyelvekben a fordítóprogramok, alacsony szintű programokban pedig az úgynevezett makrohívások szervezik meg. Korábban a rendszerhívások közvetlenül csak alacsony szintű nyelveken voltak elérhetők. Ehhez hozzátartozik, hogy a rendszerhívások módját alapvetően az alacsony szintű programozáshoz optimalizálták. A fejlődés azonban abba az irányba mutat, hogy a rendszerhívásokat a magas szintű programozási nyelvek igényeihez illesszék inkább. Egészen másképpen szokták programozni ugyanis a rendszerhívásokat assembly szinten, és a magas szintű nyelvek fordítóprogramjaihoz. Az assembly programozásban a paraméterek átadása túlnyomórészt a CPU különböző regisztereit használjuk. Erre azért van lehetőség, mert egy assembly programban mindig pontosan előre ismerjük, hogy hány és milyen paramétert kell átadni a hívott rutinnak. A programozó ezeket egyszerűen kiosztja a rendelkezésre álló regiszterek között. Ez jó is neki, mert át tudja látni a helyzetet, tudja, miben, mit találhat meg. Ugyanakkor a fordítóprogramok írói a szubrutinhívásokat általános elvek szerint szervezik meg, hiszen előre nem lehet tudni, hogy hány
és milyen paramétert kezelő szubrutin fordul majd elő a programban. Ennek egyik megoldása, hogy a behívott szubrutin kap egy mutatót (például egy egyezményes CPU regiszteren át), és ez a mutató a paramétereket leíró táblázat elejére mutat. A másik módszer, ami a legújabb hardverarchitektúrákban szinte kizárólagos, hogy a hívási paramétereket veremtárba helyezik, és a hívó szubrutinnak onnan kell azokat elővennie. Az utóbbi a legkompaktabb paraméterhívási módszer. Az operációs rendszer akkor támogatja jobban a magas szintű nyelvi hívásokat, hogyha a paraméter-átvételt ezek igényei szerint szervezi. Az MS--DOS-ban az INT 21H, szoftvermegszakításokra alapított rendszerhívási szisztémát lehet használni. A paraméterek átadása az AX és BX CPU regisztereken keresztül történik. Az OS/2-ben a hívási paramétereket a veremtárba kell helyezni, a rendszerrutin onnan fogja őket felszedni azokba a regiszterekbe, amelyikbe éppen neki tetszik. A rendszerhívás az OS/2-ben makroutasítással történik. Ha az OS/2-ben egy magas szintű programban akarunk lezárni egy állományt, a fordítóprogram pontosan ugyanolyan kódkifejtést generál, mint amit az alább vázolt OS/2 hívási példa mutat. A megoldás "öszvér jellegű", mert a hibakódot az OS/2 is az AX regiszterben adja vissza, és nem a veremtáron át kapjuk meg. Az OS/2-ben ennek MS--DOS kompatibilitást biztosító szerepe van, de egyetlen, fix CPU regiszteren át érkező információt a fordítóprogramok is előnyösen tudnak hasznosítani. Példaként elemezzük az MS--DOS és az OS/2 assembly nyelvű állományzáró (CLOSE) rendszerhívást: MS--DOS: mov ax,1000h ; funkciókód--paraméter mov bx,fhandle ; "file handle" paraméter int 21h ; rendszerhívás ; szofvermegszakítással or ax,ax ; hiba volt? jnz hibakez ; igen! OS/2: push call or jnz
fhandle DosClose ax,ax hibakez
; ; ; ;
"file handle" paraméter rendszerhívás hiba volt? igen!
A rendszerhívások igen szerteágazóak; ahány rendszermag, annyi szokás. A zűrzavar talán még a hardver--utasításkészletekben mutatkozó eltéréseket is meghaladja. Igen kevés remény van valamelyes tipizálásra. A hívások egy része primitívként, más része folyamatként fut. Eltérőek lehetnek a számukra biztosított privilégiumok is. Ezek befolyásolhatják a behívás módját. Már említettük, hogy a CPU, mint erőforrás többnyire csak elereszthető egy programból. Ezért a programoknak biztosított CPU-idő erőforrással kapcsolatos szolgáltatások listája néhány várakozási igényt bejelentő rendszerhívásból áll. Például a WAIT a határozatlan, a SLEEP pedig a határozott ideig való várakoztatásra szolgál. A normál programoknak nem áll rendelkezésre az a funkció, amely a várakozások feloldásához szükséges. Erre használják az AWAKE hívást, amely értesíti a diszpécsert, hogy valamelyik rutint "fel kell ébreszteni". A következő fontos erőforrás az operatív tár vagy az esetleg létező virtuális tár. A tárkezelő funkciók közül a két legfontosabb rutin a: * GETMAIN(tárigény) a tárigények bejelentésére és a
* FREEMAIN(tárméret) a tárlekötések felszabadítására. A kívánt tárméreten kívül alkalmasint más paraméterek is felmerülhetnek, különösen virtuális tárkezelésnél. A FREEMAIN-ben például azt is nyilvánvalóan meg kell adni, hogy melyik korábbi foglalást akarjuk lemondani. A rendszerhívási funkciókat alapvetően két nagy csoportba soroljuk: rendszeradminisztrációs rutinok és B/K rutinokra. Ezeket az operációs rendszerek általában erősen megkülönböztetik. A rendszeradminisztrációs rutinok a kernel mélyebb rétegeiben lévő funkciók igénybevételét teszik lehetővé. A B/K funkciók rendszerint maguk is igénybe veszik ezeket a szolgáltatásokat, ezért kell őket mélyebb rétegben elhelyezni. Minthogy ezek a legkevésbé tipizálhatók, itt nem foglalkozunk velük részletesen, hanem a 7. fejezetben adunk rájuk példákat. A B/K rutinokat rendszerint még további osztályokba sorolják. A besorolási szempont szintén operációs rendszerenként változik. Alapvetően megkülönböztetnek fizikai és logikai adatkezelő rutinokat. A fizikai rutinok a perifériák közvetlen kezelésére szakosodott funkciók programjai, amelyeket periféria meghajtóknak is neveznek. A logikai adatkezelési funkciók pufferelési technikával (átmeneti tármezők alkalmazásával) oldják meg a fizikai berendezésen előírt adatszerkezet és az alkalmazási programban feltételezett adatstruktúra közötti konverziót. További osztályozás tárgyát képezik a támogatott logikai adatszerkezet--típusok elérési módjait biztosító funkciók. Ezek az úgynevezett adatelérési módszerek (szekvenciális, random, indexelt szekvenciális, invertált, láncolt stb.). Az 1.4.-ben említettük, hogy a perifériák alapvetően kétfélék lehetnek: blokk típusúak és karakter típusúak. A perifériameghajtók ennek megfelelően szintén két osztályba sorolhatók. A blokk típusú kezelők arra készülnek fel, hogy az adatokat csak nagyobb egységekben, adatblokkok formájában lehet átvinni a periféria és a tár között. A tipikus méretek 16 bájttól 32 kilobájtig terjedhetnek. Az átvitel meglehetősen nagy sebességű, több Mbájt/sec értéket is elérhet. Ezért ezeket a meghajtókat nevezik gyorsperiféria meghajtóknak is. A gyors perifériák emellett speciális B/K csatornákon át érhetők el, amelyek működése a CPU-tól függetlenül vezérelhető, emiatt független ütemezésre szorul. A karakter típusú meghajtók szerepe az, hogy a multiplex csatornán különböző perifériákról érkező lassú, karakterenkénti átviteleket demultiplexelje, azaz szétválogassa felhasználók szerint illetve -- ellenkező irányban -- eljuttassa a kívánt perifériához. (A multiplex csatornában azért keverednek a különböző perifériák adatai, mert ezekhez a lassú átvitelekhez nem lenne gazdaságos külön adatcsatornákat alkalmazni. A hardvercsatornán emiatt az adatok mellett az elérendő periféria címét is mindig át kell küldeni.) A fizikai szintű kezelőknek az a feladata, hogy a logikai szintű rutinok felé eltüntessék a blokktípusú és karaktertípusú átviteli sajátosságokat. Ehhez pufferelési technikát kell használni. A logikai adatkezelés, miután a perifériák fizikai sajátosságait puffereléssel eltüntettük, kétféle lehet: * blokk szintű adatelérés, és * rekord szintű adatelérés. A blokk szintű adatelérésnél a logikai adatszerkezettől valamelyest független, tőle eltérő méretű pufferekben tárolt adatokkal dolgozunk. Ennek szerepe az átvitel gyorsítása. A logikai adategységekben történő átvitel azért lassúbb, mert az adatblokkban elférő rekordokat egyenként viszi át, ami mindenképpen plusz adminisztrációs időt jelent. A szokásosan használt rendszerhívás
neve után ezt READ/WRITE szintnek nevezik. A READ/WRITE szintet a következő funkcióhalmazzal szokták támogatni: * ASSIGN, OPEN: a fizikai és logikai állományok összerendelésére és az adatátvitel előkészítésére, amely egy sereg operációs rendszeri táblázat létrehozását eredményezi; * CREATE: egy még nem létező fizikai állomány létesítésére, amelynek adatai bekerülnek a különféle katalógusokba (nem minden operációs rendszerben van ilyen rutin explicit módon); az állományt egyben meg is nyitja, de abba csak írni lehet; * READ: egy adatblokk olvasására szolgáló funkció; * WRITE: egy adatblokk írására szolgáló funkció; * REWRITE, UPDATE: ha van ilyen funkció, akkor a korábban beolvasott és közben módosított blokk visszaírására szolgál; * SEEK: pozicionálás az adatállományban egy adott című vagy sorszámú blokkra; * CLOSE, UNASSIGN: egy adatállomány lezárása. A rekord szintű elérés igazodik az alkalmazásban használt rekordszerkezethez. Ezt az általánosan használt rutinnevek miatt PUT/GET szintnek is nevezik. Az eléréshez használt makronevek nem feltétlen különböznek a READ/WRITE szintnél ismertetett készlettől, csak a READ helyett kell GET, a WRITE helyett PUT makrohívást használni. A makrók paraméterezése persze eltérő. A rekord szintű elérés elsősorban arra hivatott, hogy a különböző adatelérési módszereket támogassa, bár a blokk szintű elérésnél is használnak eltérő adatelérési módokat. A választandó adatelérési módszert OPEN időben kell meghatározni. A READ/WRITE és PUT/GET utasítások paraméterezésére az elérési módszer kevésbé szokott kihatni, amellyel a programok többé-kevésbé adatelérési módszertől független programozását igyekeznek biztosítani. Az adatok szervezésének változása esetén emiatt nem kell módosítani a programot. Ez persze csak akkor működik, ha az adatszervezésre vonatkozó információ a programon kívülről érkezik. Ez a helyzet például az IBM OS-ben, ahol ezt az adatot a vezérlőáram DD adatleíró parancsában adhatjuk meg. Az adatkezelés és a B/K programozás további részleteit meghagyjuk az adatkezeléssel foglalkozó szakirodalomnak.
6.2. Megszakításkezelés A megszakításokról a hardvertulajdonságok elemzésénél már volt szó (l. 1.4.). Most rámutatunk arra, hogy a megszakításokat kezelő -- elterjedt szakzsargonban "lekezelő" -- rutinoknak mindig a rendszermagban kell elhelyezkedniük, továbbá elemezzük vázlatos algoritmusaikat. A megszakítások során a hardver valamelyik szintű vezérlőállapotába kerül át (ha van ilyen megkülönböztetett állapota). Ez azt jelenti, hogy a megszakítás után induló kód privilegizált jogokkal rendelkezik. Minthogy a privilégiumokat egyedül az operációs rendszernek szeretnénk biztosítani, a megszakítás-kezelő rutinoknak feltétlen az operációs rendszerben kell lenniük. Tovább fontos, hogy a megszakítás-kezelők gyorsan reagáljanak a megszakítási eseményekre. Emiatt a legalapvetőbb kezelő rutinoknak feltétlen tárrezidenseknek kell lenniük. Ezekből a feltételekből következik, hogy a megszakítás-kezelők az operációs rendszerek magjában helyezkednek el (ezt az
állításunkat később még pontosítjuk). A belépés a rendszermagba (védelmi rendszerrel rendelkező hardver esetén) csak a megszakításkezelőkön keresztül érhető el. Ezután a rendszermag -- erősen hardverfüggő módon -- reagál a belépésre. Példákat az 1.4.-ben és 1.5.-ben elemeztünk. Megjegyezzük, hogy a rendszermagba való belépést olyan hardvereknél is a megszakításokon keresztül szervezik, amelyekben nincs védelmi rendszer, úgyhogy ez a rendszerrutin-hívási mód igen széles körben elterjedt. A védelmi rendszerrel nem rendelkező hardverekben a rendszermag-funkciók elvileg egyszerű szubrutinhívással is elérhetők lennének, de akkor ismerni kellene a tárban elfoglalt pontos helyüket. Néhány hardvernél ez a feltétel teljesül (például a ROM-ba égetett rutinok esetében), de az operációs rendszerek módosítgatása során a rutincímek óhatatlanul eltolódnak. Az összes program, amelyik konkrét címre hivatkozik, az új operációs rendszeri verzió felügyelete alatt működésképtelenné válna. A megszakítások, mint azt az 1.4.-ben is elemezzük, ugrótábla alapján érik el a kezelőrutinokat. Ha tehát egy rendszerfunkció hívását valamelyik megszakításra alapozottan kezeljük, akkor programjaink mindig működőképesek maradnak, mert a hardver a megszakító rutin indítását -- a szoftvertől függetlenül -- mindig ugyanarról a vektorcímről indítja. Az operációs rendszer módosításakor csak arról kell gondoskodni, hogy a megszakítási vektorba a kezelőrutin új címe kerüljön. A védelmi rendszer hiánya folytán a vektorcímet a felhasználói programból meg lehet változtatni. Ezzel a módszerrel "el lehet kapni" a rendszertől a megszakításkezelést. A személyi számítógépek körében előszeretettel használják ezt a módszert -- főként tárrezidens és a kikapcsolás ellen védekező vagy a képernyőt és billentyűzetet különlegesen kezelő, például játékprogramok esetében. Minthogy itt monoprogramozott rendszerekről van szó, a felhasználó legfeljebb magának okoz gondokat hibás megszakítás-kezelő program bekapcsolása esetén. Multiprogramozott környezetben viszont az ilyen hiba elviselhetetlen következményekkel járhat. A megszakításkezelés elvei megkövetelik, hogy minden, a hardver számára megkülönböztethető, megszakítási típushoz tartalmazzon a rendszermag egy első szintű megszakítás-kezelőt (angol rövidítéssel: FLIH = First Level Interrupt Handler). Pontosabban tehát ez az a megszakító rutin, amelynek mindig tárrezidensnek kell lennie. Az FLIH rutin hiányozhat, ha az adott konfigurációban a megfelelő megszakítástípus soha nem fordulhat elő, de a géphiba miatti "tévelygések" elkerülésére ilyenkor is szoktak használni valamilyen "csontváz" kezelőrutint. Egy FLIH rutinnak, ha megszakítás folytán megkapja a vezérlést, legfontosabb dolga, hogy azonnal letiltsa a működését induláskor zavaró -- legalább a saját típusába tartozó -- megszakításokat. Ezt addig kell fenntartani, amíg a megszakított program folytatásához szükséges adatokat, az 1.4.ben említett állapotvektort, el nem tárolta az operációs rendszer megfelelő táblázataiban. Ezzel biztosítható a procesz-szorállapot visszaállíthatósága és a program későbbi folytatása (ha erre szükség van). A megszakítás-kezelőknél ezen a "kritikus szakaszon" kell fenntartani a megszakítások tiltását. Amint a megszakító rutin túljut egy adott megszakítási osztályra vonatkozó kritikus szakaszon, a megszakítást azonnal fel kell szabadítani, hogy ne legyen túl hosszú időre elvágva a rendszer a külvilág eseményeitől. Kritikus esetekben ez ugyanis adatvesztést okozhatna (például a szinkron átvitelnél egy távfeldolgozó vonalon). Példaként elemezzük az IBM 360/370-es hardverrel használható szoftvermegszakító utasítás, a már említett SVC (SuperVisor Call) használatát a rendszerhívások lebonyolításához. Az SVC utasításnak van egy 8-bites közvetlen (az utasításba beépülő) operandusa, amelyet a hívott funkció kódjának megadására lehet használni. A kódszám maximálisan 256 féle értéket vehet fel. Ez lekorlátozza azoknak a rendszerrutinoknak a számát, amelyeket ezzel a hívási móddal aktivizálhatunk. Bár a fejlett OS/VS rendszereknél ez a szám már kezd kevésnek bizonyulni, a 200 körüli rendszerrutin készlet tulajdonképpen igen bő lehetőségekkel felruházott szolgáltatáshalmaz elérését teszi lehetővé. Meg kell jegyezni, hogy a programozási nyelvek könyvtárai ezt a híváskészletet alkalmas paraméterezéssel, és több hívás kombinálásával erősen ki tudják terjeszteni
(makrók, szubrutinok). Sokszor ezeket a tulajdonképpen nem eredeti rendszerhívásokat is a rendszerrutinok közé sorolják. Az SVC nn hívás kiadása programozott megszakítást okoz, amelynek létrejöttét most pontosan nyomon követjük. Az SVC utasítás hardver mikrokódja olyan, hogy az utasítás operandusában szereplő nn értéket félreteszi a PSW (Program Status Word = programállapotszó) megszakítás okát jelző adatmezejébe, és jelzi a hardvernek, hogy a program megszakítást kér. A 360/370-es hardver a megszakítási igényt az SVC utasítás teljes lezajlása után észleli. A PSW utasításcímet reprezentáló része ekkorra már éppen továbbmutat a program következő végrehajtandó utasítására. Ennek végrehajtása azonban nem kezdődik el, hanem a hardver a PSW tartalmát félreteszi a főtár fix mezejébe, az úgynevezett SVC Old PSW-be (régi SVC megszakítási állapotszóba), és a főtár másik fix mezejéből, az úgynevezett SVC New PSW-ből (Új SVC megszakítási állapotszóból) előveszi az SVC megszakítás-kezelő program indítási állapotát. Ez bekerül a CPU PSW regiszterébe, s ez által a CPU az SVC feldolgozórutin végrehajtását kezdi el. Vegyük észre, hogy a hardver megszakítási mechanizmusának be kellett segítenie a régi programállapot megőrzésébe! Ez a segítség abban állt, hogy a régi PSW állapotvektor SVC elemébe elmentődött a megszakított (SVC-t kiadó) program utolsó állapotjellemzőit mutató PSW tartalom. Ez a segítség azonban elég gyenge lábakon áll, hiszen egy újabb SVC megszakítás azonnal letörölné az előzőleg kimentett PSW-t. Az SVC megszakító rutinnak ezért az Old PSW-t azonnal tovább kell mentenie a megszakított program folyamatvezérlő blokkjának állapotvektorába. Az SVC-vel ráadásul még szerencsénk van, mert amíg mi a programból nem adunk ki egy újabb SVC hívást, addig SVC megszakítás nem következhet be. Letiltásával ezért nem kell foglalkozni. Az nem kötelező, hogy az SVC FLIH rutinjából ne adjunk ki Újabb SVC hívást, de nyilvánvalóan csak azután szabad, ha az állapotvektort már elmentettük. Más, például B/K megszakítás-kezelő rutin esetén le kell tiltani a megfelelő megszakításokat. Az IBM 360/370-ben például B/K csatornánként adhatunk ki megszakítástiltást az új PSW megfelelő bitjeinek beállításával. Ez is egy hardversegítség, mert a megszakítás-kezelőben már nem kell a megszakítás letiltásával foglalkozni. Az SVC FLIH az állapotvektor mentése után hozzákezd a hívás kielemzéséhez. A megszakított program PSW-jének megszakítási ok mezejéből előveszi az SVC hívás nn operandusát, és egy ugrótábla segítségével a hívott funkció feldolgozórutinjára adja a vezérlést. Ez a második szintű feldolgozó, amelynek már nem kell feltétlenül tárrezidensnek lennie, és ütemezhető folyamatként is futhat. Amikor az FLIH véget ér, a vezérlést a diszpécser kapja meg, ami a megszakítási esemény hatására beálló környezetet kielemzi, és ez alapján elindítja a következő jogosult folyamat programját. Ehhez előveszi annak állapotvektorát, betölti a megfelelő CPU regiszterekbe, majd utolsó teendőként az elmentett PSW állapotot a CPU PSW regiszterébe töltve "kiprovokálja" a program folytatását. (Ha még emlékszünk rá, az utoljára mentett PSW címszámláló mezeje már éppen a következő végrehajtandó utasításra mutatott.) Általában elmondható, hogy az FLIH legfontosabb feladata a megszakítás előtti állapot megőrzése egy védett adatszerkezetben. Ezután gondoskodik az előállt helyzet kielemzéséről, és, ha lehet, a kért szolgáltatás teljesítéséről (primitív művelet esetén), vagy megszervezi annak teljesítését (folyamatként futó rutin esetén), végül "felébreszti" a diszpécsert. A második szintű feldolgozó rutinok természetesen funkciófüggőek, úgyhogy itt nem foglalkozunk velük részletesebben.
6.3. Alacsony szintű ütemezés Az alacsony szintű ütemező, avagy diszpécser alapfeladata az, hogy kijelölje azt a folyamatot,
amely a CPU-t következőként használhatja, és biztosítsa annak folytatási feltételeit. A CPU-idő szétosztásához nem feltétlenül van szükség ütemezőprogramra. Előre ismert számú program esetén például az időosztásos szimultán üzemet magukkal a programokkal is megszerveztethetjük. Ehhez azonban a programoknak tudniuk kell egymás munkájáról. Ebből indul ki az úgynevezett Round-Robin (RR), magyarul körben forgó ütemezés, amelyet a 6.2. ábra mutat be három program esetére. Az ábrán látható példában az ütemezés lebonyolítása a következő extra igényeket támasztja az egyenkénti futáshoz képest: * Munkaterületek az összes programban az állapotvektor tárolására. * Vezérlésátadó rutin szintén minden egyes programban, amely az állapotvektor mentését és a vezérlés továbbadását végzi. * A futóképesség vizsgálatára szolgáló kód. * Helyreállító kód, amely a megszakítás előtti programállapot visszaállítását, és a program továbbindítását oldja meg. * Egy kapcsolólista és két külső változó. +---------------+ +---------------+ +---------------+ | PGM1 | | PGM2 | | PGM3 | +---------------+ +---------------+ +---------------+ | Munkaterület | | Munkaterület | | Munkaterület | |---------------| |---------------| |---------------| *===>| Futhatok? ===>| Futhatok? ===>| Futhatok? ===>* |---------------| |---------------| |---------------| | Helyreállítás | | Helyreállítás | | Helyreállítás | |---------------| |---------------| |---------------| | PGM1 kód | | PGM2 kód | | PGM3 kód | |---------------| |---------------| |---------------| | Vezérlésátadás| | Vezérlésátadás| | Vezérlésátadás| +---------------+ +---------------+ +---------------+
IX
+---------+ | 1 | +---------+ Indexregiszter
+---------+ MAX | 3 | +---------+ A kapcsolólista hossza
0. 1. 2. 3.
*===============* | Kapcsolólista | +---------------+ | PGM1 címe | +---------------+ =>| PGM2 címe | +---------------+ | PGM3 címe | +---------------+ | 0 | *===============*
6.2. ábra. Round-Robin (körben forgó) ütemezés három programmal A kapcsolólistát, az IX és MAX változókat minden programból el kell tudni érni. Az algoritmus úgy működik, hogy induláskor az IX értéke nulla, azaz, az 1-es programra mutat. Az 1-es program először megvizsgálja, hogy éppen futóképes állapotban van-e. Ha nem, akkor azonnal továbbadja a vezérlést olymódon, hogy az IX értékét 1-gyel megnöveli, és ezzel automatikusan a kapcsolólista
szerinti 2-es programot indítja el. Ha viszont futóképes, akkor a helyreállító rutint indítja, ami a CPU regisztereit -- és ezzel állapotát -- a program előző futásának megszakadásakor érvényes értékekre állítja vissza. Ezután a program algoritmusának egy előírt szakasza zajlik le, majd aktivizálódik a vezérlésátadó kód. Ez az állapotvektor munkaterületre való mentése után ilyenkor is megnöveli az IX értékét 1-gyel, és ezzel indítja a kapcsolólista IX-edik indexű elemében szereplő programot. Ha az IX elérné a MAX-ban található értéket, akkor az IX-et nullázzuk, mielőtt a következő rutinra kapcsolunk. Így belátható, hogy a három program a vezérlést egymás között körben forogva cserélgeti. Ez elég ügyetlen és gazdaságtalan ütemezési rendszernek tűnik, de mellette szól, hogy működőképes. Gazdaságosabb megoldást jelent azonban, ha a szimultán vezérlés funkcióit és adatszerkezeteit erre specializált, külön programba integráljuk. Túlnyomó többségben ezt a módszert használják. A közös diszpécserben csak egyszer kell szerepelnie a vezérlésátadó, a helyreállító, valamint a futás feltételét vizsgáló kódoknak. Így sem kerülhető el a kapcsolótábla, a két vezérlőváltozó és a programonkénti állapotvektor mentésére szolgáló munkaterületek használata. A programoknak azonban ilyenkor egyáltalán nem kell tudniuk egymásról, ami programozási szempontból előnyös lehet. Az ütemező adatstruktúrái elrejthetők a rutint tartalmazó rétegbe, és ezzel védhető a véletlen meghibásodástól. A diszpécser működéséhez tehát speciális adatstruktúrákra van szükség. Ezek közül a legfontosabb az, amely a folyamatok pillanatnyi állapotát őrzi. Ezt mi folyamatvezérlő blokknak nevezzük, de az egyes operációs rendszerekben meglehetősen különböző elnevezéseket adnak neki (aktivációs rekord, inkarnációs rekord, diszpécservezérlő blokk, taszkvezérlő blokk). Erről már több helyen is volt szó könyvünkben, itt viszont láthatjuk ennek az adatstruktúrának a közvetlen szerepét a diszpécser működésében. A folyamatvezérlő blokkokat a diszpécser táblázatként kezeli. E táblázatban minden rekord egy folyamat adatait írja le. Az ütemezés szempontjából egyformán kezelendő folyamatvezérlő blokkokat a diszpécser vagy különböző táblázatokban tartja, vagy ugyanazon a táblázaton belül összeláncolja. Emiatt a folyamatvezérlő blokkokban nemcsak egy folyamat állapotadatai, hanem a diszpécserláncok mutatómezői is benne vannak. Így a folyamatvezérlő blokkok tipikus tartalma: * név vagy más programazonosító (például folyamatsorszám); * tárolóterület (cím, hossz); * B/K hozzárendelések mutatói; * üzemállapot (státusz, futóképesség); * prioritás; * mutatók a létrehozott gyermekfolyamatok folyamatvezérlő blokkjaira, * mutatók az ütemezés szempontjából összetartozó folyamatok vezérlőblokkjainak összeláncolására stb. A tartalomból kitűnik, hogy a táblázatban más táblázatokra mutató adatok is találhatók (B/K hozzárendelések). Ténylegesen a rendszermagot vezérlő adatstruktúrák sokszorosan összeláncolt táblázatokból, listákból, sorokból állnak. Minden folyamatként kezelendő programhoz folyamatvezérlő blokknak kell tartoznia, akár felhasználói programról, akár folyamatként futó rendszerrutinról van szó. Ezért a folyamatra újabb definíciót is adhatunk: diszpécserrel ütemezhető programegység.
A lehetséges folyamatállapotokat ismét kielemezzük a diszpécser szemszögéből nézve. Eszerint a folyamotok állapota lehet: * futó, amikor a diszpécser átadta a programnak a CPU vezérlés jogát; * aktivizálható, amikor a program futóképes, de nincs nála a CPU vezérlés joga; * blokkolt, alvó, amikor azért vették el a programtól a CPU vezérlési jogát, mert éppen nem tudna továbbhaladni, vár egy esemény bekövetkezésére (például B/K átvitel végére); * (a tárból) kiszorított, amikor a diszpécser elvette a programtól a CPU vezérlés jogát, a tárkezelő pedig elvette a korábban neki adott tárterületet, és kimásolta háttértárra (swapping); * feltartóztatott, felfüggesztett, futáson kívüli, amikor a program ugyan futóképes volna, de mégsem adja meg neki a diszpécser a vezérlési jogot, mert valamilyen okból nem teheti (például operátori beavatkozással felfüggesztették a futását); * holtponti, amikor a program olyan esemény bekövetkezésére vár, amely már sohasem következhet be; * befejezett, amikor a program algoritmusa véget ért, és az operációs rendszernek el kell végeznie a folyamat megszüntetésének teendőit. A diszpécserek kifinomult működése még az itt vázoltnál is részletesebb "állapotsereget" igényelhet. Ezért ez a diszpécserek politikájának kialakításában döntő fontosságú kérdés. Ütemezéskor a diszpécser mindig csak a futóképes állapotú programok közül választhat. A programok állapotát a politika eredményeként részben az ütemező befolyásolja, de az ütemező nem tudja a folyamatokat futóképes állapotba átvinni. Ezt a feladatot a megszakítás-kezelők látják el, ezért a diszpécser a megszakítás-kezelőkkel közösen használja a vezérlőtáblázatokat. Ennek kapcsán érdemes kielemezni a blokkolt állapotok konkrét okait, amelyek a következők lehetnek: * várakozás a B/K befejeződésére; * várakozás egy zár felszabadítására; * várakozás más folyamat kimenő adataira; * lapozás (virtuális tár esetén), amikor a kívánt programrész vagy adatmező nincs benn a valós tárban; * a swapping visszatöltési folyamata zajlik stb. A megszakítás-kezelők másodszintű funkciói tudják kielemezni a vezérlőtáblázatok láncait követve, hogy melyik folyamattal kapcsolatos az éppen kezelt megszakítási esemény (például melyik folyamat B/K átvitele zajlott le). Az adott folyamat állapotát az esemény típusának megfelelően meg kell változtatni, így jelezni lehet a diszpécsernek, hogy a kérdéses folyamat már nem blokkolt, hanem futóképes. A diszpécser működését aktivizálhatja, hogy: * (1) az éppen futó program önként lemond a CPU vezérlés jogáról (a WAIT, SLEEP
rendszerhívások valamelyikével); * (2) olyan esemény következik be, ami miatt a legmagasabb prioritású folyamatot kell folytatni; * (3) az időzítő mechanizmus közbelép (lejárt a kijelölt időszelet); * (4) az operációs rendszer elveszi a folyamattól a CPU--vezérlési jogot (adott ütemezési politika döntése folytán). A fenti sorrend bizonyos történetiséget takar, amennyiben elmondható, hogy legkorábban alakult ki a prioritásvezérelt, később az időosztásos és csak legutoljára a komplex ütemezési politika. Ha a diszpécser csak az (1) feltételt veszi figyelembe, akkor politikamentes. Ha az (1) és (2) feltételre együttesen figyel, akkor a diszpécser politikája a nagy prioritású folyamatoknak kedvez, úgymond prioritásvezérelt. Az (1) és (3) feltételeket figyelembe vevő diszpécser nem kivételez a felügyelt folyamatok egyikével sem, hagyja, hogy azok egyenletesen haladjanak, de útját állja a folyamatok önkényeskedésének. A megvalósítási mód miatt ezt a politikát időosztásosnak nevezik. A további kombinációk igen bonyolult politikák megvalósítását teszik lehetővé. Ezeknek számba kell venniük azt, hogy a számítógépes rendszert az operációs rendszer alacsony és magas terhelésénél is hatékonyan lehessen üzemeltetni. Ez a működésoptimalizált politika (például IBM SRM, l. 13. fejezetet). A működésoptimalizáláshoz adatokat kell gyűjteni, ezért a vezérlőtáblázatok bonyolult politikájú diszpécserek esetén, a fentieken túl, további elemekkel bővülnek. Az operációs rendszerben nemcsak egy alacsony szintű ütemező létezhet. Ennek oka az alrendszerek alkalmazásában keresendő (vö. 5.7.-el). Az alrendszeri szolgáltatások folyamatait külön is ütemezni kell. Ezekbe beépíthető az alrendszer szempontjából kívánatos ütemezési politika, amivel tehát nem kell a legalacsonyabb szintű ütemezőt terhelni. Az alrendszeri diszpécserek persze helyzetüknél fogva csak rosszabb hatékonysággal működtethetők. Ez a probléma a tipikus alkalmazásokat figyelembe véve nem kritikus, mert a felhasználók interaktív alkalmazók, akik lassú, emberi reakcióidőkkel dolgoznak, és nem kívánnak túl gyors válaszadást. Más a helyzet a virtuális gépes rendszerekkel, ahol komplett operációs rendszerek, bonyolult politikájú diszpécserekkel működnek a virtuális gépet kezelő operációs rendszer alrendszereiként (l. 14. fejezet). Ilyenkor a hatásfokromlás meglehetősen nyomasztó lehet. Megjegyezzük, hogy a működésoptimalizálás szükségessé teszi egy harmadik, közbenső szintű ütemező alkalmazását is. Ennek okait külön fejezetben tárgyaljuk (l. 13. fejezet). A közbenső szintű ütemező figyeli a folyamatok haladását, és mért statisztikai adatok alapján beavatkozik a diszpécser várakozó soraiba. Megnövelheti például a lassan haladók prioritását, de szükség esetén az erőszakoskodókat időlegesen le is blokkolhatja (l. előbb a folyamatállapotok fajtáit). Konkrét diszpécser algoritmusokról a 9. fejezetben lesz szó.
6.4. Tárkezelési funkciók Erre a témakörre egy külön fejezetet is szántunk (10. fejezet). Itt elsősorban arra szeretnénk rámutatni, hogy a tárkezelés feltétlenül a rendszermag részének kell lennie, és meglehetősen alacsony szintű rétegben kell elhelyezkednie. Ezt persze zavarja -- mint azt már a T.H.E. architektúra kapcsán is elemeztük, -- hogy a virtuális tár kezelése perifériakezelést is igényel. Ha a szigorú rétegezési elveket akarjuk tartani, akkor a tárkezelőben redundáns módon perifériakezelő rutinokat is szerepeltetni kell. Ha pedig lemondunk a szigorú hierarchiáról, akkor a magasabb
rétegben elhelyezkedő perifériakezelőt kell aktivizálni az alacsonyabb rétegben elhelyezkedő tárkezelőből. Ha a két funkciót egyazon rétegben, párhuzamosan valósítjuk meg, akkor közös vezérlőtáblázatokat használhatnak. Ez a helyzet például a UNIX-ban. A korai, nem rétegelt struktúrájú operációs rendszerekben a táblázatok bonyolult összeláncolásával próbálták elkerülni a problémákat, de nem túl sok sikerrel. Ezekben az operációs rendszerekben ma is hemzsegnek a hibák. Az IBM 360/370-re írt operációs rendszerek mindegyikére vonatkozhat ez a megjegyzés. Úgy tűnik, túlhajtották a kódredundancia elkerülésére irányuló erőfeszítéseket. Nem lehet a problémát ilyen egysíkúan kezelni. A CPU után a tár a hardver legfontosabb erőforrása. Sok számítógépes feladat már e két erőforrás birtokában megoldható. A tárkezelést tehát minden operációs rendszer kiemelten kezeli. A tárkezelés alapvetően két szempontból osztályozható: * lapozott vagy nem lapozott, és * valós vagy virtuális. A tárfoglalás lehet: * statikus (fix partíciókkal) vagy * dinamikus (GETMAIN, FREEMAIN funkciókkal támogatva). Ebben a fejezetben csak a dinamikus tárfoglalással foglalkozunk részletesebben, hogy megmutathassuk a lebonyolításhoz szükséges architekturális elemeket. A téma további kifejtése a már említett 10. fejezetben található. A dinamikus tárkezelés sarokpontjai: * a szabad mezők nyilvántartásának módja; * a lefoglalás stratégiája; * a felszabadítás módszere. A problémák elsősorban a valós tárkezelésnél csúcsosodnak ki, hiszen (az igazi!) virtuális tárkezelés esetében -- a fixpartíciós statikus tárkezeléshez hasonlóan -- minden program a saját címmezejében gazdálkodik a tárral. A valós, dinamikus tárkezelés két fő funkciójáról, a GETMAIN és FREEMAIN rendszerrutinokról már korábban is esett szó. Ezek feltétlenül a rendszermag rezidens részében helyezendők el, hiszen a tárfoglalás és felszabadítás igen gyakori tevékenység, különösen dinamikus esetben. A tárkezelés kezeléséhez szükséges adatstruktúra a tártartalom--táblázat. Ez láncolt listák formájában tárolja az egyes folyamatok tárlekötéseit, de használnak másféle adatstruktúrákat is. Az egyik megoldás szerint a láncolt lista elemei a lefoglalt tármezők elején foglalnak helyet. A tárfoglalás szempontjából fontos az úgynevezett szabadmező lánc. Ilyet használnak például az IBM OS/MVT-ben.
A szabad mezők elején mezőleírók vannak, amelyek tipikus tartalma: * mutató a következő szabad mező elejére; * mutató az előző szabad mező elejére; * mezőhossz és státusz. A mutatók lánca a rendszermagban kezdődik, illetve végződik. A végpontokat 0 értékű mutató jelzi (nullpointer). A gyorsabb kereséshez előre és hátramutató lánc is van. Ilyen adatszerkezetet használnak például az IBM OS/MVT-ben. A viszonyokat a 6.3. ábrán tanulmányozhatjuk. A GETMAIN tárfoglaló funkció ilyen adatstruktúra alkalmazása esetében úgy működhet, hogy a szabadmező láncokon haladva keres egy alkalmas méretű tármezőt, és elveszi belőle a kért hosszúságú részt. Ellentmondó igényeket támaszt, hogy melyik szóba jöhető mezőből vegyük el a kívánt részt. Ha azt a politikát követjük, hogy mindig a legnagyobból vágunk le egy darabot, akkor egy idő után rengeteg sok apró, kihasználhatatlan mező keletkezik. A legkevésbé eltérő méretű mező kiszemelése jobb algoritmusnak tűnik, de ezekből meg éppen hogy csak igen apró, végképp kihasználhatatlan mezők maradnak szabadon. Nehéz tehát igazságot tenni. Ha a GETMAIN-nel kiszemeltük az "áldozatot", akkor kettévágjuk. Az eredeti szabadlánc-mutatót át kell alakítani úgy, hogy az foglaltsági státuszt kapjon, és beláncolódjon az igénylő taszk táblázataiba. A maradék tárrészt az elején elhelyezett új listaelemmel be kell kapcsolni a szabad láncba. A FREEMAIN funkció algoritmusa sem magától értetődően egyszerű. Ha egy mező felszabadul, azt nem illik csak úgy "bután" beláncolni a szabad láncba. Ez ugyanis növelné az elaprózódás veszélyét. Ilyen algoritmus esetén két szabad mező kerülhetne közvetlenül egymás mellé. Ezeket nyilván célszerű egyesíteni.
6.5. Perifériakezelés 6.5.1. B/K vezérlőprogram A perifériakezelést a rendszermagok meglehetősen jól elkülöníthető része valósítja meg. Ezt a részt olykor külön név alatt emlegetik. Mi erre a funkcióhalmazra a B/K vezérlőprogram elnevezést fogjuk használni. Az IBM 360/370-es operációs rendszerekben ezt a szerepet töltik be az I/O Supervisorok. A B/K--vezérlő aktivizálódik: * B/K funkcióhívás esetében (akár alkalmazói, akár rendszerfolyamatból, akár más rendszerhívásból ered); * B/K--megszakítások lekezelése után, látszólag a csatornák és perifériák kérelmére. A periféria-lekötés általában nem a B/K vezérlőrendszer része. Ezt az allokátorok, az általános erőforrás--kezelő rutinok végzik a magasabb operációs rendszeri rétegekben. Az allokálás lebonyolításához persze szükség lehet B/K vezérlőprogram--szolgáltatásokra.
G
F
+------------------------------+ | REZIDENS TERÜLET | +----+----+----+ | | >0 | <SV|S/H | | +----+----+----+---------------+ | | | | | (TASK3) | | | +----+----+----+ | | >0 | <SV|S/H | | +----+----+----+---------------+ | |
> előremutató elem < visszamutató elem S/H státus/hossz SV Supervisorba
mutat | (szabad mező) | +----+----+----+ | E | >0 | 0 | 0 | <SV|S/H | | +----+----+----+---------------+ | | | (szabad mező) | +----+----+----+ | B | >E | <SV|S/H | | +----+----+----+---------------+ | | | (TASK1) | +----+----+----+ | A | >D | <SV|S/H | | +════+════+════+═══════════════+ +----+----+ | SV | >B | <0 | Szabadmező lánc | +----+----+ | +----+----+ | 3. | >F | >0 | | +----+----+ | 2. | >C | >0 | Taszk táblázatok | +----+----+ | 1. | >A | >0 | | +----+----+ | | SUPERVISOR | +------------------------------+
A,B,...G régiócímek 0 láncvégjel Jelenlegi szabadmező lánc: SV > B > E > 0 Jelenlegi szabadmező lánc: 0 < SV < B < E
6.3. ábra. Szabadlánc-struktúra az IBM OS/MVT-ben. 6.5.2. A B/K--szolgáltatások hívása Egy B/K művelet indításához minimum a következő adatokra van szükség: * a berendezés hardvercíme (hardverkódszáma), * a végrehajtandó funkció, * az átviendő adatok címe. Ezek az adatok azonban csak rögzített blokkméretek (például lyukkártya, sornyomtató), és egyetlen átviteli csatorna létezésekor elegendőek. Ha ezek nem teljesülnek, akkor további adatokra is szükség van: * a hardverstruktúra bonyolultsága, * a törekvés a berendezés-független adatkezelésre, * a berendezések osztott használatának felmerülése (mágneslemezek). A szükséges további adatok az alábbiak lehetnek: * csatornacím, * transzporthossz, * a B/K-kérések és a kérelmezők összeláncolása, * a berendezés--állomány összefüggések adatai, * az adatállomány--program összefüggés stb. A szükséges adatokat itt is bonyolult, összeláncolt táblázatok képezik, melyek össze vannak láncolva a már említett diszpécservezérlési táblázatokkal is. A cél, hogy a perifériákat minél rugalmasabban lehessen kezelni (kisteljesítményű számítógépes alkalmazásokat kivéve). Az állománytípus és a berendezés-hozzárendelés megadható: * a programok forrásnyelvű szövegében (ez később már nem módosítható, tehát csak statikus kezelést tesz lehetővé); * a munkavezérlő, vagy a parancsnyelvekben (ez dinamikus kezelést biztosít) * a rendszerkatalógusokban, amelyet alapértelmezések megadására használnak. 6.5.3. IBM 360/370 OS/MVT vezérlőtáblázatok Példaként nézzük meg, hogy milyen táblázatokat használ az IBM OS a perifériaműveletek kézben tartására. Kiindulásul megvizsgáljuk, hogy mi történik a DD JCL utasítás feldolgozása során.
A DD utasítás fő (kulcsszavas!) paraméterei: DSN=
adatállománynév (Data Set Name);
UNIT=
a fizikai berendezés azonosítója;
VOL=SER=
a fizikai hordozó azonosítója (kötetsorszám);
DISP=
az adatállomány állapota, kezelésmódja;
LABEL
a címkeinformációk típusa;
DCB
a logikai állapotjellemzők, részletesebben: . állománytípus (adatelérési módszer!), . blokkméret/logikai rekordhossz, . logikai rekordtípus, . kulcsjellemzők, ha vannak, . pufferelési jellemzők stb.
A beolvasó program, és a főütemező a DD utasítások adataiból a 6.4. ábrán látható táblázatsereget generálja. A táblázatok generálása persze a JOB utasításból generálódó munkavezérlő blokk (angolul: JCB = Job Control Block) létrehozásával kezdődik. Ehhez láncolódnak a munkához tartozó DD utasításokból képződő táblázatok. A JCB-hez kapcsolódó első, a munka állományigényeit összegyűjtő, táblázat a munkaállomány-vezérlő blokk (angolul: JFCB = Job File Control Block). Amikor a vezérlőáram--olvasó (beolvasó) talál egy DD utasítást, akkor annak adataiból létesít egy JFCB blokkot. Ugyancsak keletkezik egy másik vezérlő blokk is az úgynevezett lépés B/K táblázatban (angolul: SIOT = Step I/O Table), amely nyilvántartja azt, hogy melyik EXEC utasításhoz -- azaz munkalépéshez, -- kapcsolódik a feldolgozott DD utasítás. A munkához tartozó táblázatok akkor épülnek tovább, amikor a főütemező beütemezi végrehajtásra a munkát. Az első munkalépés programjának indítását végző Iniciátor program létesít egy folyamatvezérlő blokkot (ezt IBM terminológiával taszkvezérlő blokknak hívják: TCB = Task Control Block). A program futásához szükséges erőforrásokat az Iniciátor a JFCB és SIOT táblázatok alapján igyekszik lefoglalni (most eltekintünk az esetleges lefoglalási problémáktól). A SIOT alapján az Iniciátor létesít egy ehhez hasonló tartalmú táblázatot, amely már a programból képzett folyamathoz, IBM terminológiával taszkhoz tartozik (TIOT = Task I/O Table = taszk B/K táblázat). Miért van szükség erre a másolatra? Ez a gyermekfolyamatok (IBM terminológiával altaszkok) létrehozásával kapcsolatosan merült fel. Az altaszkoknak ugyanis külön TIOT-ra van szükségük a független működéshez. Így ha egy munkalépés indítótaszkja további altaszkokat szül, akkor azok mindegyikéhez keletkezik egy TIOT, de a munkalépéshez továbbra is csak egy SIOT táblázat tartozik. A JFCB, SIOT, TIOT vezélőstruktúrákkal tartja kézben az OS a MunkaMunkalépés-Taszk feladathierarchiát. (A 6.4. ábra csak egy taszkhoz tartozó táblázatokat mutat.)
A TIOT hozzá van láncolva a taszk TCB blokkjához. A TIOT tételeinek tartalma: * a JOB neve, * a lépés neve, * mutató egy JFCB tételre, amely a vonatkozó DD utasítás adatait tárolja, * mutató az allokált periféria UCB tételére. +----------+ ---> | | ----> | | EXEC ---> | Beolvasó | | | DD ---> | | ----> +----------+ JOB
O=====O | JCB | O==v==O | O==v===O O======O | JFCB | ---> | SIOT | Ov====vO O=v====O | | | +---------------+ ++---------++ | | Iniciátor/| | | Terminátor| | +-v---v---v-+ | +---+ | +---+ +----v----+ | | | | | O====v=O | O=v====O | Open/ | <-----< TIOT | <---|-----< TCB | | Close | O=v==v=O | O==v===O | | | | O===v==O | | | <-------|--|---< DEB | <---+ +----v----+ | | Ov═v═v═O | | | | | | O=====O | | +----|-|-+----> | UCB >----+ O==v==O | | | O=====O | | | >---------+ | +-------+ | | | DCB | <-----------------+ O=====O | | +------v----+ | | >-------------------> IOB | | | | B/K | O==v==O +---------+ Ov===vO | | |megszakítás| | | | | | | | |feldolgozó,| +-------> | Put/Get | <---+ | | | |B/K vezérlő| | | >--+ | | | +------v----+ +---------+ | Ov==v=vO | +---> RB | <------+ Post O======O 6.4. ábra. Az IBM 360/370 OS/MVT vezérlőtáblázatai
Az utolsóként említett UCB (Unit Control Block = berendezés-vezérlő táblázat) az eddig említett táblázatoktól függetlenül létező adatstruktúra, és a B/K vezérlőprogram vezérlőtáblázataihoz tartozik. Az UCB táblázat az operációs rendszermag generálásakor keletkezik, és minden érvényes perifériacímhez tartalmaz egy bejegyzést. Az érvényes perifériák köre azonban nem ennyire előre eldöntött az OS-ben, mert rendszerbetöltéskor intézkedni lehet egyes tételek érvénytelenítéséről és újak felvételéről. A rendszer tehát üzemkezdetkor "átkonfigurálható".
Az UCB-k tartalma: * a fizikai berendezéscím; * mutató a megfelelő fizikai perifériameghajtóra; * a hibakezelő rutin címe; * a berendezésosztály szimbolikus neve; * berendezés-jellemzők; * mutató a perifériát utoljára használó taszk RB blokkjára; * üzemállapot, ami több adatból áll: . perifériafoglaltság, . vezérlőegység--foglaltság, . lemezátvitel van-e folyamatban, . lemezfej-mozgatási parancs van-e folyamatban, . volt-e átviteli hiba; * a berendezésen éppen használatban lévő állományok; * az adathordozón található szabadterület; * a berendezéssel kapcsolatot tartó felhasználók; * a berendezés elérését lehetővé tevő B/K csatorna vagy csatornák címe(i). A táblázatok sora a programból aktivizálódó OPEN hívás hatására tovább bővül a dinamikus igények nyilvántartására. A programok minden elérendő adatállomány számára használnak egy adatvezérlő blokkot (angolul: DCB = Data Control Block). Ez kiindulásul a programíráskor definiált kezdőértékeket tartalmazza. Az OS-ről azonban már korábban említettük, hogy nem statikus, hanem dinamikus perifériakezelést biztosít. Ez úgy valósul meg, hogy a program futásakor a DD utasításból származó adatok (amelyeket a JFCB és a SIOT tárol) részben kiegészítik, részben felülbírálják az OPEN folyamatban a programban eredetileg megadott DCB információkat. Érdekes megemlíteni, hogy a hibás DD paraméterek ilyenkor hibát okozhatnak, ami tehát csak futáskor derül ki. Ez a dinamikus kezelés ára, hiszen emiatt az ilyen hibák korábban nem deríthetők fel.
Az adatvezérlő blokk a DD utasításban jelzett DCB paramétereken túl hivatkozik a vezérlés lebonyolításához szükséges rendszermag-táblázatokra. Ezek közül már említettük a TIOT táblázatot, de nem szóltunk a DEB táblázatról (Data Extent Block = adatterület blokk), amely a mágneslemezen tárolt állományok esetében adatterületekre vonatkozó pótinformációkat tartalmaz, valamint mutatót a kezdeményezett B/K átvitelek leírására szolgáló másik táblázatra, az IOB-re (I/ O Block = B/K blokk). Az IOB minden, az adatállománnyal kapcsolatban kezdeményezett, még érvényben lévő B/K átviteli kérelemre tartalmaz egy IOB blokkot, melynek tartalma: * visszamutató a DCB-re, * a csatornaprogram címe (fizikai B/K), * puffercím, * készülékállapot, * mutató egy kérelemblokkra (RB = Request Block). A programból kiadott PUT/GET stb. transzferaktivizáló makrók mindegyikéhez készül egy IOB és egy RB kérelemblokk. A kérelemblokk becsatlakoztatja a B/K átviteli kérelmeket az OS/MVT általános erőforrás-használat igénylési és teljesítési rendszerébe. Az RB blokk tartalma: * a vonatkozó TCB címe (kapcsolat a kérést kiadó taszkkal), * az UCB indexe (berendezés-kapcsolat), * az IOB címe (csatornaprogram-kapcsolat), * a vonatkozó DEB címe (adatterület(ek) leírása). Ezek az adatok teszik lehetővé, hogy elinduljon a fizikai transzfer. Ez azonban akadályba ütközhet, ha a periféria vagy a lehetséges átviteli csatornák mindegyike foglalt. Ekkor a kérés beáll a konkrét perifériára vonatkozó kérelmek sorának végére. A kérelmet akkor kezdi kielégíteni a B/K vezérlő, ha felszabadul az út a perifériához, és a kérelem a várakozó sor elejére jut. A B/K művelet a IBM 360/370-es hardverek sajátosságainak megfelelő módon indul. A B/K transzfer az OS-ben (és több más IBM operációs rendszerben) az EXCP rendszerhívással kezdődik. Ez tulajdonképpen egy SVC 0 hívás, amely regiszteren át kap egy mutatót a kérelem IOB blokkjára. Az EXCP rutin ennek birtokában az IOB-ből előveszi a vonatkozó DCB és további táblázatok (TIOT,DEB) címét, és a megfelelő táblázatokból előállítja a fizikai transzfer lebonyolításához szükséges adatokat. Eközben ellenőrzi az érintett táblázatok valószerűségét, és inicializálja a hibakódokat. A végén kiad egy privilegizált B/K--indító hardverutasítást. A fizikai transzfer lebonyolítása az IBM 360/370-es hardverekben a CPU működésével párhuzamosan (tehát izokron, aszinkron üzemmódban) történik a csatornavezérlő hardvereszközök és egy úgynevezett csatornaprogram alkalmazásával. A csatornaprogram tulajdonképpen egy speciális vezérlőadat--táblázat, amely a perifériának előírt utasításokat írja le. Segítségével a multiplex, szelektor és blokkmultiplex csatornavezérlőket programozhatjuk. A csatornaprogram csatornaparancsok (IBM terminológiával CCW-k = Channel Command Words) sorozata. A parancsok csak szekvenciálisan hajthatók végre (nincs ugrás és ciklus, de van megszakíthatóság), és lehetővé teszik a "szétszóró" és az "összegyűjtő" írást/olvasást a tárból(ba). Ez azt jelenti, hogy az átvitel adatelemeinek sem az operatív tárban, sem a periféria fizikai blokkjaiban nem kell feltétlenül egymás mellett elhelyezkedniük. Ezzel többnyire megspórolható a szoftver úton történő
blokkolás/deblokkolás, illetve a hardver "be tud ebbe segíteni". A csatornaprogramok egyéb lehetőségei folytán sok CPU időt meg lehet spórolni. Le lehet például választani a mágneslemezek fejmozgatását (az adatátviteltől automatikusan külön transzferként kezelve), meg lehet kerestetni egy mintát a lemez adott tartományaiban stb. Ezeknél a csatornaprogramoknál csak az indítás igényel egy kis CPU időt. A csatornaprogram befejeztét B/K megszakítás jelzi. 6.5.4. A B/K--szolgáltatások befejezése Egy aktív kérelem addig él a nyilvántartásokban, amíg nem teljesül. A teljesülés a megszakítási események kielemzésével deríthető ki. A megfelelő megszakítórutinoknak, esetünkben a B/K megszakítás-feldolgozónak kell felismernie, hogy egy megszakítás kapcsán melyik igény elégült ki. A felismerés után értesíteni kell az igénylőt a teljesülésről. Az OS/MVT-ben az értesítés a POST operációs rendszeri funkció segítségével történik. A megfelelő B/K megszakítás-kezelő rutin a POST hívással "küldi el" a vonatkozó IOB blokkba a "végrehajtódott" információt (most eltekintünk a hibás transzferek problémáitól). Részletesebben ez úgy zajlik, hogy B/K--megszakításkor a hardver feljegyzi a megszakítást okozó periféria címét. A B/K másodszintű kezelője a perifériacím alapján kikeresi, hogy melyik UCB blokkhoz tartozik. Az UCB-ben (mint említettük) van egy bejegyzés arról, hogy utoljára melyik kérelem kielégítésével foglalkozott a periféria. A kezelőprogram ezzel vissza tudja göngyölíteni a láncot a vonatkozó IOB blokkig. A B/K vezérlőprogram a teljesítés után "felszámolja" a kérelem RB igényblokkját és IOB blokkját, majd a vonatkozó folyamatvezérlő blokk üzemállapot-adatát blokkoltról futóképesre változtatja, így a diszpécser ismét beütemezheti a folyamatot. A B/K vezérlőprogramnak még ezután is van teendője, ugyanis a perifériára várakozó igények sorából el kell indítania a következő transzfert, azaz új kérelmet aktivizál. Az OS/MVT ilyenkor a vonatkozó periféria UCB blokkjában feljegyzi az aktivizált RB címét, hogy biztosítsa a megszakítás megérkezésekor a kérelem felismerhetőségét. A B/K vezérlőprogram működésének még számos olyan részlete van, amit itt elhanyagoltunk. Az IBM OS rendszerekben például a felhasználó saját rutinokat is aktivizáltathat a B/K vezérlővel az úgynevezett kilépési pontokon (angolul: exit points), amelyeken ki lehet lépni az operációs rendszerből vagy más rendszerprogramból a felhasználó kódjába, a visszatérést pedig a felhasználó szervezi meg). Ily módon a felhasználó "elkaphatja" például a hibakezelést, tehát a szabványos helyett a felhasználó algoritmusa szerint történik a hibakezelés. A felhasználói rutin bekapcsolását OPEN időben kell kezdeményezni a paraméterek között megadott hibarutin címmel. Ez a módszer nagyon rugalmas perifériakezelést biztosít, de ugyanakkor a kapcsolódási pontok fix kijelölésével rendszabályozza a felhasználó rendhagyó viselkedésre mutatott törekvéseit. A lehetőségekkel a tapasztalat szerint az alkalmazók csak igen szűk körben élnek. Használatuk ugyanis túl sok rendszerprogramozási szakismeretet igényel. Nem csoda, ha az újabb operációs rendszeri generációk egyre szegényesebben tartalmaznak ilyen támogatásokat (pl. a UNIX). Az OS/MVT B/K vezérlője nem a legtipikusabb megoldás, de bonyolultsága alkalmas arra, hogy valamelyest átfogó áttekintést kapjunk egy dinamikus perifériakezelést biztosító B/K vezérlőprogram multiprogramozott környezetben felmerülő funkcióiról és belső architektúrájáról.
6.6. Egyéb magfunkciók
A tárakon és perifériákon kívül más erőforrásokkal is kell gazdálkodnia az operációs rendszernek. Ezek speciális magfunkciókat és további vezérlő adatstruktúrákat igényelhetnek. Elhelyezésüket a réteghierarchiában igen sok szempont befolyásolja. Ezekről az általános erőforrás-kezelőkről a 8. fejezetben, lesz még szó. Említettük, hogy a rendszermagok az alrendszerek támogatására speciális funkciókat tartalmazhatnak. Ezek megfelelő elhelyezése a réteghierarchiában erősen kihathat a támogatott alrendszerek hatásfokára. Külön gond, hogy az alrendszer működése teljesen a rendszermag erőforrás-kezelőjére támaszkodjon-e (erős integráltság), vagy külön gazdálkodjon a számára fixen előre lefoglalt erőforrásokból (individuális alrendszer). Az integrált alrendszerek előnye az, hogy a felhasználó közelebb kerül az operációs rendszerhez, ami jobb kiszolgálást eredményez. Ez a helyzet például az IBM OS/MVT TSO alrendszerénél is.
6.7. Mintapéldák Nem túl könnyű a belső architektúrákra konkrét mintapéldákat adni. Barron nyomán azonban nézzük meg egy egyszerű spooling rendszer szerkezetét. Spooling rendszerünk vezérelje az alábbi három konkurens program multiprogramozását: * rendszerolvasó program a feladott munkák felvételére; * rendszerlistázó program a nyomtatandó eredmények kinyomtatására; * munkafelügyelő program (job supervisor), amely a munkák lépéseit szervezi és végrehajtja. A következő lépés az egyes programok prioritásának kijelölése: rendszerolvasó > rendszerlistázó > munkafelügyelő. Ezzel figyelembe vettük a perifériakezelési sajátosságokat. A rendszerolvasó perifériájáról feltételezhetjük, hogy az a leglassúbb, ezért ritkán fog kiszolgálást kérni. Ha azonban kér, akkor célszerű szinte azonnal kiszolgálni, mert utána úgyis megint elég hosszú ideig békén hagy bennünket. Ezért kell neki adni a legnagyobb prioritást. Ugyanakkor a munkafelügyelő erősen CPU-igényes. Ha nem akarjuk, hogy túlzottan kisajátítsa a CPU-t, akkor neki kell adni a legkisebb prioritást. Feltételezzük, hogy a vezérlés mindig visszatér a munkavezérlőbe, amikor egy munkalépés lezajlik. A munkákról tételezzük fel, hogy olyan kártyakötegekből állnak, amelyeket egy munkaazonosító vezérlőkártya vezet be, ezt forrásprogram kártyák követik a program végét jelző vezérlőkártyával, majd a futáshoz szükséges adatok következnek az adatok végét jelző vezérlőkártyával, és az egészet egy munkazáró vezérlőkártya zárja le (ez utóbbi már redundánsadat, de megkövetelése leegyszerűsítheti a vezérlő algoritmusát). Spooling rendszerünknek tehát három adatfajtát kell kézben tartania: programszövegeket, bemenő adatokat, és eredményadatokat. Ezeket tegyük fel, hogy három könyvtárban mágneslemezen tároljuk. A lebonyolítást egy B/K vezérlőrendszerre bízzuk, amely megoldja a mágneslemez szabadhely-gazdálkodását, valamint a felvett állományok nyilvántartását és elérését. A munkákról feltételezzük, hogy a következő lépéseken mennek át: * (1) Beolvasás:
a munkák adatai lemezre kerülnek;
* (2) Várakozás:
a munka végrehajtásra kész;
* (3) Futás:
a munka végrehajtódik;
* (4) Befejeződött:
a munka eredménye nyomtatásra várakozik;
* (5) Kiírás:
a munka eredménye kinyomtatódik;
* (6) Vége:
a munka elkészült.
A következő tartalmú vezérlőrekord szükséges egy munka adatainak nyilvántartásához: * munkaazonosító * állapot
* mutató a programállományra * mutató a bemenő adatokra * mutató a kimenő adatokra A munkasor ilyen tartalmú rekordok láncolt listájaként alkotható meg. Ez a sor egy példa az osztott erőforrásokra, mert mindhárom rendszermodul használja a működéséhez. Ilyenkor biztosítani kell az adatok integritását, ami azt jelenti, hogy amíg az egyik program ír valamelyik rekordba, addig azt más program ne olvassa, mert félrevezető információt kaphat. A rendszerolvasó egy új munka beolvasásakor készít a munkasorban egy új tételt. Ez a tétel addig nem törlődik a listából, amíg a munka el nem éri a "Vége" állapotot. Váratlan rendszerleállásnál a rendszer felélesztése után ez teszi lehetővé a munka újraindítását. Az indulási állapot persze a "Beolvasás". Ebből a munkafelügyelő modul tudhatja, hogy még nem kezdheti el a program végrehajtását, hiszen azt előbb be kell olvasni. Munkafelügyelő programunkban a fordítóprogram és a lefordított program aktivizálását szubrutinhívásként képzeljük. A B/K lebonyolításával kapcsolatos feltételezést már említettük. Az egész modell elhanyagolja a konkurens műveletek szinkronizálásának problémáját, amelyet egy pontosabb modellben meg kell oldani. Felügyelőprogramunk ily módon kiegészítendő a munkafelügyelő programon kívül a szinkronizáló rutinok, a megszakítás-kezelők, és a B/K kezelő rutinjaival stb. Ezek működtetése további táblázatok létrehozását és kezelését fogja igényelni. A példa további boncolgatását a tanultak alapján az olvasóra bízzuk. Megjegyezzük még, hogy a három programmodul párhuzamosságát sem jelöltük. Erre vonatkozóan a 12. fejezetre utalunk. Spooling rendszerünk vázlatos programterve mindezek után a következő lehet: Rendszerolvasó: ISMÉTELD munkaazonosító kártya olvasása munkasor tétel készítése "Beolvasás" állapot beállítása programbeolvasás és elhelyezés lemezen üres állomány létesítése az eredményeknek "Várakozás" állapot beállítása VÉGTELENSZER Rendszerlistázó:ISMÉTELD "Befejeződött" állapotú munka keresése eredménylistázás állományok törlése munkasor tétel törlése VÉGTELENSZER Munkafelügyelő: ISMÉTELD "Várakozás" állapotú munka keresése programfordítás HA hibátlan AKKOR programfutás "Befejeződött" állapot beállítása VÉGTELENSZER
6.8. Gyakorlatok 6.8.1.
Mi a rendszermag és mi a szerepe?
6.8.2.
Mit nevezünk rezidens és mit tranziens rutinnak?
6.8.3.
Mi a primitív művelet és mi az ellentéte?
6.8.4.
Miért tárrezidens a legtöbb magfunkció?
6.8.5.
A magfunkciók jó része megszakíthatatlan rutinként fut. Miért van erre szükség?
6.8.6.
Miért kell az operációs rendszeri funkciók rutinjainak a hardver valamelyik privilegizált üzemmódjában futnia?
6.8.7.
Milyen a helyes rendszermag-struktúra? Miért?
6.8.8.
Milyen célt szolgálnak a vezérlőtáblázatok?
6.8.9.
Mire szolgálnak a zármechanizmusok, és mi a működési elvük?
6.8.10.
Mi a "kritikus szakasz"?
6.8.11.
Mi a diszpécser, és hogyan működik?
6.8.12.
Mi váltja ki a diszpécser működésbe lépését?
6.8.13.
Milyen operációs rendszeri szolgáltatástípusokról volt szó?
6.8.14.
Mi a rendszerhívások szerepe, és hogyan szokták őket megvalósítani?
6.8.15.
Hogyan történik a rendszermagban a megszakítások kezelése?
6.8.16.
Melyek a dinamikus tárkezelés fő rendszerfunkciói?
6.8.17.
Mi a B/K vezérlőprogram?
6.8.18.
Mi az OPEN szerepe, és hatására hogyan reagál a B/K vezérlőprogram?
6.8.19.
Mi történik egy B/K kérelemmel?
6. Hogyan fejeződik be egy B/K igény kielégítése?
OS07V10.rtf,ZSP,2001-04-16
7. RENDSZERHÍVÁSOK
A rendszerhívások azok a programutasítások, amelyekkel programunkból operációs rendszeri szolgáltatásokat tudunk kérni. Erről már több fejezetben is volt szó, de itt összefoglaljuk az ezzel kapcsolatos kérdéseket. Mégegyszer tisztázni kívánjuk a primitívként és a folyamatként futó rendszerhívások közötti különbségeket. Különösen azért, mert az irodalom is eléggé eklektikusan használja a primitív művelet fogalmát: lényegében minden operációs rendszeri, sőt alrendszeri hívást primitívként emlegetnek. Ez elvileg definíció kérdése, de mi inkább azok pártján állunk, akik gyökeresen megkülönböztetik e két rendszerfunkció aktivizálási módot.
7.1. Rendszerprimitívek Az operációs rendszerek (vagy alrendszerek) azon funkcióit, melyeknek algoritmusa homogén (egy célnak szentelt) kód, és igénybevételét nem kell diszpécserrel ütemezni, primitív műveleteknek nevezzük. A primitív funkciók kódja természetesen tartalmazhat elágazásokat, ciklusokat, sőt még szubrutinhívásokat is, de a végrehajtás során nem keletkezhet olyan helyzet, amelyben a rutin végrehajtása megakad. Elakadásnál ugyanis el kellene venni a rutintól a CPUvezérlési jogot, és ez már bejegyzéseket igényelne a rendszertáblázatokban, továbbá a diszpécser beavatkozását tenné szükségessé. A primitív műveletek algoritmusa olyan, hogy helyes működésüket olykor a megszakítások is zavarnák. Bár egyes rutinok megszakítása megengedhető olymódon, hogy a megszakítás elsőszintű lekezelése (FLIH lefutása) után a rutin azonnal visszakapja a vezérlést, a gyakorlatban a primitív műveletek futása alatt letiltják a megszakításokat. Természetesen, mivel egyes megszakításokat időben illik kiszolgálni, a primitív funkciók csak meglehetősen rövid lélegzetű rutinok lehetnek, különben megzavarnák a megszakítások kiszolgálását. Az operációs rendszerek tervezőinek meg kell találni a kompromisszumot a két ellentmondó igény között. Nem megszakítható primitív funkcióként kell például megvalósítani a már említett P és V szemaforkezelő műveleteket. Ugyanakkor a primitívként beprogramozott, tehát nem folyamatként futó, diszpécserrutin általában túl bonyolult művelet ahhoz, hogy teljes végrehajtása alatt le lehessen tiltani a megszakításokat. Kódjában csak kifejezetten azokon a kritikus szakaszokon szabad letiltást használni, ahol a megszakítások a diszpécser működését tényleg zavarnák. Az is természetes azonban, hogy a diszpécser azonnal visszakapja a vezérlést, amint az FLIH rutin végrehajtódik, hiszen éppen ő az ütemező, aki eldönti, hogy melyik folyamat kaphatja meg a CPU vezérlésének jogát. A diszpécser alkalmanként még jól is jár, ha engedi a megszakításokat, mert ezzel menet közben frissebb információkhoz juthat a környezeti eseményekről, és ezáltal ütemezési döntéseit is jobban megalapozhatja. A primitív funkciókat megvalósító rutinok szinte kötelezően tárrezidensek. Ennek az az oka, hogy
ezeknek az algoritmusoknak gyorsan kell reagálniuk, hiszen azért írták meg őket primitívként. Ha nem tartózkodnának állandóan a valós operatív tárban, akkor megakadna működésük, ami a fentebb mondottak értelmében primitívek esetén lehetetlen szituáció. A felmerülő időkésleltetés ráadásul elég nagy lenne, ha tranziens rutinként a háttértárról kellene elővenni a kódot. A háttértárak elérési sebessége a legkorszerűbb mágneslemezes perifériák esetében is 4-5 nagyságrenddel lassúbb, mint az operatív tár elérése (RAM: általában kisebb, mint 1 mikrosec, háttértár: legalább 10-20 millisec!). Az operációs rendszerek tervezőit a fenti meggondolások vezérelhetik annak eldöntésében, hogy egy funkciót primitív vagy folyamatként futó rendszerhívásként valósítanak meg. Elképzelhető, hogy egyes algoritmusokat kényszerűségből két vagy több primitívre kell felszabdalni, és velük kell megszervezni a rendszerhívást kiszolgáló rutint egy magasabb hierarchia szintű rétegben folyamatként futó funkcióként. A primitív funkciók működését a 7.1. ábra szemlélteti. Hívó program
Rendszermag
= (a tárcímek lefelé nőnek) = | 2 | + x-------------------->>+ p PROGRAM(p) | 3 # FLIH(#) p |2 # 1 v 2 | v 4 CALL >>--------------------/ SCALL >>--x .<<-------------------\ 7x->>. |4 v 11 | | 8 # 9 | 12 p |11 | *>>-|------x p ? 7| | 5 | 9| p | +<<-x4 | * A vezérlést akár rögtön | & SLIH(&): | | megkaphatja | 6 & PRIMITÍV | | | 7 & funkció | | {+ Rutin eleje} ? x-<<* | | {* Rutin vége} | | 9 | | {> Kilépés} | +<<--------x | {< Visszalépés} | $ | {v Lefelé irány!} | 10 $ DISZPÉCSER | {. Folytatás} | $ ($) v x------------- 11 ??--<< v $ = = CALL a primitívet aktivizáló makrohívás a hívó programban SCALL szubrutinhívás a rendszermagon belül a primitív végrehajtására FLIH First Level Interrupt Handler = Elsőszintű megszakítás-kezelő SLIH Second Level Interrupt Handler = Másodszintű megszakítás-kezelő 7.1. ábra. Primitívként futó funkciók működése
7.2. Folyamatként futó rutinok Azokat a rendszerhívásokat, amelyek aktivizálása során bejegyzések keletkeznek a diszpécser vezérlőtáblázataiban, folyamatként futó rutinoknak nevezzük.
A folyamatként futó algoritmusok a megszakításokat sohasem tiltják le működésük teljes idejére. Ennek fő oka, hogy algoritmusuk elakadásokat tartalmaz, amelyekből tipikusan csak megszakítás útján tudnak kikeveredni. Várakozásaik alatt célszerű elvenni tőlük a CPU vezérlési jogát, amely a diszpécser igénybevételét jelenti (l. 7.2. ábra). A folyamatként futó rendszerrutinokat nem szabad összetéveszteni a 4.10.-ben tárgyalt rendszerfolyamatokkal. A rendszerfolyamatok az operációs rendszer olyan elemei, amelyek általában nem részei a rendszermagnak, annak ellenére, hogy tárrezidensek is lehetnek. Ezek olyan folyamatok, melyeknek az operációs rendszer valamilyen módon megkülönböztetett jogokat (privilégiumokat) biztosít (mint pl. az OS/2 a parancsértelmezőknek), de különben adataik a diszpécser vezérlőtáblázataiban találhatók. A folyamatként futó rendszerrutinok mindig a rendszermag részét képezik. A folyamatként futó rendszerrutinok többféle privilégiumot is élvezhetnek. Egyrészt előfordul, hogy leírásukat a diszpécser külön (rövidebb és ezért gyorsabban áttekinthető) táblázatban tartja, vagy egy speciális mutatólánc segíti a megtalálást a normál folyamatok leírásai között. A prioritásvezérelt diszpécserek a rendszerfolyamatoknak és a folyamatként futó rendszerrutinoknak elegendően nagy prioritás beállításával biztosíthatnak elsőbbséget. A folyamatként futó rendszerhívások annyi előnyt biztos élveznek, hogy mivel a rendszermag részei, a CPU valamelyik privilegizált üzemmódját használhatják. Ez lehetővé teszi, hogy a számukra szükséges vezérlőtáblázatokhoz közvetlenül is hozzáférjenek, sőt egyes rendszerprimitíveket is közvetlenül szubrutinként hívhatnak. Ez egyszerűsítést és jelentős sebességnövekedést eredményez.
Hívó program
Rendszermag
= = | 2 | + x-------------------->>+ p | 3 # FLIH p |2 # 1 v 2 | 4 v 5 CALL >>--------------------/ SCALL >>--x .<<-------------------\ x->>. |5 v 11 | | 8 # 9 | 12 p |11 | *>>-|------x p ? 7 | | 5 | 9| p | +<<-xSLIH | * Vezérlést csak azután | & CREATE | | kaphat, ha a funkciót | 6 & folyamat | | megvalósító folyamat | & | | lefutott x-<<* | | {+ Rutin eleje} | 9 | | {* Rutin vége} ? +<<--------x | {> Kilépés} | $ | {< Visszalépés} | 10 $ DISZPÉCSER | {v Lefelé irány!} | $ | {. Folytatás} x------------- 11 ????<< | $ = = CALL SCALL FLIH SLIH
a primitívet aktivizáló makrohívás a hívó programban szubrutinhívás a rendszermagon belül egy folyamat létrehozására First Level Interrupt Handler = Elsőszintű megszakítás-kezelő Second Level Interrupt Handler = Másodszintű megszakítás-kezelő 7.2. ábra. Folyamatként futó funkciók működése
7.3. Mintapéldák Bár mintapéldákat keresni elég nehéz ebben a témakörben, a mondottakat két példával, az IBM OS, és a UNIX kernel főbb rendszerhívásainak elemzésével próbáljuk meg szemléltetni. 7.3.1. Az IBM 360/370 OS rendszerhívásai Korábban már többször említettük, hogy az IBM 360/370-es hardverekben a vezérlő állapotot kiváltó SVC szoftver-megszakítási utasítást lehet használni a supervisor funkciók hívására. Az OSben erre az SVC utasításra alapozott rendszerhívásokat négy osztályba sorolják. Az osztályba sorolás tulajdonképpen finomítja azt a felosztást, hogy mely rutinok futnak primitívként és melyek folyamatként. A rendszerhívások első osztályába sorolt rutinok a tulajdonképpeni primitív funkciók, míg a többiek folyamatként futnak. A magasabb osztályokba sorolt rutinok végrehajtása egyre nagyobb akadályokba ütközik.
Kód 0D 2A -14 09 30 3E 38 00 0A -0A -06 08 13 02 ---11 -33 2F 01 ---
Rutinnév
Osztály
ABEND ATTACH CHECK CLOSE DELETE DEQ DETACH ENQ EXCP FREEMAIN GET GETMAIN GTRACE LINK LOAD OPEN POST PUT READ RECEIVE RESTORE SEND SNAP STIMER WAIT WRITE WTO
IV. II. II. IV. II. II. II. II. I. I. IV. I. IV. II. II. IV. I. IV. IV. IV. III. IV. IV. I. I. IV. IV.
Funkció Programlelövés Altaszk létesítése B/K szinkronizáló primitív Állományzárás (többmodulos!) Program kitörlése a tárból Erőforrás felszabadítása Altaszk leállítása Erőforrás lekötése B/K csatornaprogram indítása Tárterület felszabadítása Logikai rekord beolvasása Tárigény bejelentése Nyomkövetés Alprogram hívása Programmodul betöltése Állománynyitás (többmodulos!) Eseménybekövetkezés jelzése Logikai rekord kiírása Adatblokk olvasása Olvasás távoli perifériáról Visszaállítás Írás távoli perifériára Szelektív tárkivonat kérése Óraszolgálat igénybevétele Várakozás kezdeményezése Adatblokk írása Üzenet a rendszeroperátornak
A kötőjellel jelölt kódú rutinok több rendszerrutinra támaszkodó makrohívások, ezek osztályba sorolása képletes. 7.1. táblázat. Az IBM 360/370 OS néhány rendszerhívása Az első osztályba sorolt rutinok futása nem szakítható meg és kódjuk teljes egészében a rendszermagban található. A második osztályba soroltak ugyan a rendszermag részei, de futásuk megszakadhat, ezért nyilván folyamatként kezelendők. A harmadik osztályba sorolt rutinok feltételesen (a rezidens területen) rezidenssé tehető, egyetlen modulból álló, míg a negyedik osztályba sorolt rutinok hosszadalmas, több tranziens modulból álló kódok. Az SVC hívások paraméterezése egyrészt az SVC-kód megadásával lehetséges, aminek szimbolikus rutinnevet szoktak adni. A programozónak nem is közvetlen SVC hívást, hanem egy makronevet vagy szubrutinnevet kell leírni a programban. A makrót vagy szubrutint paraméterezni kell a kért szolgáltatási igénynek megfelelően. A paraméterek részben táblázatokba, részben egyezményes regiszterekbe kerülnek. Ez a paraméterátadási módszer -- mint már szó volt róla -- az alacsony szintű nyelvi programozásra optimalizált, tehát az assembly nyelv igényeihez igazodik. A korai programozási stílusra jellemző volt az assembly nyelv túlzott használata, amelynek előnye, hogy hatékonyabb algoritmusokat lehetett írni az adott hardverre, de a program átvitele egyik gépről a másikra még azonos gépsorozatoknál is akadályokba ütközhetett. Új hardver beállításakor sok munka ment veszendőbe.
7.3.2. A UNIX kernel rendszerhívásai A UNIX kernel szolgáltatásait -- az adott verziótól függően -- 50-70 rendszerhívásra szokták alapozni. Ez nem túl széles választék az IBM OS 200 körüli hívásszámához képest. Más operációs rendszerek pedig még bonyolultabb alacsony szintű (rendszerprogramozói) interfésszel rendelkeznek. Hogyan lehetséges, hogy a UNIX ezzel a szűk választékkal mégis olyan fényes pályát futott be az operációs rendszerek történelmében? A magyarázat egyrészt a jól kiválasztott híváshalmazban keresendő, másrészt a nyelvi könyvtárak (főleg a C könyvtár) alaposan kibővítik a rendszerhívások körét összetett szubrutinok biztosításával. Az utóbbi lehetőség persze más operációs rendszerekben is megtalálható. A UNIX-ban a programozónak nem kell törődni azzal, hogy primitívként vagy folyamatként futó szolgáltatást hív. A rendszer ezt a problémát a "belügynek" tekinti. Hatékony programok írásához azonban nem mindegy, milyen rendszerhívásokat használunk. Ha a kódolásnál több primitív funkciót alkalmazunk, akkor a kód mérete ettől megnő, de a program gyorsabban fut. Sok primitív használata viszont programunkat túl erőszakossá teszi, és ezáltal más folyamatoktól elrabolja a CPU-időt és az egyéb erőforrásokat. A UNIX automatikus prioritásválasztási mechanizmusainak kiismerésével ezt még fokozhatjuk. A UNIX dokumentációk nem tartalmazzák azt az információt, hogy melyik rendszerhívás működik primitívként és melyik folyamatként. A UNIX rendszerhívásokat bemutató 7.2. táblázat ezért inkább megérzésen, mint tényeken alapul. A legtöbb funkcióról feltételezhető, hogy működése elakad, ezért alig néhányról állítjuk, hogy esetleg primitívként fut. A UNIX rendszerhívásokat eredetileg assembly szinten is lehetett használni, de a UNIX ma már kifejezetten C nyelvű interfészéről közismert (SVID = System V Interface Definition, amelyet a Bell Laboratórium tart karban). A rutinhíváshoz a programozónak még azt sem kell ismernie, hogy az adott hardveren melyik a szoftvermegszakító utasítás. A hívásokat kifejezetten a magas szintű nyelvekben szokásos paraméterezésű szubrutinhívások mintájára kell kódolni. A UNIX rendszerhívásokat tehát a magas szintű nyelvekre optimalizálták. Ez jellegzetes fejlődési irányzat. Ilyen például az IBM OS/2 rendszerhívási interfésze is, és az ötödik generációs operációs rendszerekben is ez a törekvés tapasztalható. A cél a portabilitást biztosító magas szintű nyelvek minél hatékonyabb támogatása, mert ezzel programozói munkamegtakarítás érhető el úgy, hogy emellett a magas szintű nyelven írt programok hatásfoka is elég jó maradhat.
Rutinnév ABORT ACCESS ACCT ALARM CHDIR CHMOD CHOWN CLOSE CREAT DUP EXECxx EXIT FCLOSE FCNTL FOPEN FORK FSEEK GETCHAR GETCWD GETENV GETLOGIN GETPASS GETPID GETPW GETUID IOCNTL KILL LINK LOCKF LSEEK MKNOD MKTEMP MONITOR MOUNT NICE OPEN PAUSE PERROR PIPE PRINTF PROFILE PTRACE PUTCHAR
Típus Folyamat Folyamat Folyamat Folyamat Folyamat Folyamat Folyamat Folyamat Folyamat Primitív Folyamat Primitív Folyamat Primitív Folyamat Folyamat Folyamat Folyamat Primitív Primitív Primitív Folyamat Primitív Folyamat Primitív Folyamat Folyamat Folyamat Folyamat Folyamat Folyamat Primitív Folyamat Folyamat Primitív Folyamat Primitív Primitív Folyamat Folyamat Folyamat Folyamat Folyamat
Funkció A folyamat leállítása tárkivonattal Állomány-hozzáférési jog lekérdezése A számlázás vezérlése Ébresztőóra szolgáltatás kérése Munkakatalógus kijelölése Állományvédelmi mód beállítása Állomány tulajdonosának módosítása Állomány lezárása Állomány-létrehozás és -nyitás kimenetre Állománynyitás duplikálása Új program indítása Folyamat leállítása és eredménykód Pufferelt állomány lezárása Manipulációk nyitott állományokkal Pufferelt állomány nyitása Gyermekfolyamat szülése (leágazás) Pufferelt állomány pozicionálása Egy karakter olvasása Aktuális munkakatalógus lekérdezése Környezetleírás lekérdezése A bejelentkezési név lekérdezése Jelszó bekérése Folyamatazonosító lekérdezése Egy felhasználó jelszavának bekérése Felhasználói azonosító lekérdezése Perifériák fizikai vezérlése Jelzés küldése egy folyamatnak Új név kapcsolása létező állományhoz Állományterület- és rekordzárolás Megnyitott állomány pozicionálása Speciális állományleírás készítése Egyedi állománynév generálása ID-ből Programbelövés inicializálása Állományrendszer megnyitása A folyamat prioritásának módosítása Állomány megnyitása Várakozás kezdeményezése Az utolsó hibaüzenet dekódolása Szülő--gyermek kapcsolat létesítése Formázott kivitel szabvány kimenetre Dinamikus nyomkövetési eszköz Folyamatvégrehajtás nyomkövetése Egyetlen karakter kivitele
7.2. táblázat. A UNIX kernel tipikus rendszerhívásai
Rutinnév
Típus
Funkció
(folytatás) READ SBRK SCANF SETUID SIGNAL SLEEP STAT STIME SYNC SYSTEM TIME TIMES UMOUNT UNLINK USTAT UTIME WAIT WRITE
Folyamat Folyamat Folyamat Primitív Primitív Folyamat Folyamat Folyamat Folyamat Folyamat Primitív Primitív Folyamat Folyamat Folyamat Folyamat Folyamat Folyamat
Adatblokk beolvasása pufferbe Tárigény bejelentése Formázott bevitel szabvány bemenetről Tényleges felhasználó megadása Jelzések kezelésének megadása Várakozás adott ideig Állományjellemzők lekérdezése Órabeállítás Módosított pufferek lemezre írása Shell parancs végrehajtatása Dátum, időzóna és időpont lekérdezése Szülő és gyermekeinek időfelhasználása Állományrendszer lezárása Katalógustétel törlése Állományrendszer állapotának lekérdezése Állomány időadatainak módosítása Várakozás a gyermek(ek) befejeződéséig Adatblokk kiírása pufferből
7.2. táblázat. A UNIX kernel tipikus rendszerhívásai
7.4. Gyakorlatok 7.4.1.
Mit nevezünk rendszerhívásoknak?
7.4.2.
Mit nevezünk primitív műveleteknek?
7.4.3.
Létrejöhet-e elakadás egy primitív művelet végrehajtásakor?
7.4.4.
Megszakítható-e a primitív műveletek futása?
7.4.5.
Mennyi ideig tarthat a primitív műveletek végrehajtása?
7.4.6.
Mondjon példákat primitív műveletekre!
7.4.7.
Miért kell a primitív műveletek kódjainak tárrezidensnek lennie?
7.4.8.
Melyek a folyamatként futó rendszerhívások?
7.4.9.
Mi a helyzet a megszakításokkal a folyamatként futó rendszerrutinok esetében?
7. Mi a hasonlóság és a különbség a rendszerfolyamatok és a folyamatként futó rendszerrutinok között?
OS08V09.rtf,ZSP,2001-04-17,(sajtóhibák javítva)
8. ERŐFORRÁS-KEZELÉS
8.1. Alapelvek Amikor a számítógépes rendszerekben még a hardver árán volt a hangsúly, erőforráson a rendszer fontosabb hardver komponenseit értették: a központi egységet, a tárat, a B/K csatornákat és a különböző perifériákat. Az idők folyamán ez a szemlélet megváltozott, az erőforrások köre a szoftvererőforrásokkal, azaz a programokkal és az adatokkal bővült. A szoftvererőforrások -- mivel ezek élőmunka tartalma magas (és egyre növekvő) -- értéke emelkedik, a hardver erőforrásoké pedig élőmunka tartalmukkal együtt csökken. Gondoljunk például egy kiterjedt bankhálózatban tárolt adatok értékére: elvesztésük jóformán helyrehozhatatlan kárt okozna. Általában elmondható, hogy az operációs rendszerek egyik fontos funkciója a teljes számítógépes rendszer erőforrásainak kezelése. Ez azt jelenti, hogy az operációs rendszer gondoskodik az erőforrások elosztásáról, védett használatáról és a közben kialakuló versenyhelyzetek kezeléséről. Az erőforrás-kezelés során az operációs rendszer maga is létrehoz később elosztandó erőforrásokat. Ilyenek például a virtuális tárkezelésnél a lapok, a B/K során használt pufferek, a mágneses adathordozókon használt objektumok (blokkok, cilinderek, sávok, szektorok), vagy akár maguk az adatállományok és tartalomjegyzékeik. Az erőforrás-kezelés két alapvető célja a számítógéprendszer működésének valamilyen értelemben gazdaságossá tétele és a holtponthelyzetek kivédése. A két cél annyiban függ össze, hogy ha lemondanánk a gazdaságos üzemről, például az erőforrások osztott felhasználásáról, a holtpont kérdése fel sem merülne. A fejezetben az erőforrás-gazdálkodás magasabb szintű stratégiáival foglalkozunk csak, a fontosabb, konkrét erőforrások (processzor, tár állományok, programok) ütemezésének külön fejezeteket szenteltünk.
8.2. Gazdaságosság A számítógép használati értékét elsősorban az a haszon határozza meg, amit a gép használata közvetlenül vagy közvetve hajt. Ilyen lehet a termelési költség csökkentése, az adatok tárolása, a felhasználók termelékenységének növekedése, a minőségileg értékesebb és jobban ütemezett információszolgáltatás. A bevételt természetesen terhelik a hardverköltségek, az üzemeltetés és az alkalmazási rendszerek fejlesztési, vagy beszerzési költségei. A gazdaságos üzem valamilyen költségfüggvény értékének minimalizálását jelenti. A probléma általában az, hogy a költségfüggvény nem univerzális, hanem függ a számítógépes rendszer felhasználási körülményeitől. Az operációs rendszerek esetében általában két -- sajnos egymásnak ellentmondó -- költségfüggvényt használnak. Az egyik az erőforrások minél teljesebb kihasznált-
ságára törekszik, a másik a rendszer válaszkészségét igyekszik optimalizálni. Az általános stratégia mellett meg lehet fogalmazni -- nem ellentmondásmentes -- konkrétabb célokat is: * * * *
az átlagos átfutási idő minimalizálása, a lassú válaszok számának minimalizálása, a hardverkihasználtság maximalizálása, maximális kihasználtság adott válaszidő-korlát esetén
Elvileg az a jó -- és vannak is ilyen operációs rendszerek --, ha egy nagy rendszer esetében az üzemeltető befolyásolhatja az erőforrás-kezelési stratégiát. Az elmúlt 20 év alatt a hardver árával együtt a gazdaságosság megítélése is változott. Az a tendencia, hogy a maximális kihasználtság háttérbe szorul a válaszkészséggel szemben. A valós idejű rendszereknél ez mindig így is volt, de újabban általánossá vált az időosztásos rendszereken folyó fejlesztési tevékenység is, ami szintén a válaszkészségre helyezi a hangsúlyt. A személyi számítógépek elterjedése ugyancsak ebbe az irányba hatott. A kötegelt rendszereknél ugyanakkor az erőforrások minél jobb kihasználására kell törekedni, hiszen az operációs rendszer a munkákat saját szempontjainak megfelelően ütemezheti. Ilyen esetben sokat segíthet a rendszernek a manuális előtervezés, melynek során a munkákat a rendszer által jobban ütemezhető osztályokba sorolják. Az ehhez szükséges információ a munkavezérlő programból nyerhető, illetve egyes számítóközpontok elvárják a felhasználótól a munka jellemzőinek megadását. E jellemzők igen változatosak lehetnek, az általunk közölt minta nem tekinthető teljesnek: * * * * * *
relatív prioritás kezdési határidő befejezési határidő központiegység-igényesség B/K igényesség tárigény
A kötegelt üzemű operációs rendszer magas szintű ütemezője (l. a 9. fejezetet) az indításra váró munkák közül jellemzőik alapján válogatva létrehozza és állandóan feltölti az indítható munkák sorát. Egy munka akkor indulhat, ha a közbenső ütemezővel megvalósított erőforrás-lefoglalási stratégia által támasztott feltételeknek eleget tesz.
8.3. Az erőforrások lefoglalása A klasszikus kötegelt feldolgozás idején az alacsony szintű ütemező az indítható munkák közül olyat próbált választani, amelyhez az erőforrások -- tár, adatállományok és perifériák -rendelkezésre álltak. Ilyenkor az ütemezés és az erőforrás-lekötés eseménye összekeveredett: a rendszer az F1 munkához például lefoglalta a tárat (mert ezt meg tudta tenni), majd üzenetet küldött az operátornak, hogy tegye fel azt a mágnesszalagot, amelyen az A1 állomány van. Ezután az ütemező esetleg az F2 munkához is foglal tárat és egy lemezállományt, majd üzen egy másik mágnesszalagért. E tevékenységek eredményeként még egyik munka sem indult el, de már le volt kötve tár és két szalagegység. A munka csak akkor indulhatott, ha az ütemező a két említett feladat minden erőforrásigényét "összegyűjtögette". Ezt a módszert statikus lefoglalásnak nevezzük, hiszen az erőforrások lekötése a munka indítása előtt megtörténik. Nagy hátránya, hogy az erőforrások akkor is függő (más munka számára igénybe nem vehető) állapotban lehetnek, amikor tulajdonképpen még senki nem használja őket. A statikus rendszerben egy munka
meghatározhatatlan ideig várakozhat az indítható munkák sorában mielőtt sorra kerül. Azonban, ha egy munka végrehajtása elindult, erőforráshiány miatt nem szakad meg. A statikus lefoglalást természetes módon szorította ki a dinamikus módszer, amelyben az indítandó munkát minden előzetes erőforrásigény kielégítése nélkül választjuk ki. A szükséges erőforrásokat a munka maga kérheti futása során az operációs rendszertől. Az ütemező csak azt biztosította, hogy a munka részt vehet az erőforrásokért folyó versenyben. A felhasználó számára előny a gyors indítás, ami természetesen még nem garantálja a gyors befejezést. Az operációs rendszer számára az éppen nem használt erőforrások szabaddá tétele és újra hasznosíthatósága a fontos, ami azonban függ a programozótól is. Ilyen stratégia mellett nagymértékben növekedhet a rendszer átbocsátóképessége, ha minden folyamat csak addig tart magánál egy erőforrást, ameddig arra okvetlenül szűksége van (pl. a programozó nem felejtkezik meg a már feldolgozott állományok azonnali lezárásáról). Dinamikus stratégiát követnek a modernebb kötegelt, valamint az időosztásos rendszerek, ahol a statikus módszer szóba sem jöhetne.
8.4. Holtpont A holtpont jelenség tulajdonképpen az erőforrásokkal gazdálkodó, megosztott használatukat lehetővé tevő algoritmusok mellékhatása, melynek kezelése egyetlen fejlett operációs rendszerből sem hiányozhat. Egy folyamathalmaz akkor kerül holtponthelyzetbe, amint ezt a 3. fejezetben már láttuk, ha mindegyikük egy olyan esemény bekövetkezésére vár, amit csak a halmaz valamelyik folyamata válthatna ki, de erre nincs lehetőség. Az erőforrásokkal kapcsolatban az esemény értelemszerűen azok lekötése és elengedése lehet. A dinamikus lefoglalási stratégiának megfelelően egy folyamat a következő sorrendben kerül egy erőforrással kapcsolatba: * Igénylés. Ha az igény nem teljesíthető azonnal (pl. az erőforrást egy másik folyamat használja), az igénylő várakozásra kényszerül * Használat. * Felszabadítás. Az igénylés és a felszabadítás mindenképpen az operációs rendszer privilegizált rutinjainak hívását jelenti, a használat elvileg a felhasználó hatáskörében is megoldható, de az alsó szinten általában itt is rendszerrutinok működnek. A holtpont kezelése érdekében kielemezték a holtpont bekövetkezéséhez szükséges, feltételrendszert. E szerint egy rendszer csak akkor kerülhet holtponthelyzetbe, ha a következő négy feltétel egyidejűleg teljesül: * Kölcsönös kizárás van. Legalább egy erőforrás nem osztható módon foglalt, azaz egyszerre csak egy folyamat használhatja. Ha egy másik folyamat is igényli, várnia kell az erőforrás felszabadulásáig. * Várás közben lekötés történik. Van olyan folyamat, amely leköt legalább egy erőforrást, miközben várakozik más folyamatok által használt erőforrás(ok)ra. * Rablás nincs. Az erőforrások egy folyamattól erőszakkal nem vehetők el. A felszabadítást a folyamat mindig önkéntesen végzi. * Ciklikus várakozás lép fel. Létezik a folyamatok olyan {p0, p1, ... pn} halmaza, hogy p0 a p1 által lefoglalt, p1 a p2 által lefoglalt,... pn a p0 által lefoglalt valamelyik
erőforrásra várakozik. A feltételek nem teljesen függetlenek, a "ciklikus várakozás" például tartalmazza a "várás közbeni lekötés" feltételt. A négy feltételt a későbbi tárgyalás egyszerűsítése érdekében célszerű mégis megtartani. A holtpontkezelésnek két alapvető módja van: bizonyos szabályok betartásával megelőzzük, vagy felismerjük a bekövetkezését, majd a rendszert felélesztjük. Mint látni fogjuk, a megelőzés az "olcsóbb". 8.4.1. A holtpont megelőzése Azt kell biztosítani, hogy a négy szükséges feltétel közül legalább egy ne teljesüljön. Ennek érdekében mindegyiket közelebbről is meg kell vizsgálni. A "kölcsönös kizárási feltétellel" nem sokra juthatunk. Ez olyan eszközökre vonatkozik, melyeket nem használhat két folyamat párhuzamosan (például egy sornyomtató). A párhuzamosan használható erőforrásokat viszont nem célszerű kölcsönösen kizáró módon kezelni, ezért ezek nem játszanak szerepet a holtpont kialakulásában. Ha például egy csak-olvasható állományt tekintünk, azt akárhány folyamat használhatja egyidejűleg, tehát arra senkinek nem kell várnia. Mivel azonban egyes erőforrások természetüknél fogva nem oszthatók, a kölcsönös kizárás nem küszöbölhető ki és így a holtpont nem előzhető meg. Ha azt akarjuk, hogy a "várás közbeni lekötés" feltétel soha ne teljesüljön, lehetővé kell tenni, hogy valahányszor egy folyamat erőforrást igényel, ne tartson másik erőforrást lekötve. Ez legegyszerűbben a 8.3.-ban tárgyalt statikus lefoglalási stratégiával biztosítható, azaz a folyamat csak az összes erőforrás előzetes megszerzése után indulhat. A másik megoldás, hogy minden folyamat csak akkor igényelhet újabb erőforrást, ha nincs lekötött erőforrása. Példaként tekintsünk egy folyamatot, amely cserélhető lemezről átmásol egy állományt fix lemezre, ott rendezi, majd nyomtatón kiírja az eredményt. Az első megoldás szerint a folyamatindulás előtt igényli és lefoglalja a cserélhető lemezt, a fix lemezt és a nyomtatót. A nyomtatót végig leköti, pedig csak az utolsó fázisban van rá szüksége. A másik megoldás először csak a kétféle lemezt igényli, elvégzi a másolást és a rendezést, majd felszabadítja a lemezeket. Ezután újra igényli a fix lemezt és a nyomtatót. Ha megkapja, kinyomtatja a rendezett állományt, majd minden erőforrását felszabadítja és befejeződik. Mindkét megoldásnak komoly hátránya, hogy igen rossz lehet az erőforrások kihasználtsága, hiszen lekötött erőforrások hosszú ideig kihasználatlanul állhatnak. A másik probléma, hogy nem korlátos annak a folyamatnak a várakozási ideje, amelyik több, gyakran használt erőforrást igényel, hiszen az összes igen ritkán válik egyszerre szabaddá. Ezt a jelenséget "éheztetés"-nek is nevezik. A "harmadik feltétel" az volt, hogy egy folyamattól nem lehet elrabolni a már megszerzett erőforrásait. Ha azt akarjuk, hogy ez ne teljesüljön, a következőképpen járhatunk el: ha egy folyamat, amelyik már lekötött valamilyen erőforrást, újabb olyan erőforrást igényel, amit nem lehet azonnal hozzárendelni (azaz a folyamat várakozni kényszerül), az összes eddig lekötött erőforrását el kell rabolni (erőszakkal fel kell szabadítani). Az elvett erőforrások felkerülnek azon erőforrások listájára, melyekre a folyamat várakozik. A folyamat csak akkor folytatódik, ha egyaránt visszaszerzi a régi és új erőforrásait. Ugyanúgy célhoz juthatunk, hogy ha egy folyamat erőforrást igényel, először megnézzük, hogy az erőforrás elérhető-e. Ha igen, lekötjük; ha nem, ellenőrizzük, hogy olyan folyamathoz kötött-e,
amelyik további erőforrásra vár. Ha igen, elraboljuk az igényelt erőforrást a várakozó folyamattól, és odaadjuk az igénylőnek. Ha az erőforrás nem hozzáférhető, vagy más okból várakozó folyamathoz tartozik, az igénylőnek várnia kell. Miközben várakozik, egyes erőforrásait elrabolhatják, de csak akkor, ha egy másik folyamat igényli azokat. A folyamat akkor indulhat újra, ha megkapja az újonnan igényelt és visszaszerzi a várakozás közben esetleg elvesztett erőforrásait. Ez a módszer jól alkalmazható olyan erőforrásokra, melyek állapota könnyen menthető és visszaállítható (pl. a központi egység regiszterei, a tár). Általában nem használható sornyomtatóknál és mágnesszalagoknál (ennek ellenére a T.H.E. rendszerben a sornyomtató elrabolható volt, az esetleg összekeveredett listákat az operátor szétválogatta!). A "ciklikus várakozás" kiküszöbölésére, az összes erőforrásra teljes rendezettséget kell létrehozni. Minden erőforrástípushoz egy egyedi egész számot rendelünk, melynek segítségével bármely két erőforrásról eldönthető, hogy a mi rendezési sorrendünk szerint melyik előzi meg a másikat. Legyen Ei az i. erőforrás és a hozzátartozó egész számot jelöljük F(Ei)-vel. Az alábbi szabályok betartásával a holtpont megelőzhető. A folyamatok csak növekvő sorrendben igényelhetnek erőforrásokat. Egy folyamat először akárhány példányt igényelhet, mondjuk az Ei erőforrásból. Ezután a folyamat csak akkor jogosult egy Ej erőforrás igénylésére, ha F(Ej)>F(Ei). Ha azonos típusú erőforrásból több példányra van szükség, ezt egyetlen igénylésként kell kezelni. Másképp fogalmazva ez azt jelenti, hogy az Ej típusú erőforrást igénylő folyamattól egyszerűen megköveteljük minden olyan Ei erőforrásának felszabadítását, melyre F(Ei) > F(Ej). Könnyű belátni, hogy a fenti módszer nem engedi meg a ciklikus várakozást, mert a szigorú rendezettség miatt a várakozási kör nem tud bezárulni. Megjegyezzük, hogy az F függvény értékeit az erőforrások természetes felhasználási sorrendjének megfelelően célszerű definiálni. A lemezek például általában előbb használatosak, mint a nyomtatók. A fenti algoritmusok közös tulajdonsága, hogy az igénylések megszorításával elérik, hogy valamelyik szükséges feltétel nem teljesül, de eközben esetleg csökken az eszközök kihasználtsága és a rendszer áteresztőképessége. A holtpont úgy is elkerülhető, ha a folyamatok igényeiről további információt kérünk. E modellek közül a legegyszerűbb és leghasznosabb, amely minden folyamattól megköveteli annak közlését, hogy az egyes erőforrástípusokból maximálisan hányat igényel. Ezen információ birtokában olyan algoritmus szerkeszthető, amely lehetővé teszi a holtpont elkerülését. A holtpontelkerülő algoritmus dinamikusan vizsgálja az erőforrás-kiosztási állapotokat és kiküszöböli a ciklikus várakozást. Az erőforrás-kiosztási állapot a még szabad és a már lekötött erőforrások számával, valamint a folyamatok maximális igényeivel jellemezhető. Egy állapot biztonságos, ha minden folyamat igényét valamilyen sorrendben ki lehet elégíteni a ciklikus várakozás bekövetkezésének veszélye nélkül. A folyamatok egy F1, F2,... Fn sorozata akkor biztonságos, ha a még igényelhető erőforrások minden Fi-re vagy azonnal biztosíthatók, vagy olyan Fj folyamatok birtokában vannak, melyekre j
fel, ami holtponthoz vezet. +---------------------------+ | +-----------+ Bizonytalan | | | | /| | | Holtpont | / | | | | / | | +-----------+ / | | / | | -----------------| | / | | / | | / | |/ Biztonságos | | | +---------------------------+ 8.1. ábra. Biztonságos, bizonytalan és holtponti állapot Legyen például az E erőforrásból a rendszerben 12 darab, legyenek az F1, F2 és F3 folyamat maximális igényei, illetve egy T1 időpontban már lekötött erőforrásai a következők: Max. igény
Lekötve
F1 10 5 F2 4 2 F3 9 2 T1 időpontban (3 E szabad) a rendszer biztonságos állapotban van, mivel az F2, F1, F3 sorozat biztonságos. Természetesen több folyamat és sokféle erőforrás esetén egy biztonságos sorozat megtalálása nem egyszerű, a 8.5. pontban példaként néhány erre vonatkozó algoritmus található. 8.4.2. A holtpont felismerése A holtpont kezelésének másik módja: egy felismerő és felélesztő alrendszer alkalmazása. A felismerő periódikusan megvizsgálja a rendszer állapotát, és eldönti, hogy holtponthelyzetben van-e. Ha igen, megkísérli a felélesztést. Ennek érdekében két tevékenységre van szükség: * Folyamatosan karbantartott információ az erőforrások szétosztásáról és minden ki nem elégített igényről. * Algoritmus, amely a fenti információból eldönti, hogy a rendszer holtponthelyzetbe került-e. A 8.5. pontban szerepel egy általános felismerő algoritmus, melynek használatához azonban tisztában kell lennünk azzal, hogy bármilyen felismerő-felélesztő módszer rontja a rendszer hatásfokát: egyrészt a futási idők növelésével, másrészt azzal, hogy a felélesztés során a már elvégzett munka egy része megsemmisülhet. Külön probléma, hogy milyen gyakran hajtsuk végre a felismerő algoritmust. Ehhez meg kellene
becsülni a holtponthelyzetek gyakoriságát, illetve az egy-egy holtpontnál érintett folyamatok számát. Ha ez nem sikerül, gondoljunk arra, hogy holtpont csak akkor állhat elő, ha egy igényt nem lehet azonnal kielégíteni. Ha minden ilyen esetben meghívjuk a holtpontfelismerő algoritmust, nem csak a holtpontban érintett folyamatokat azonosíthatjuk, hanem azt a folyamatot is, amelyik "lezárta" a várakozási ciklust (az is előfordulhat, hogy egyszerre több ilyen ciklus záródik le). Az ilyen mérvű "éberség" természetesen számottevő időt vonhat el a termeléstől. Ha a felismerő algoritmus hívásait ritkítjuk, és önkényesen jelöljük ki a hívási időpontokat (pl. negyedóránként, vagy ha a központi egység kihasználtsága 40% alá esik), előfordulhatnak többszörös ciklikusan várakozó sorok is és ilyenkor a felélesztés nagyobb veszteséget okoz. A rendszer holtpont utáni felélesztésére két módszer kínálkozik: felszámolunk egy, esetleg több folyamatot, hogy megszűnjön a ciklikus várakozás, vagy a holtpontban résztvevő folyamatoktól elrabolunk egyes erőforrásokat. A folyamatok felszámolását megoldhatjuk radikálisan, azaz megölünk minden folyamatot a ciklikus várakozási láncban. Ez igen nagy kárt okozhat, ezért általában részleges eliminációt alkalmaznak, a folyamatokat egyenként ölik meg, ameddig a ciklikus várakozás meg nem szűnik. Megjegyezzük, hogy egy folyamat eliminálása bonyolult helyzetet teremthet (pl. a folyamat éppen egy állomány írása közben volt). Az sem mindegy, milyen sorrendben választjuk ki az áldozatokat. Itt általában a következő szempontokat kell mérlegelni: * A folyamat prioritása * Mennyi ideje működött már a folyamat és, mennyi időre lenne még szüksége? * Hány és milyen erőforrást kötött le? * Hány további erőforrást igényel még? * A visszalépés hány folyamatot érint? Az erőforrásrablásnál hasonló jellegű problémák merülnek fel. Először meg kell találni az áldozatot, majd el kell dönteni, hogy melyik erőforrásától fosztjuk meg. Mindkét esetben a fentiekhez hasonló szempontok alapján célszerű dönteni. Ha a döntés megszületett, további kérdés, hogy meddig lépjünk vissza a kirabolt folyamatban? Nem mindig tanácsos a teljes újraindítás, elképzelhető, hogy a holtpont már egy kisebb visszalépéstől is megszűnik. Ilyen "manőverekhez" azonban sok információt kell nyilvántartani az aktív folyamatokról. A gyakorlatban ilyen célt szolgálhatnak az ún. ellenőrző pontok (angolul: check point), melyeknél a folyamat félbeszakításra alkalmas pontjain -- éppen a holtpontra vagy egyéb hibára gondolva -- minden, a folytatáshoz szükséges információt tárolnak valamilyen alkalmas háttértárban. Végül arra is gondolni kell, hogy ne mindig ugyanattól a folyamattól raboljuk el erőforrásait és ezzel folyamatos éhezésre ítéljük. A megoldás az, hogy ugyanaz a folyamat nem választható akárhányszor áldozatul.
8.5. Korlátok, kompromisszumok Az erőforrás-kezelés hasznával és értelmével kapcsolatban alapvető tény, hogy minél összetettebb
a rendszer hardverrétege, minél gazdagabb a megosztottan használható, párhuzamosan működő erőforrások választéka, annál hatékonyabb lehet egy intenzív erőforrás-kezelő rendszer. Mint egyéb szabályzórendszereknél, itt sem jók a végletes megoldások. Az egyik véglet az alul szabályozás, amikor az erőforrás-kezelés nem képes hasznosítani a hardverben rejlő lehetőségeket: nem működteti párhuzamosan az erre alkalmas eszközöket, vagy feleslegesen várakoztat folyamatokat. Az erőforrás-kezelés túlszabályozása azt jelenti, hogy a rendszer az erőforrások jó elosztása érdekében túl sok adminisztrációt végez, felesleges információt tárol és módosít folyamatosan, s ezzel csökkenti a hasznos teljesítményt. Nem szabad elfelejteni, hogy az erőforrás-kezelés szabályozása, az ütemező, a holtpontkezelő stb. algoritmusok ugyanattól a rendszertől vonnak el erőforrásokat, amely elsősorban a felhasználó számára hivatott hasznos munkát végezni. Annak megítélése, hogy egy rendszer mikor túlszabályozott, nem lehet teljesen objektív. Ha példát keresünk, akkor az OS/360--at említhetjük, ahol mind az MFT, mind az MVT változatoknál előfordult, hogy a központi egység tiszta idejének mintegy 50%-át "fogyasztotta el" az operációs rendszer és akkor még nem is említettük az általa lekötött hatalmas tárterületet. Az erőforrás-kezelő alrendszer tehát gondos mérlegelést igényel. Igen fontos, hogy a számítógéprendszer technikai színvonalához jól illeszkedő megoldást találjunk. A felhasználó szempontjából az alapvető kompromisszum eredménye a döntő: a válaszkészséget vagy az eszközkihasználtságot részesítsük-e előnyben? Van, amikor adott erre a válasz (valós idejű rendszerek), de általában csak az alkalmazási környezet gondos elemzése nyújt támpontot.
8.6. Mintapéldák
A fejezet példaanyaga a holtpontkezelésre vonatkozik, az erőforrás-kezelés egyéb részleteivel kapcsolatos példák a 9-12. fejezetekben találhatók. 8.6.1. Megelőzési algoritmusok Elsőként az ún. "bankár" algoritmust ismertetjük. Ennek lényege, hogy egy jó bankár sohasem helyezi ki úgy a pénzét, hogy ne tudja minden ügyfele igényét kielégíteni. Az alapelv az, hogy minden belépő folyamat erőforrás-típusonként deklarálja maximális igényét, ami természetesen nem haladhatja meg a rendszer teljes állományát. Ha a folyamat erőforrást igényel, azt kell eldönteni, hogy az igény kielégítése még biztonságos állapotban hagyja-e a rendszert. Ha igen, az erőforrást megkapja, különben addig vár, amíg e helyzet megváltozásához elegendő erőforrás fel nem szabadul. Az algoritmus megvalósításához szükséges adatokat mátrixokban tároljuk: m: az erőforrástípusok száma, n: a folyamatok száma. Készlet: m elemű vektor, melynek i. eleme az Ei erőforrásból rendelkezésre álló mennyiséget tartalmazza. Max: n*m méretű mátrix, amely az egyes folyamatok maximális igényét tartalmazza. Max(i,j)=k, ha az Fi folyamat az Ej erőforrásból legfeljebb k darabot igényelhet. Lekötés: n*m méretű mátrix, amely folyamatonként és típusonként a pillanatnyilag lekötött erőforrások számát tartalmazza. Lekötés(i,j)=k, ha az Fi folyamat az Ej erőforrásból éppen k darabot köt le.
Szükséglet: n*m méretű mátrix, amely folyamatonként és típusonként a még ki nem elégített erőforrások mennyiségét tartalmazza. Szükséglet(i,j)=k, ha az Fi folyamat még k darabot igényel az Ej erőforrásból ahhoz, hogy befejeződhessen. Igény: n*m méretű mátrix, amelynek i. sora Fi pillanatnyi igényét tartalmazza típusonként. Igény(i,j)=k, ha Fi pillanatnyilag k darabot igényel Ej--ből. Az algoritmus leírásában -- az egyszerűség kedvéért -- bevezetjük két vektor (A és B) között a következő relációt: A <= B, ha A és minden megfelelő elempárjára teljesül a <= reláció. Amikor Fi "benyújtja igényeit Igény(i) formában, a következőket kell tenni: 1. Ha Igény(i) <= Szükséglet(i), folytatás 2.-kal, különben hiba történt, mert a folyamat átlépte maximális igényét. 2. Ha Igény(i) <= Készlet, folytatás 3.-kal. Különben nincs elegendő szabad készlet, Fi-nek várnia kell. 3. A rendszer szimulálja Fi igényeinek kielégítését: Készlet := Készlet - Igény(i); Lekötés(i) := Lekötés(i) + Igény(i); Szükséglet(i) := Szükséglet(i) - Igény(i); Ha az új állapot biztonságos, Fi megkapja, amit igényelt, ha az új állapot bizonytalan, Fi--nek várnia kell és a rendszer eredeti állapotába kerül vissza. A következő algoritmussal dönthetjük el, hogy egy állapot biztonságos-e: legyen S egy m elemű vektor, amelynek kezdeti értéke S = Készlet. Legyen Biztos egy n elemű logikai vektor, melynek kezdetben minden eleme hamis (false). 1. Keressünk olyan i-t, amelyre Biztos(i)=hamis és Szükséglet(i)<=S. Ha ilyen i nincs, folytatás 3.-kal. 2. S:=S+Lekötés(i); Biztos(i):=igaz; Folytatás 1.-vel. 3. Ha Biztos minden eleme igaz, a rendszer biztonságos állapotban van. 8.6.2. Holtpontfelderítő algoritmus A bankár algoritmus adatszerkezetei közül használjuk a Készlet vektort, a Lekötés, és az Igény mátrixot. Az S vektor kezdetben szintén a Készlet elemeit tartalmazza. Legyen Hpont egy n elemű logikai vektor, melynek i. eleme kezdetben hamis, ha Lekötés(i)-ben van nem 0 elem; és igaz, ha nincs. 1. Keressünk olyan i-t, melyre Hpont(i)=hamis és Igény(i)<=S. Ha ilyen i nincs, folytatás 3.-kal. 2. S:=S+Lekötés(i); Hpont(i):=igaz; Folytatás 1.-vel.
3. Ha Hpont-ban van hamis elem, a rendszer holtponton van. Ha Hpont(i)=hamis, akkor Fi a holtpontot okozó várakozó lánchoz tartozik. Az algoritmus természetszerűleg hasonlít a biztonságot eldöntő algoritmushoz.
8.7. Gyakorlatok 8.7.1.
Milyen erőforrásokat ismerünk?
8.7.2.
Mi az erőforrás-kezelés célja?
8.7.3.
A számítógép üzemeltetésének két fontos költségfüggvénye és ezek viszonya.
8.7.4.
Milyen típusú operációs rendszerek helyezik válaszkészségre a hangsúlyt?
8.7.5.
Mi az erőforrás-lefoglalás két formája?
8.7.6.
Hogyan segítheti a programozó a dinamikus erőforrás--lefoglalást?
8.7.7.
A holtpontkezelés két alapvető stratégiája.
8.7.8.
A holtponthelyzet kialakulásához szükséges feltétel rendszer.
8.7.9.
Mit értünk a rendszer biztonságos, illetve bizonytalan helyzetén?
8.7.10.
Mit nevezünk egy folyamat éheztetésének?
8.7.11.
Mi a bankár algoritmus?
8.7.12.
Legyen egy rendszerben 5 folyamat (F1,...F5) és 3 féle erőforrás (E1--ből 10, E2--ből 5, E3--ból 7 darab). Legyen egy adott pillanatban a helyzet a következő: Lekötés Max Igény Készlet E1 E2 E3 E1 E2 E3 E1 E2 E3 E1 E2 E3 F1 0 1 0 7 5 3 7 4 3 2 3 0 F2 3 0 2 3 2 2 0 2 0 F3 3 0 2 9 0 2 6 0 0 F4 2 1 1 2 2 2 0 1 1 F5 0 0 2 4 3 3 4 3 1 a) Döntsük el, hogy ez az állapot biztonságos-e! b) Mi történik (milyen állapotba kerül a rendszer), ha F5--re Igény = (3, 3, 0) lenne? c) Mi történik, ha F1--re Igény = (0, 2, 0) lenne?
8.7.13.
Legyen egy rendszerben 5 folyamat (F1,...F5) és 3 féle erőforrás (E1-ből 7, E2-ből 2, E3-ból 6 darab). Legyen egy adott pillanatban a helyzet a következő: Lekötés Szükséglet Készlet E1 E2 E3 E1 E2 E3 E1 E2 E3 F1 0 1 0 0 0 0 0 0 1 F2 2 0 0 2 0 2 F3 3 0 2 0 0 0 F4 2 1 1 1 0 0 F5 0 0 2 0 0 2 a) Döntsük el, hogy a rendszer holtponthelyzetben van-e! b) Mutassuk meg, hogy ha Igény=(0, 0, 1), a rendszer holtpont-helyzetbe kerül! Mely folyamatok szerepelnek a ciklikus várakozási láncban?
OS09V07.RTF,ZSP,2001-04-17.
9. PROCESSZORKEZELÉS
A központi egység -- a talán legfontosabb hardvererőforrás -- idejének folyamatok közötti elosztása a multiprogramozott operációs rendszerek alapja. Mint az erőforrások ütemezésénél általában, a cél most is a számítógépes rendszer termelékenységének fokozása.
9.1. Alapfogalmak: az ütemezés eszközei A multiprogramozástól azt várjuk, hogy javítsa a központi egység kihasználtságát, és növelje a rendszer átbocsátóképességét (az adott idő alatt végrehajtható feladatok mennyiségét). A központi egység kihasználtsága azért nő, mert a B/K műveletek alatt újabb folyamatokat lehet aktivizálni. Az átbocsátóképesség növekedését egy egyszerű példával szemléltetjük: Az A és B feladat egyformán viselkedik: mindegyik fut egy másodpercig, majd B/K műveletet végez egy másodpercig, és ez 100-szor ismétlődik. Ha a két feladatot egymás után futtatjuk, 400 másodpercre van szükség a végrehajtásukhoz. Közben a központi egység pedig csak az idő felében dolgozik. Ha az A feladat várakozási idejében a központi egység a B feladatot hajtaná végre, a B várakozási idejében pedig újra az A-t, a teljes átfutási idő megfeleződne, a központi egység kihasználtsága pedig megkétszereződne, vagyis 100% lenne. Figyeljük meg, hogy az A feladat ugyanakkorra fejeződik be, mint az előző esetben, a javulás abból ered, hogy ez alatt a B feladat is lefut. Természetesen ilyen jól illeszkedő feladatok a gyakorlatban nincsenek, de a multiprogramozás akkor is sokat segíthet, ha csak közelíti a fenti példát. A központi egység ütemezése azon a felismerésen alapszik, hogy minden folyamat két tevékenység ciklikus ismétléséből áll: CPU használat és B/K használat. A ciklus végén mindig központi egység művelet van. Statisztikai mérések azt mutatták, hogy -- bár a központiegység-használati szakaszok erősen függenek a folyamatoktól és a hardvertől -- általában minden folyamat során túlnyomó többségben vannak az igen rövid CPU használati szakaszok, és csak nagyon kevés, a központi egységet használó hosszú szakasz fordul elő. Az ún. CPU orientált programokra jellemző néhány ilyen igen hosszú szakasz, míg a programok többsége B/K-orientált. A folyamatok állapotáról már a 3. fejezetben is volt szó (l. 3.8. ábra), most a központi egység szempontjából finomítjuk az ott elmondottakat. Mivel a CPU egyszerre több aktív folyamattal is foglalkozik, az aktív állapotot felbontjuk ún. kész (amikor a folyamat a B/K miatt futhatna, de a CPU-ra várnia kell), illetve futó állapotra (l. 9.1. ábra).
.------. .----. .----. .----------. ( ÚJ ) ==> ( KÉSZ ) ==> ( FUTÓ ) ==> ( BEFEJEZETT ) *------* *----* *----* *----------* ^ | | .---------. | | +---> ( HOLTPONTI ) | | *---------* | v .---------. ( VÁRAKOZÓ ) *---------* 9.1. ábra. Folyamatállapotok „A” PROGRAM OPERÁCIÓS RENDSZER „B” PROGRAM | . FUTÓ | . >------------------\ . . MEGSZAKÍTÁS V . . +-------------------+ . . | REGISZTEREK | . . | MENTÉSE | . VÁRAKOZÓ . +-------------------+ . . | MAGRUTIN FUT . . +-------------------+ . . | REGISZTEREK | . . | VISSZAÁLLÍTÁSA | . . +-------------------+ . . \ ÁTKAPCSOLÁS . . --------------------> VÁRAKOZÓ . | FUTÓ . --------------------< . / MEGSZAKÍTÁS . . +-------------------+ . . | REGISZTEREK | . . | MENTÉSE | . . +-------------------+ . . | MAGRUTIN FUT . VÁRAKOZÓ . +-------------------+ . . | REGISZTEREK | . . | VISSZAÁLLÍTÁSA | . . +-------------------+ . . ÁTKAPCSOLÁS / . <-----------------. FUTÓ | . | . 9.2. ábra. Átkapcsolás (context switch)
A megszakíthatóság és ütemezhetőség érdekében minden folyamathoz többféle információt kell tárolni. Ezen információk tárolási helyét folyamatvezérlő blokknak (angolul: Process Control Block = PCB) nevezik, és szerkezete a következő: * A folyamat állapota: új, kész, futó, váró, holtponti vagy befejezett.
* Az utasításszámláló tartalma: a folyamat következőként végrehajtandó utasításának címe. * A CPU regisztereinek tartalma. * Különféle tárkezelési információk: bázisok és limitek, laptáblák stb. (l. 10. fejezet). * Elszámolási információk: CPU idő, valós idő, idő limit, számlaszám, feladat, vagy folyamatazonosító stb. * B/K-állapot információ: ki nem elégített B/K igények, a folyamathoz rendelt B/K egységek, nyitott állományok stb. * CPU-ütemezési információ: prioritás, ütemezési sorban elfoglalt pozíció, egyéb paraméterek. A PCB-ket az operációs rendszer területén rendszerint egy lista formájában kell tárolni. Ez történhet statikusan (a maximális folyamatszám rögzítése után) vagy dinamikusan. A PCB segítségével a központi egység átkapcsolható egyik folyamatról a másikra és vissza, amint ezt a 9.2. ábra szemlélteti.
KÉSZEN- +------+ +---PCB4----+ +---PCB2----+ LÉTI | FEJ .>-->| .>-->| .>-->NIL SOR +------+ +-----------+ / +-----------+ | VÉG .>-\ |REGISZTEREK| | |REGISZTEREK| +------+ | | . . . | | | . . . | | +-----------+ | +-----------+ \------->-------/ MÁGNES- +------+ SZALAG | FEJ .>--\ 00 +------+ NIL | VÉG .>--/ +------+ MÁGNES- +------+ +---PCB3----+ SZALAG | FEJ .>-->| .>-->NIL 01 +------+ / +-----------+ | VÉG .>- |REGISZTEREK| +------+ | . . . | +-----------+ MÁGNES- +------+ +---PCB8----+ +---PCB12---+ +---PCB9----+ LEMEZ | FEJ .>-->| .>-->| .>-->| .>->NIL 00 +------+ +-----------+ +-----------+ / +-----------+ | VÉG .>-\ |REGISZTEREK| |REGISZTEREK| | |REGISZTEREK| +------+ | | . . . | | . . . | | | . . . | | +-----------+ +-----------+ | +-----------+ \------->--------------->-------/ TERMI- +------+ +---PCB5----+ NÁL | FEJ .>-->| .>-->NIL 00 +------+ / +-----------+ | VÉG .>- |REGISZTEREK| +------+ | . . . | NIL = NULLPOINTER +-----------+ 9.3. ábra. Várakozó sorok és láncolt listák A cél az, hogy valamelyik folyamat állandóan futó állapotban legyen. Egyprocesszoros rendszernél természetesen minden időpontban csak egy folyamat lehet futó, a többiek várnak (kész állapotban) és egy sort alkotnak, amelyet "készenléti" sornak nevezünk. A készenléti sort -- a B/K egységekre váró folyamatok soraihoz hasonlóan -- általában láncolt listákkal valósítják meg. A láncolt listákat mutatja be a 9.3. ábra. A készenléti sor feldolgozása pedig -- mint látni fogjuk -az egyes ütemezési algoritmusoktól függően változhat.
9.2. Ütemezési szintek A központi egység ütemezését és a folyamatok rendszerben megtett útját jól mutatja a 9.4. ábra. MAGAS SZINTŰ
+------------+ | KÉSZENLÉTI |
ALACSONY SZINTŰ
--/
\
KÉSZ
------------>| SOR |------------->( CPU )-----> ÜTEMEZŐ x--->| | ÜTEMEZŐ \ / | +------------+ -+| | | | VÁRAKOZÁS | | | | | +----------+ | | *-----* | | | x--| B/K |<----| B/K SOR |<--------x *-----* | | +----------+ 9.4. ábra. Központi egység ütemezés Számunkra a készenléti sor a fontos, hiszen ez tartalmazza a központi egységre váró feladatokat. Az ütemezést, első közelítésben, két lépcsőben végzik: a magas szintű ütemező dönti el, hogy mely feladatok kerülhetnek a készenléti sorba. Kötegelt feldolgozásnál ugyanis gyakran több feladatot közölnek a rendszerrel, mint amennyit azonnali végrehajtásra át tud venni. A feladatok a háttértáron várakoznak, ameddig a magas szintű ütemező át nem viszi őket a készenléti sorba. Az alacsony szintű ütemező a készenléti sorból kiválasztott feladathoz rendeli a központi egységet, azaz "futtatja" a programokat. A két ütemező között több eltérés lehetséges, de a legfontosabb különbség végrehajtásuk gyakoriságában van. Az alacsony szintű ütemező igen gyakran fut, másodpercenként százszor is indítják, hogy egy B/K művelet miatt felfüggesztett folyamat helyett másikat aktivizáljon. Ezért az alacsony szintű ütemezőnek igen gyorsnak kell lennie. Annak eldöntése, hogy egy folyamat néhány század másodpercig aktív legyen, nem tarthat még egy ezredmásodpercig sem, mert különben a rendszer "kieső ideje" (angolul: overhead, amikor nem a felhasználó programja, hanem az operációs rendszer maga működik) igen magas lenne. A magas szintű ütemező azonban viszonylag ritkán dolgozik, mert lehet, hogy percekig nem érkezik újabb feladat. Fő feladata a multiprogramozás fokának (a tárban lévő folyamatok számának) vezérlése. Ha a multiprogramozás fokát állandó szinten tartjuk, akkor a rendszerbe többé-kevésbé annyi feladat lép be, amennyi távozik. Így a magas szintű ütemezőt elég csak a befejezett munkák után hívni. Ezzel az ütemezővel szemben tehát nem a sebesség az elsődleges követelmény, hanem, hogy minél jobb munkakeveréket töltsön a készenléti sorba. A munkakeverék akkor jó, ha egyformán tartalmaz CPU-, illetve B/K-orientált feladatokat. Ha ez az egyensúly felborul, akkor valamelyik várakozó sor kiürül, és a megfelelő ütemező (az alacsony szintű vagy a B/K) munka nélkül marad. Egyes rendszereknél a magas szintű ütemező hiányozhat, vagy lehet egészen minimális is. Az időosztásos rendszereknél például a feladatokat általában közvetlenül a készenléti sorba lehet a terminálról bevinni, itt a multiprogramozás fokát csak a terminálok száma, illetve a bevitel sebessége korlátozza, a túlterhelés ellen nincs biztosíték. Ugyanakkor más operációs rendszerek -- különösen a virtuális tárral rendelkezők -- igényelnek egy harmadik, ún. közbenső szintű ütemezőt is. Ez tulajdonképpen a swapping technika (l. 3. és 10. fejezet) multiprogramozásos környezetben való megvalósítását támogatja. A különböző megfontolások (tárnyerés, a munkakeverék javítása stb.) alapján ideiglenesen eltávolított folyamatok visszajuttatása a várakozó sorba szintén a közbenső szintű ütemező feladata. A közbenső szintű ütemezővel a sordiagram a 9.5. ábrán látható módon alakul.
+-------------+ SWAP BE | RÉSZBEN | SWAP KI x-------------| VÉGREHAJTOTT|<------x | | FELADATOK | | | | SORA | | | +-------------+ | | KÖZBENSŐ SZINTŰ ÜTEMEZŐ | | | | | MAGAS | +------------+ ALACSONY -+SZINTŰ x--->| KÉSZENLÉTI | SZINTŰ / \ KÉSZ ------------>| SOR |------------->( CPU )-----> ÜTEMEZŐ x--->| | ÜTEMEZŐ \ / | +------------+ -+| | | | VÁRAKOZÁS | | | | | +----------+ | | *-----* | | | x--| B/K |<----| B/K SOR |<--------x *-----* | | +----------+ 9.5. ábra. A közbenső szintű ütemezés hatása A teljesség kedvéért megjegyezzük, hogy az alacsony szintű ütemezőről le szokták választani az ún. diszpécsert, amely a kiválasztott folyamatot ténylegesen aktivizálja. Ez konkrétan a regiszterek visszatöltését, a privilegizált állapotból normál állapotra való visszakapcsolást és egy megfelelő vezérlésátadás végrehajtását jelenti.
9.3. Ütemezési algoritmusok A következő munkának a készenléti sorból való kiválasztási algoritmusa nagymértékben befolyásolhatja az egész rendszer hatékonyságát. A feladat súlyának érzékeltetésére megpróbáljuk összefoglalni, hogy az ütemező algoritmustól általában milyen szempontok szerinti optimalizálást várnak el: * CPU kihasználtság, ami a gyakorlatban 40% és 95% között szokott lenni. * A rendszer átbocsátóképessége, amit például az óránként befejezett feladatok számával lehet mérni. * Fordulási idő, ami egy feladat leadása és befejezése között telik el. Ez különösen a felhasználó szempontjából fontos, de a B/K sebességtől erősen függ. * Várakozási idő, a fordulási idő egyik komponense, amit a feladat a készenléti sorban tölt. Az ütemező algoritmusok a fordulási időt tulajdonképpen csak a várakozási időn keresztül befolyásolják.
* Válaszidő, ami különösen interaktív rendszereknél fontos, ahol a fordulási idő nem megfelelő kritérium. Előfordulhat, hogy ha egy folyamat az eredmények egy részét már előállította, a többi eredmény meghatározását át lehet lapolni a meglévők közlésével. Így a felhasználót tulajdonképpen csak az első eredmény megjelenéséig eltelt idő -- a válaszidő -- érdekli. Természetesen egy-egy algoritmus a fentiek közül egyszerre csak egyet, vagy néhányat optimalizálhat. Jó esetben a többire sem ad az átlagosnál rosszabb értéket. Interaktív rendszernél például inkább a válaszidő szórását, mint átlagát célszerű minimalizálni, mert ekkor a rendszer viselkedése jobban tervezhető. 9.3.1. Előbb jött -- előbb fut A legegyszerűbb ütemezés, melyet angol rövidítéssel (First-Come-First-Served) FCFS-nek is neveznek. A központi egységet mindig az először igénylő folyamat kapja meg. Megvalósítása csupán egy FIFO (l. 10.7.1.) sort igényel, amelynek kezelése igen gyors lehet. Az algoritmus hatékonysága ugyanakkor meglehetősen rossz. A fordulási idő például erősen függ a feladatok megjelenésének sorrendjétől. Tekintsük például a következő három munkából álló esetet: Munka 1 2 3
CPU idő 30 5 5
Ebben a sorrendben a 3 feladat fordulási ideje 30, 35 és 40, tehát átlagosan 35 egység. Ha a feladatok sorrendje 2, 3, 1 lett volna, az átlagos fordulási idő (5+10+40)/3 = 18.3, vagyis alig több mint az előző fele. Az FCFS másik gyenge pontja az ún. csordahatás. Ha a feladatok között egy CPU orientált van, ez kisajátítja a központi egységet, a többi B/K orientált feladat pedig egy idő múlva mind a készenléti sorban vár, s a perifériák kihasználatlanok. Majd a B/K orientált feladatok végül megkapják ugyan a központi egységet, de gyorsan visszatérnek a B/K sorokba, és ezáltal a CPU lesz tétlen. A rendszer működését tehát az egyetlen nagy, CPU orientált feladat el tudja rontani. Úgy tűnik, érdemes a rövidebb feladatokat előre venni. 9.3.2. A legrövidebb előnyben Az algoritmus (angol rövidítése SJF = Shortest-Job-First), lényege, hogy a központi egységet felszabadulása után ahhoz a feladathoz rendeljük, amelynek következő CPU igénye a legkisebb. Ha több ilyen van, az FCFS algoritmus dönt. A 9.3.1. pontban szereplő példában is tulajdonképpen az SJF algoritmus eredményét vetettük össze az FCFS eredményével és láttuk, mennyivel jobb fordulási időt adott. Ezen túlmenően, kimutatható, hogy a legrövidebb előnyben elv optimális az átlagos fordulási idő szempontjából, mert ha egy rövidebb feladatot egy hosszabb elé viszünk a sorban, akkor a rövid feladat várakozási ideje nagyobb mértékben csökken, mint amennyivel nő a hosszabb feladaté, tehát az átlag csökken. Az SJF igazi problémája, hogy a készenléti sorban minden feladat mellett tárolni kell a következő CPU-igény hosszát is. A kötegelt rendszereknél a felhasználóktól kapott időkorlátok
alkalmazhatók: a programozók érdekeltté válnak a program futási idejének jó becslésében, mert alacsonyabb időkorláttal gyorsabban jutnak az eredményekhez, ha viszont túl optimistán becsülnek, a rendszer a feladatot időtúllépés miatt visszautasítja. Ezért az SJF különösen a kötegelt rendszereknél gyakori. Mivel azonban az algoritmus egyszerű és optimális, nem szívesen mondanak le róla ott sem, ahol nincs igazi magas szintű ütemezés (időosztásos rendszerek). Ilyen esetekben, ha ismerjük az előző igényt és az erre adott becslést, a matematikai statisztika segítségével meg lehet becsülni a következő CPU igény hosszát. A becslésre az ún. exponenciális átlagot szokták használni, ami egy alkalmasan választott w<1 esetén a következő: bn+1 = w*tn + (1-w)*bn, ahol tn az utolsó CPU igény hossza, bn az utolsó, bn+1 pedig a következő igény becslése. A w súly tulajdonképpen a jelen és a múlt hatásának figyelembevételét szabályozza. Az egyszerűség kedvéért a w-t általában 1/2-nek veszik, ami azt fejezi ki, hogy a jövő szempontjából a múlt és a jelen egyformán fontos. 9.3.3. Prioritás A prioritásos ütemezés az SJF algoritmus általánosítása, a készenléti sorban minden feladathoz egy egész számmal kifejezett, a feladat fontosságát jelző prioritást is tárolunk, a CPU-t minden esetben a legmagasabb prioritású feladat kapja (több ilyen esetén az FCFS elv dönt). Az SJF-nél a prioritás speciálisan a következő CPU-igény reciprok értéke volt. Általános megegyezés még abban sincs, hogy a nagyobb számok jelentik a magasabb prioritást (mint nálunk), vagy fordítva. A prioritás belülről vagy kívülről adható meg. A belső prioritást a feladat különböző paramétereiből (pl. SJF, vagy időhatárok, állományok száma, B/K igényesség, tárigény stb.) határozza meg a rendszer. A külső prioritást viszont a rendszeren kívül álló szempontok alapján adják meg. Ilyen lehet például a felhasználó privilégiuma, a magasabb díjtétel, a feladat objektív fontossága, üzletpolitika stb. Minden prioritásos ütemezés közös problémája az ún. kiéheztetés, ami azt jelenti, hogy egy kész állapotban lévő folyamat várakozási ideje nem korlátos. A folyamatosan érkező, nagyobb prioritású folyamatok egy alacsony prioritású munkát igen hosszú várakozásra kényszeríthetnek. A probléma megoldása nem bonyolult, be lehet vezetni az "öregedés" fogalmát például a készenléti sorban eltöltött idő alapján. Ha minden 5 perc várakozás után a feladatok prioritását eggyel növeljük, a legalacsonyabb prioritású feladat is belátható időn belül sorra kerül. Amint sorra kerül, prioritását vissza kell állítani a régi értékre. A VAX VMS, és az IBM OS/2 operációs rendszerekben pont ezt a módszert alkalmazzák. A prioritásos algoritmusok egy további finomítása lehet az ún. kizárás. Ez azt jelenti, hogy ha a várakozási sorba az éppen aktív folyamatnál nagyobb prioritású folyamat érkezik, akkor az kiszorítja az aktív folyamatot és megkapja a CPU-t. Az időosztásos rendszerekben, ha prioritásos ütemezést használnak, kizárásra feltétlenül szükség van, mert csak így biztosítható, hogy többékevésbé szabályos időközönként minden felhasználó hozzájusson a központi egységhez. Könnyen belátható, hogy az SJF (szintén prioritásos) algoritmus kizárással együtt rövidebb átlagos fordulási időt ad, mint a nélkül.
9.3.4. Körben járás Az időosztásos rendszerek számára tervezett körben járás (angol rövidítése RR = Round-Robin) lényege, hogy meghatároznak egy kis időtartamot, amit "időszelet-nek" neveznek. Értéke általában 10 és 100 ezredmásodperc között van. A készenléti sort egy zárt körnek tekintik, az alacsony szintű ütemező körben jár, és minden folyamat rendre megkapja a CPU-t az időszeletet meg nem haladó időtartamra. Az RR algoritmust legegyszerűbben egy FIFO sorral valósítják meg. Az érkező folyamatok a sor végére kerülnek, az ütemező veszi az első folyamatot, beállítja az időszelet alapján az óramegszakítást, és a folyamat indulhat. Ezután a folyamat vagy visszaadja a CPU-t önként (mert befejeződik, ill. B/K műveletbe kezd), vagy az időszelet lejártával bekövetkező megszakítás során az ütemező veszi el tőle, a folyamat pedig visszakerül a sor végére. A 9.6. ábrán az FCFS-nél adott példa ütemezése látható 6 egységnyi időszelettel: Feladat Időegység F1 30 F2 5 F3 5 +------+-----+-----+------+------+------+------+----+----+ | | | | | | | | | | | F1 | F2 | F3 | F1 | F1 | F1 | F1 | .. | .. | | |(5!) |(5!) | | | | | | | +------+-----+-----+------+------+------+------+----+----+ 0 6 11 16 22 28 34 40 .. 9.6. ábra. Időosztásos ütemezés Az átlagos fordulási idő (11+17+41)/3 = 23 egység. Figyeljük meg, hogy az 1. feladat akkor sem kap egyszerre az időszeletnél hosszabb CPU időt, amikor már egyedül maradt. Ilyenkor megszakítódik, majd a rendszer újra ütemezi. Ha a sorban N folyamat van, az időszelet pedig Q egység, mindegyik folyamat megkapja a CPU-t 1/N időre, ami legfeljebb Q nagyságú kvantumokból tevődik össze. A várakozási idő soha nem haladja meg az (N-1)*Q értéket. Az RR algoritmus hatékonysága erősen függ az időszelet nagyságától. Kis időszelet esetén "processzorosztás-ról" beszélünk, ekkor minden felhasználó úgy érzi, hogy saját processzora van, ami az igazi processzor sebességének 1/N szeresével működik. Ezt a megoldást alkalmazták a CDC 6600-nál a perifériaprocesszorok megvalósításánál. Egy fizikai processzorhoz 10 regiszterkészletet használtak. A hardver minden utasítás után átkapcsolt a következő regiszterkészletre. A felhasználó egy gyors helyett tíz lassú processzort látott, de ezek még elég gyorsak voltak a perifériák meghajtására. Az RR szoftver megoldásaival azonban egyéb problémák vannak. Az éppen aktív folyamat megszakításakor menteni kell, az új folyamat indításakor pedig be kell tölteni a regisztereket. Ezt a két tevékenységet együttesen környezetváltásnak nevezzük, időtartama gépenként változik, de általában eléri az időszelet 10%-át. A környezetváltás teljes egészében kieső idő, és komoly mértékben befolyásolja az ütemező hatékonyságát, hiszen -- az időszelet tizedével számolva -- a CPU idejének 10%-át kell környezetváltásra fordítani. Ezért az látszik célszerűnek, ha az időszelet jóval nagyobb, mint a környezetváltás ideje, mert akkor egy adott feladathalmaz esetében csökken a környezetváltások száma és esetleg az átlagos fordulási idő is. Ugyanakkor az időszelet növelésével az RR algoritmus FCFS-sé degradálódik, ami nyilván nem kívánatos. Általánosan bevált becslés szerint az időszeletet úgy kell megválasztani, hogy a CPU igények nagy része (mintegy 80%-a) egy időszelet alatt kielégíthető legyen.
9.3.5. Többsoros ütemezés Különösen nagyobb számítógépes rendszerek esetén gyakran előfordul, hogy a munkák könnyen két vagy több csoportra oszthatók. Például az ún. előtérben futó interaktív és a háttérben futó kötegelt munkák szétválasztása azért kézenfekvő, mert a válaszidő-követelmények eltérőek, és ezért különböző ütemezést igényelnek. Ezen túlmenően az előtérmunkákhoz sokszor nagyobb külső prioritás is tartozik. A több sorral dolgozó ütemező a készenléti sort több, különálló sorra osztja. Az érkező munkák valamilyen tulajdonságuk alapján kerülnek be valamelyik sorba, besorolásuk később már nem változhat. Minden sorhoz saját, az adott feladattípusnak megfelelő ütemező algoritmus tartozhat. Több sor esetén természetesen a sorok közötti választást is ütemezni kell, amit általában rögzített prioritással, kizárásos alapon oldanak meg. Példaként egy OS/MFT rendszer 5 készenléti sorát adjuk meg: * * * * *
operációs rendszerbeli munkák interaktív programok interaktív szerkesztés kötegelt munkák a tanulók feladatai
A felsorolás a rögzített prioritási sorrendet mutatja. Egy alacsonyabb prioritású sorban lévő feladat csak akkor futhatott, ha az összes magasabb prioritású sor üres volt. A sorok közötti ütemezés időszeletek kiosztásával is megoldható. Az időszeleten belül az egyes sorok a saját algoritmusuk (pl. az interaktívak RR, a kötegeltek FCFS) alapján ütemezik a munkákat. Ha a különböző sorokba való beosztást nem a munkák külső ismérvei alapján végezzük, hanem a rendszerre bízzuk azzal a céllal, hogy a különböző CPU igényű munkák külön sorokba kerüljenek, feladhatjuk a besorolás állandóságának elvét és eljutunk az ún. visszacsatolásos többszintű sorokhoz. Az alapelv az, hogy ha egy folyamat túl sok CPU időt használ, átkerül egy alacsonyabb prioritású sorba, illetve ha egy feladat túl sokat vár egy sorban, magasabb prioritású sorba juttatják. Példaképpen tekintsünk meg három , 0-tól 2-ig számozott sorból álló visszacsatolásos algoritmust. Az ütemező először a 0. sorban levő munkákat intézi el. Ha ez a sor üres, csak akkor következik az 1., illetve ez után a 2. sor. Ha időközben egy folyamat kerül az 1. sorba, ez kizárja a 2. sor ütemezését. Hasonló módon, egy munka megjelenése a 0. sorban felfüggeszti az 1. sor kiszolgálását. Az újonnan érkező munkák a 0. sorba kerülnek és kapnak 8 egységnyi időszeletet. Ha a folyamat ennyi idő alatt nem fejeződik be, átkerül az 1. sor végére, ahol a megfelelő időben (pl. RR algoritmussal) kap egy 16 egységnyi időszeletet. Ha még ez sem lenne elég, a folyamat a 2. sorba kerül, ahol az FCFS algoritmus alapján csak akkor juthat egyáltalán szóhoz, ha a 0. és 1. sor egyaránt üres (l. 9.7. ábra).
+--------------------------+ SIKERÜLT -----> |0. IDŐSZELET = 8 | -------> +--------------------------+\ ) ÁTADÁS / -------------------------------/ ( \ +--------------------------+ SIKERÜLT ---> |1. IDŐSZELET = 16 | -------> +--------------------------+\ ) ÁTADÁS / -------------------------------/ ( \ +--------------------------+ SIKERÜLT ---> |2. FCFS | -------> +--------------------------+ 9.7. ábra. Többsoros ütemezés Ez az algoritmus a legnagyobb prioritást a 8 egységnél nem hosszabb CPU igényű folyamatoknak adja. A 9 és 24 egység közötti munkák közepes prioritást kapnak, míg az ennél hosszabbakat az ütemező mostohán kezeli. A példa alapján általánosíthatjuk a többsoros visszacsatolásos ütemezés jellemzőit: * * * *
a sorok száma, az egyes sorok ütemező algoritmusa, a munkák sorok közötti mozgatásának feltételei, az új munkák helyének meghatározása.
A többsoros visszacsatolásos ütemezés tekinthető a processzor-kezelés legfejlettebb megoldásának. Segítségével az operációs rendszer úgy hangolható, hogy jól megfeleljen szinte bármilyen működési környezet által támasztott igényeknek. Ugyanakkor az is igaz, hogy ez a legösszetettebb ütemezés, amely csak nagy teljesítményű hardver és megfelelően heterogén terhelés esetén lehet gazdaságos. Ennek ellenére az OS/2 személyi számítógépes operációs rendszerben is hasonló alapelveket valósítanak meg, és más, kis teljesítményű hardverekre kidolgozott, multiprogramozott operációs rendszerek is igyekeznek ilyen megoldásokat használni.
9.4. Értékelési módszerek A megfelelő ütemezési algoritmus kiválasztása összetett feladat. Mint az előzőekből láttuk, a választék elég nagy, sokféle szempont alapján lehet dönteni, ezért célszerű erre irányuló tevékenységünket rendszerezni. Az első tennivaló az algoritmussal szemben támasztott igények rögzítése. Ezeket a 9.3. pont alapján általában három feltétel köré csoportosítják: a CPU kihasználtsága, a válaszidő és a rendszer átbocsátóképessége. Egy algoritmus értékelése előtt el kell döntenünk ezek egymáshoz viszonyított fontosságát.
Például a következő igények fogalmazhatók meg: * maximális CPU-kihasználás adott válaszidő korlát mellett, * maximális átbocsátóképesség, azzal a megszorítással, hogy az átlagos fordulási idő a munkák futási idejével egyenes arányban álljon. Ha a választási feltételeket már tisztáztuk, a szóba jöhető algoritmusokról el lehet dönteni, hogy megfelelőek-e. Az értékelés alapvetően háromféle módón hajtható végre: analitikusan, szimulációval és gyakorlati úton. Az analitikus értékelés legegyszerűbb formája az ún. determinisztikus modellezés. Rögzítünk egy munkahalmazt és minden algoritmust ennek segítségével értékelünk. Tegyük fel, hogy a következő 5 munkát kell végrehajtani, melyek egyszerre érkeztek a rendszerbe: Munka
CPU igény
1 2 3 4 5
10 29 3 7 12
Vessük össze az Előbb jött-előbb fut, a Legrövidebb előnyben és a Körben járás algoritmust az átlagos várakozási idő szempontjából! Az FCFS algoritmusnál a munkák a felsorolási sorrendben hajtódnak végre: Munka
Várakozás
1 2 3 4 5
0 10 39 42 49 ---140
Az átlagos várakozási idő tehát 140/5=28 Az egyszerű (nem kizárásos) SJF algoritmus szerint a munkák sorrendje és a várakozási idők a következőképpen alakulnak: Munka
Várakozás
3 4 1 5 2
Most az átlagos várakozási idő csak 65/5=13 egység.
0 3 10 20 32 ---65
Az RR algoritmusnál válasszuk az időszeletet 10 egységnek. A hosszabb munkák több időszeletet igényelnek, a végrehajtás sorrendje és a várakozási idők a következők: Munka 1 2 3 4 5 2 5 2
Várakozás 0 10 20 23 30 20 10 2 ----115
Az átlagos várakozás itt 115/5=23 egység. A determinisztikus modellezés szerint tehát ebben az esetben az SJF algoritmus az átlagos várakozási idő szempontjából messzemenően a legjobb. Az értékelési módszer gyors és egyszerű, bár, ha megbízható eredményt akarunk, természetesen nem elegendő egy modellt felállítani, hanem csak több esetből lehet általános következtetésekre jutni. Kimutatható például, hogy a fenti környezetben (amikor az összes munka és CPU igény ismert az induláskor) az SFJ algoritmus minimalizálja az átlagos várakozási időt. A determinisztikus modellek közös hibája, hogy a valóságban állandóan változó a terhelés, amit statikus mintákkal nem lehet jól közelíteni. Vannak azonban az ütemezésben más, meghatározható paraméterek is. Ilyen például a CPU és a B/K igények eloszlása. Ezek megfelelő mintavétel után különböző eljárásokkal a matematikai statisztika segítségével megbecsülhetők. Az egyik alapfeladat például egy adott hosszúságú CPU igény valószínűségének meghatározása lehet, ami általános esetben exponenciális eloszlású. Ha emellett még az érkező munkák eloszlásáról is tudunk valamit, akkor a legtöbb algoritmushoz meghatározható az átlagos átbocsátóképesség, a CPU kihasználtság, az átlagos várakozási idő stb. Maga a számítógép-rendszer felfogható szolgáltatók hálózataként is. Minden szolgáltatóhoz (CPU, perifériák stb.) egy várakozási sor tartozik. Ha ismerjük az érkezési és a kiszolgálási ütemet, kiszámítható a kihasználtság, az átlagos sorhossz és a várakozási idő. Ezt nevezik "sor--hálózat analízis"-nek. Ha például a sor átlagos hossza L, az átlagos várakozási idő T és a munkák átlagos érkezési üteme C (munka/másodperc), akkor a rendszer egyensúlyi állapotához az érkező és a kilépő munkák számának meg kell egyeznie. Tehát: L = C * T Ez az összefüggés az ún. Little-formula, melynek nagy előnye, hogy független az ütemezési algorimusoktól és a munkák érkezésének eloszlásától. Segítségével bármely benne szereplő két mennyiség ismeretében meghatározható a harmadik. A sorban állási modell analízise a néha bonyolult matematikai apparátus igénye miatt jelenleg csak néhány algoritmusra és eloszlásra szorítkozik. Az egyszerűsítés érdekében bevezetett közelítések viszont sok esetben a megbízhatóság rovására mennek. Az ütemező algoritmusok kiértékelésében pontosabb eredmény várható a szimulációtól, ami a
számítógépes rendszer programozott modellje. Szoftver úton reprezentálják a fontosabb komponenseket: az órát, a rendszer állapotát, a B/K egységek munkáját, a munkákat és az ütemezőt. A szimuláció folyamán az algoritmus teljesítményét kifejező statisztikák készülnek. A szimulációhoz szükséges adatokat általában véletlenszám-generátorokkal állítják elő, amelyek a munkákat, a CPU igényeket, az érkezési és kilépési ütemet stb. az előírt eloszlásoknak megfelelően produkálják. Az eloszlásokat nem csak matematikailag, hanem empirikusan is meg lehet adni. A legjobb szimulációs adatanyag a valós rendszerek működésének részletes naplózásából (pl. mágnesszalagra való rögzítéséből) nyerhető. A napló valóságon alapuló adatainak segítségével vizsgálandó algoritmusok tényleg reális alapon vethetők össze. A szimuláció igen megbízható , de nagyon költséges. Nemcsak komoly szoftverfejlesztést, hanem sok gépidőt is igényel. Teljesen megbízható eredmény tulajdonképpen csak a gyakorlattól várható. Meg kell írni az ütemező algoritmust megvalósító programot, és élesben kipróbálva elvégezni az értékelést. Az ilyen megközelítés természetesen igen költséges. Nemcsak a programozási munka, hanem a teljes számítógéprendszer folyamatos termelésből való kivonása az ár, hiszen a felhasználóktól nem várható el, hogy egy állandóan változó operációs rendszerrel dolgozzanak. Ha mégis megoldjuk ezt a kérdést, a következő problémát a működési környezet állandó változása jelenti. A programozók nemcsak új programokat írnak, hanem alkalmazkodnak is az ütemező sajátságaihoz. Ha például a rendszer automatikusan osztályozza az interaktív és egyéb munkákat, mondjuk úgy, hogy ha egy folyamat nem ír, vagy olvas a terminálról egy másodpercig, akkor nem interaktív, érdemes lesz a programokba egy felesleges képernyőre írást tenni, hogy a program a magas prioritású, interaktív csoportban maradhasson. A programozók programozási stílusa egyébként is sokkal döntőbb lehet az ütemezési algoritmusok hatékonyságára, mint bármilyen trükkös optimalizálási törekvés.
9.5. Gyakorlatok 9.5.1.
Mi a különbség az alacsony, a közbenső és a magas szintű ütemezők között?
9.5.2.
Milyen rendszerekből szokott hiányozni a magas szintű ütemező?
9.5.3.
Melyek az ütemezők legfontosabb értékelési szempontjai?
9.5.4.
Mit nevezünk egy rendszer átbocsátó képességének?
9.5.5.
Jellemezze egy folyamat különböző állapotait!
9.5.6.
Mit nevezünk készenléti sornak?
9.5.7.
Mi az FCFS algoritmus gyenge pontja?
9.5.8.
Mi a többszintű ütemezés lényege?
9.5.9.
Az alábbi ütemező algoritmusok közül melyek valók elsősorban magas- és melyek alacsony szintű ütemezésre? a) b) c) d)
9.5.10.
FCFS RR SJF magasabb prioritású előbb fut
Tegyük fel, hogy a következő munkák a felsorolásuk sorrendjében érkeznek: Munka 1 2 3 4 5
CPU-igény 10 1 2 1 5
Prioritás 3 1 3 4 2
Tekintsük a következő algoritmusokat: FCFS, RR (időszelet=1), SJF, kizárás nélküli prioritásos. a) Mennyi az egyes munkák fordulási ideje a fenti algoritmusok mellett? b) Mennyi az egyes munkák várakozási ideje a fenti algoritmusok mellett? c) Melyik algoritmusnál legkisebb az átlagos várakozási idő? 9.5.11.
Mi az eltérés a kizárásos és a nem kizárásos ütemezés között?
9.5.12.
Mi a folyamatvezérlő blokk (PCB) szerepe és felépítése?
9.5.13.
Tekintsünk egy körben járásos ütemezést, melynél a készenléti sorban PCB-kre irányuló mutatók vannak. a) Milyen hatást vált ki, ha két mutató ugyanarra a PCB-re mutat? b) Mi e megoldás előnye és hátránya ? c) Hogyan lehetne ugyanezt a hatást az RR algoritmus módosításával duplikált mutatók nélkül is elérni?
OS10V07.RTF,ZSP,2000-04-23, végleges
10. TÁRKEZELÉS
A tárolóegységek vagy tárak igen fontos szerepet játszanak minden számítógépes rendszer működésében. Ezért az erőforrások kezelésében a tárolóegységekkel való gazdálkodás körülbelül a processzor-kezeléssel egyforma súlyt képvisel. Táron most a gép belső vagy operatív tárolóját értjük, bár -- mint látni fogjuk -- a külső tároló egységek szintén kulcspozíciót töltenek be a tárkezelésben. Ebben a fejezetben a fejlődés sorrendjében tekintjük át a különböző szintű tárkezelési módszereket.
10.1. Abszolút címzésű rendszerek Az egyszerű, egyfelhasználós számítógép-rendszereknél a tárat két részre osztották. Az egyiket a felhasználó kapta, a másikat az operációs rendszer rezidens része (ami lényegében egy betöltő programból állt) használta. A programok és a tárcímek közötti kapcsolatot már a program írásakor rögzítették, azaz a program csak a tár -- abszolút címekkel megadott -- egy bizonyos területén volt működőképes. Az utasítások közvetlenül címezhették a teljes tárat, így a tárkezelésre igen kevés feladat jutott. Ilyen volt például az operációs rendszer területének védelme. E célra egy határregiszter szolgált, amely az operációs rendszer által elfoglalt legnagyobb, vagy legkisebb címet tartalmazta annak megfelelően, hogy a rendszer a tár alsó, vagy felső részén helyezkedett el. A privilegizált módban futó operációs rendszer a teljes tárhoz (a felhasználó területéhez is) hozzáfért, a felhasználó programjaiban azonban minden generált címet ellenőrizni kellett, hogy nem sérti-e a határregiszter által kijelölt rendszerterületet. Arra számítva, hogy az operációs rendszer mérete az idők folyamán változik (rendszerint növekszik), a határregiszter tartalmát egy, természetesen privilegizált, utasítással lehetett módosítani.
10.2. Áthelyezhető címzésű rendszerek Az abszolút címzés igen sok gépies munkát rótt a programozókra, ezért a programozási nyelvek elterjedésekor gyorsan feledésbe is merült. Helyét átadta a legegyszerűbb áthelyezhető címzésnek, amit relatív címzésnek is neveznek. Ennek lényege, hogy a fordítóprogram például 0-tól kezdődő relatív címet állít elő, a végleges címek kialakítását pedig a tárgyprogram betöltéséig késleltetjük. Ekkor a betöltő egy alkalmas érték hozzáadásával kialakítja az abszolút címeket. A megoldás előnye, hogy ha változik a határcím, a programot elegendő csak újratölteni, fordítani nem kell. A fejlődés következő szintjét a tranziens résszel rendelkező operációs rendszerek képviselték,
amikor a rendszer által elfoglalt tár a felhasználói program futása során is változhatott, mivel a ritkán használt szolgáltatásokat nem volt célszerű állandóan -- az akkor még viszonylag szűkös méretű -- tárban tartani. A legegyszerűbb megoldást egy régi PDP-11 rendszerben találhatjuk meg, ahol az operációs rendszer a tár elején a növekvő címek szerint foglalt helyet, míg a felhasználó programját a tár tetejétől lefelé töltötték be. A kettő közötti szabad területet akár a rendszer, akár a felhasználó elfoglalhatta. Általános megoldás a CDC 6600-as gépekre készült, ahol a címszámítást egészen a végrehajtás pillanatáig késleltették. Ezt dinamikus áthelyezésnek nevezik, és némi hardvertámogatást igényel. A 10.1. ábrán láthatjuk, hogy a határregiszter szerepét a relokációs bázisregiszter veszi át, amelynek tartalma hozzáadódik a futó program relatív címeihez. .------. +--------------+ BÁZISREGISZTER |
(
2000
0 )
|
*---|--*
|
| |BÁZIS- .............b>|--+- BÁZIS | |CÍM
|
|
| ---
(b)
| d|ELTOLÁS
| /
\
LOGIKAI CÍM
|
FIZIKAI CÍM
|
|
| ( CPU )-------(d)--------->(+)-------------------->|--+| \
/
0518
VÉGCÍM-
2518
|
(ELTOLÁS)
SZÁMÍTÁS
(VÉGCÍM)
|
| ---
TÁR
| (b+d)
|
| | | | | | | MAX +--------------+ 10.1. ábra. Dinamikus relokálás relokációs regiszterrel A felhasználó nem is látja a fizikai címeket, minden műveletét logikai (relatív) címekkel végzi. Ekkor, ha változik a relokációs regiszter tartalma, a felhasználó teljes területét egyszerűen átmásolható a kijelölt részre, a futó program kódja változatlan. E régóta alkalmazott megoldás lényege -- a logikai címek fogalma, melyeket az operációs rendszer fizikai címekre képez le -minden modern tárkezelő rendszer alapja.
10.3. Particionált rendszerek +----------+ |
|
.------------------------. (
) | | | *------------------------*| | | | | | | | +--------------+ | | | SWAP (KI) | | | | | >------------------------------>| 1. PROGRAM | | | | 1 | | | | | | | +--------------+ | | | | | | | | +-------------+ | | | SWAP (BE) | | | | | <--------------------------------<| 2. PROGRAM | | | | 2 | | | | | | | +-------------+ | +-----------+ | | | | | | | MONITOR | ( ) | | *------------------------* +-----------+ HÁTTÉRTÁR KÖZPONTI TÁR 10.2. ábra. Multiprogramozás helycserével (swapping) A tárkezelés -- a multiprogramozás miatt, -- természetszerűleg a tár több felhasználó közötti megosztásának irányába fejlődött tovább. Ehhez a logikai és fizikai címek fogalmán kívül arra is szükség volt, hogy a tárkezelés háttértárakra is támaszkodhasson. Mivel viszonylag gyors, cím szerint írható -- olvasható háttértárra van szükség, eleinte mágnesdobok, később (és jelenleg is) főleg mágneslemezek jöhettek csak szóba. Az első gyakorlati megoldást az ún. swapping (helycsere) jelentette, amely először egy rezidens operációs rendszerrel és határregiszterrel felszerelt hardveren működött időosztásos alapon.
A swapping lényege, hogy a felhasználói részt mindig egy felhasználó uralja, a többiek teljes tárterülete a háttértáron várakozik. Felhasználócserénél a rendszer kimásolja a régi-, és behozza az új felhasználó "tárképét". A helycsere ideje a kivitt, illetve behozott terület méretétől függ, ezért a swapping felvetette a programok tárigényének dinamikus kezelését. A rendszer sokkal hatékonyabban működött, ha csak a folyamatok által ténylegesen lefoglalt területeket cserélgette, nem pedig mindig a teljes felhasználói tárrészt. Ekkor alakultak ki a tárfoglalásra, illetve felszabadításra szolgáló rendszerhívások. A swapping hatásfokát tovább lehetett növelni azzal, hogy az egyik folyamat beolvasását átfedjük a másik folyamat végrehajtásával. A megvalósítást a 10.3. ábra mutatja. Két pufferterület segítségével egy program végrehajtása közben az előző programot kivisszük, a következő programot pedig behozzuk a megfelelő pufferbe.
.--------------------. +-------------------+
(
) | | | *---------------------*| | | | | | AKTÍV FELHASZNÁLÓ | | SWAP | | | | ZÓNA | | | | | *===================* | | M | | | +-------+ | O | | | | | | N | 2. PUFFERZÓNA <-------------------------| | | I | | | | | | T | | | +-------+ | O +-------------------+ | | R | | | +-------+ | | | | | | | T | 1. PUFFERZÓNA ------------------------->| | | E | | | | | | R | | | +-------+ | Ü +-------------------+ | | L | | | | E | MONITOR | | | T | | ( ) +-------------------+ *---------------------* OPERATÍV TÁR HÁTTÉRTÁR
10.3. ábra. Swapping pufferezéssel Az új folyamat aktivizálása előtt végre kell hajtani még egy táron belüli helycserét a megfelelő puffer és a felhasználói terület között. A swapping technika egyik komoly hátránya, hogy a csere csak passzív folyamatokkal hajtható végre. A B/K műveletek esetében azonban megtörténhet, hogy az operációs rendszer több aszinkron lépésben fordul a felhasználó területén lévő pufferekhez, tehát a folyamat passzív volta nem egyértelmű. Két ilyen művelet közötti swapping ugyanis mindkét folyamatra számára "végzetes" lehet. A megoldás mindenképpen a B/K tevékenység megszorítását jelenti: vagy megtiltjuk a swappingot a teljes B/K művelet alatt, vagy B/K műveletet csak az operációs rendszer puffereivel lehet végezni, amit egy későbbi belső adatátvitel követ. Talán ez volt az oka annak, hogy a swapping átfedéses változatából kialakult a multiprogramozásnál általánosan elterjedt technika: egyszerre több programot kell a tárban tartani. A többpartíciós rendszerekben a tár szabad területét több részre (partícióra) osztják és minden partícióban egy-egy felhasználó programja tartózkodhat végrehajtásra várakozva. A központi egység igen gyorsan vált át egyik folyamatról a másikra, a tárkezelés feladata, hogy a munkasorban várakozó munkákból folyamatosan feltöltse a partíciókat futásra kész programokkal. A multiprogramozás fokát a partíciók száma szabja meg; ha egy partíció felszabadul, az operációs rendszer kiválaszt és betölt egy munkát a várakozó sorból. A particionálás kétféle módon oldható meg: statikusan vagy dinamikusan. A statikus megoldásban rögzített méretű partíciók szerepelnek, szemben a másik megoldás változó méretű partícióival. A két változatot az IBM MFT, illetve MVT néven vezette be (a Multiprogramozás Fix, ill. Változó számú Feladattal kifejezések rövidítése), melyek általánosan elterjedt elnevezéssé váltak. 10.3.1. Rögzített partíciók (MFT) A felosztás során a különböző méretű munkák számára kis, közepes és nagy partíciókat rögzítenek. A rendszerbe lépő feladatok egy sorba kerülnek, a munkaütemező pedig nyilvántartásba veszi minden munka tárigényét. Ha egy soron következő munka számára szabaddá válik egy méretben megfelelő partíció, a program betöltődik (esetleges relokációval) és most már a központi egységért versenyez. Minden befejeződött munkával felszabadul egy partíció, amelyet a sorból újra fel lehet tölteni. Az algoritmushoz tartozó tárvédelmet a 10.8. pontban tárgyaljuk. A sor kezelésére többféle lehetőség van. Az egyik megoldás szerint minden partícióhoz külön sort szervezünk, és minden munkát a méretét felülről legjobban megközelítő sorba irányítunk. Ehhez ismerni kell a munka tárigényét, amit vagy a programozó ad meg, vagy a rendszer egy külön fázisban automatikusan meghatározhat a munkavezérlő programból. A másik megoldás egyetlen sort használ, és abból próbálja optimálisan feltölteni a rendelkezésre álló partíciókat, ami szintén többféle algoritmussal mehet végbe. A legegyszerűbb az "előbb jöttelőbb fut" elv, ami esetleg rossz tárkihasználást eredményez. Ezen igyekszik segíteni az "első lehetséges fut" (ami oda vezethet, hogy nagy partíciót kis munka foglal le), illetve a "legjobban illeszkedő fut" (ami sok, közel egyforma méretű munka esetén mond csődöt) elv. Az MFT algoritmust swappinggal együtt is szokták alkalmazni, ami sok, azonos méretű munka esetén lehet előnyös, mert az egy partícióra várakozó munkák közül adott idő alatt több is "szóhoz juthat". Az ilyen környezetben működő swapping-ot "roll-in/roll-out"-nak (ki/be görgetésnek) is nevezik. A rögzített méretű partíciókkal óhatatlanul együtt jár a tár ún. elaprózódása. Bármilyen gondosan
határozzuk meg a partíciók méretét, előfordulhat, hogy egy munka a méreténél jóval nagyobb partíciót köt le (ez a belső elaprózódás). Az is megtörténhet, hogy egy partíció kihasználatlanul áll, mert nem elég nagy egyik várakozó munka számára sem (külső elaprózódás). Mivel az MFT-ben a partíciók méretének bármilyen változtatásával csak azt lehet elérni, hogy módosuljon a belső és külső elaprózódás aránya, használható megoldást csak a változó méretű partíciók hozhattak. 10.3.2. Változó partíciók (MVT) A tárkezelés itt igen egyszerű: az operációs rendszer nyilvántartja, hogy a tár mely részei szabadok, illetve foglaltak. Amikor egy munka érkezik, megkeresi a számára elegendően nagy szabad területet ("lyukat") és abból lefoglal annyit, amennyit a munka igényel (l. 3.5. ábra). Ha "előbb jött-előbb fut" alapon lejátszanánk a fenti ábrán látható munkasor végrehajtását, azt tapasztalnánk, hogy körben járásos módszerrel -- egy egységnyi időszelettel számolva -- a tárban hamarosan több, 10-20K nagyságrendű lyuk jön létre, azaz a külső elaprózódás még mindig jelentős, bár a belsőt már kiküszöböltük. Ez ellen első közelítésben újra az "első lehetséges fut", illetve a "legjobban illeszkedő fut" módszerével igyekeztek (nem mindig eredményesen) védekezni. A teljesen használhatatlan, néhány bájtos lyukak kialakulása ellen (melyek nyilvántartása rontja a rendszer hatásfokát) úgy lehet védekezni, hogy a tárat nem bájtonként, hanem nagyobb, 16, 256 vagy akár, mint az IBM tette, 2048 bájtos egységekben osztják ki, amivel természetesen újra megjelenik (ha korlátozott formában is) a belső elaprózódás. Ha már kiválasztottuk, hogy melyik munka kerüljön a tárba, a programok futtatása ugyanazt a hardvertámogatást igényli a tárvédelemhez (l. 10.8.), mint az MFT algoritmusnál, tehát a két módszer egymástól tulajdonképpen csak szoftver szempontból különbözik.
10.4. Tömörítés Az MVT-nél a külső elaprózódás egyik hatékony megoldása a tár rendszeres időközönkénti "átrendezése" azért, hogy a kis -- önmagukban használhatatlan -- darabokból egy folytonos területet képezzünk. Ezt a hívjuk tömörítésnek, vagy a programozási nyelvek futtató rendszereitől átvett kifejezéssel "szemétgyűjtésnek". A tömörítés csak akkor végezhető el, ha a rendszer megengedi a dinamikus relokációt.
256 K +-------------------+
256 K +-------------------
+ | / / / / / / / / / |
| / / / / / / / / /
| |/ / / / 45 K / / /| |/ / / / / / / / / /| 210 K +-------------------+ | | | K / / /| | 3. | | | FELADAT | |/ / / / / / / / / /| | | + 150 K +-------------------+ | |/ / / / 20 K / / /| | 130 K +-------------------+ | | 2. | | | FELADAT | + 100 K +-------------------+ | |/ / / / 10 K / / /| | 90 K +-------------------+ + | 1. | | | FELADAT | | 40 K +-------------------+ + | | | | MONITOR | | | | | 0 K +-------------------+ +
| / / / / / / / / / |/ / / / 75 | / / / / / / / / /
180 K +------------------| | | ======>
3. FELADAT
| 120 K +------------------| |
2. FELADAT
90 K +------------------| |
1. FELADAT
40 K +------------------| |
MONITOR
| 0 K +-------------------
10.4. ábra. Tömörítés Ebben az esetben csak át kell másolni a program- és az adatterület tartalmát, és be kell írni a bázisregiszter új értékét. A 10.4. ábra is mutatja, hogy a tömörítés jól használható, bár itt is érdemes költségszámítást végezni. Könnyen belátható, hogy ha csak egyszerűen minden programot
a tár eleje felé mozgatunk, meglehetősen rosszul járunk, hiszen lehet, hogy elég lett volna csupán egy programot átmásolni (esetleg ellenkező irányba), hogy a sorban következő munka számára elegendően nagy lyukat hozzunk létre valahol. A tömörítést tehát célszerű a sorban álló munkák paramétereinek figyelembevételével szervezni. A minden munka befejezése után rendszeres tömörítést végző operációs rendszerek egyik példája a CDC 6600 SCOPE rendszere, ahol egyidejűleg 8 munka lehetett a tárban. A swapping természetesen a tömörítéssel is kombinálható. Ilyenkor a kimentett munkát (dinamikus relokáció esetén) általában a tár más helyére hozza vissza a rendszer, vagy éppen a tömörítésnél mozgatásra ítélt munkákat menti ki.
10.5. Lapozás és szegmentálás A külső elaprózódás leküzdésének másik, a tömörítésnél is jobb megoldása, hogy feladjuk az egy munkára kiosztott tárterület folytonosságának elvét. A munkához több, a tárban szétszórtan elhelyezkedő blokk tartozik. Az operációs rendszer gondoskodik arról, hogy futás közben szükség esetén a vezérlés az egyik blokkból a másikba kerüljön. A blokkokat lapoknak, a módszert pedig lapkezelésnek vagy lapozásnak nevezik. +----------+ L 0.| | +-----------+ LAPTÁBLA A +-----------+ | 0.LAP | P KERET P 1.| 0.LAP | +-----------+ +---+-----+ K +-----------+ | 1.LAP | L | 0 | 1 | E 2.| | +-----------+ A +---+-----+ R +-----------+ | 2.LAP | P | 1 | 4 | E 3.| 2.LAP | +-----------+ I +---+-----+ T +-----------+ | 3.LAP | N | 2 | 3 | S 4.| 1.LAP | +-----------+ D +---+-----+ Z +-----------+ | 4.LAP | E | 3 | 6 | Á 5.| 4.LAP | +-----------+ X +---+-----+ M +-----------+ LOGIKAI TÁR | 4 | 5 | O 6.| 3.LAP | +---+-----+ K +-----------+ FIZIKAI TÁR 10.5. ábra. Logikai lapok, laptábla és fizikai lapkeretek
A lapkezeléshez szükséges hardvert a 3.6. ábrán mutattuk be. Minden, a központi egység által generált címet két részre bontunk: egy lapcímre (p) és egy lapon belüli relatív címre (d). A lapcím adja a laptábla indexét, ahol minden laphoz megtalálható annak fizikai (bázis) címe (f). Bármelyik lapon belüli fizikai cím tehát f+d. A logikai és a fizikai cím közötti leképezés modelljét mutatja a 10.5. ábra. A logikai tárat azonos nagyságú lapokra, a fizikai tárat pedig ugyanekkora részekre, ún. keretekre osztjuk. A programot végrehajtás előtt betöltjük az éppen szabad keretekbe, majd a laptáblát úgy állítjuk be, hogy a lapok és keretek aktuális megfeleltetését fejezze ki. A lapméret hardver paraméter, a gyakorlatban 1 Kbájttól, vagy szótól 4K-ig terjed. (Az IBM 370-nél 2K vagy 4K, a PDP-10-nél 512 szó). Általában, ha a lapméret P, akkor az L logikai címhez tartozó lapilletve relatív cím: p = L div P d = L mod P A lapméretet azért szokás kettőhatványnak választani, mert így a fenti műveletek a bináris címen igen egyszerűen elvégezhetők: a megfelelő számú felső bit adja p-t, az alsó bitek pedig d-t. A munkák ütemezése természetesen alkalmazkodik a lapozáshoz. A munka méretét lapokban kell kifejezni. Ha az ütemező úgy találja, hogy rendelkezik a munka által igényelt számú kerettel, akkor ezeket lefoglalja, a munkát laponként betölti a keretekbe, és minden lap betöltése után a keret sorszámát beírja a laptábla megfelelő rovatába. Minden feladathoz külön laptábla tartozik, melyet a regiszterek tartalmával együtt az ütemező a munkavezérlő blokkban tárol. Lapozásnál külső elaprózódás nincs, de fellép egy -- munkánként várhatóan féllapnyi -- belső veszteség, hiszen a munkák mérete általában nem egész számú többszöröse a laphossznak. A laptábla tisztán szoftver megvalósítása meglehetősen lelassította volna a rendszert, ezért többféle -- hardverrel támogatott -- megoldást alkalmaztak. Eleinte, amikor a logikai tár csak néhány tucat, vagy néhány száz lapból állt, a laptáblát külön regiszterkészlettel oldották meg, ami laponként egy regisztert jelentett (PDP-11). A lapregiszterek tartalmát természetesen csak az operációs rendszer módosíthatta. A regiszterek a címtranszformációt igen gyorssá tették. Amikor azonban a tár mérete nőtt (az IBM 370-nél már 4096 lap is lehetett), a laptáblát kénytelenek voltak a tárban tartani és bevezetni az ún. laptábla--bázisregisztert (angol rövidítése: PTBR), amely mindig az aktuális laptáblára mutatott. Ennek segítségével a laptáblák váltása viszonylag gyors volt, a logikai -- fizikai címtranszformáció azonban legalább két tárhoz fordulást igényelt, ami sok esetben elfogadhatatlan sebességcsökkenéshez vezetett.
+--------+ +------------+ | E1 | | +--------+ +------------+ | E2 | | +--------+ +------------+ | E3 | | +--------+ +------------+ | ADAT-1 | | +--------+ +------------+ 1.FELADAT |
1 +---+ . | 3 |
0.|
L +---+ A | 4 |
1.|
ADAT-1
2.|
ADAT-3
3.|
E1
4.|
E2
P +---+ T | 6 | Á +---+ B | 1 | L +---+
+--------+
2 +---+
A
|
|
. | 3!|
+--------+
L +---+
|
|
A | 4!|
+--------+
P +---+
|
|
T | 6!|
+--------+
Á +---+
| ADAT-2 |
B | 7 |
3 +---+
+--------+
L +---+
. | 3!|
3.FELADAT
A
E1
+------------+ E2
5.|
| +------------+ E3
6.|
E3
7.|
ADAT-2
| +------------+ | +--------+ +------------+ | E1 | | +--------+ +------------+ | E2 | | +--------+ +------------+ | E3 | | +--------+ +------------+ | ADAT-3 | ~~~~~~~~~~ | +--------+ +------------+ 3.FELADAT TÁR
8.|
L +---+ A | 4!|
9.|
P +---+ T | 6!|
10.|
Á +---+ B | 2 |
|
L +---+ A
FIZIKAI
10.6. ábra. Kódmegosztás lapozásnál A probléma általánosan elfogadott megoldása egy kis, speciális hardvertár beépítése, amelyet tartalom szerint címezhető vagy asszociatív tárnak hívnak (l. 1.4.2). Ez a tár igen gyors, asszociatív regiszterekből állt, melyek együtt tartalmazták a lapcímet és a keretsorszámot. Ha megadtunk egy lapcímet, az asszocitív tár egyszerre hasonlítja össze ezt az összes tárolt értékkel, a megtalált regiszterben pedig ott volt a megfelelő keretsorszám is. A keresés igen gyors volt -- csak mintegy 10%-kal több a közvetlen címzés idejénél -- a szükséges hardver viszont meglehetősen költséges (belső cache, azaz belső -- értsd: CPU -- gyorstár). Éppen a magas hardverköltség miatt az asszociatív tárak általában csak a laptábla kis részét tartalmazzák. Egy-egy konkrét címtranszformációnál két eset lehetséges: Ha a keresett lap éppen az asszociatív tárban van, nincs probléma, ellenkező esetben pedig a tárból kell elővenni a keresett keretsorszámot, amit nem csak felhasználunk, hanem -- további hivatkozásokra számítva -- beírunk az asszociatív tárba. A találati valószínűség nyilván elsősorban az asszociatív regiszterek számától függ. 8 vagy 16 regiszterrel általában 80-90%os találati arány érhető el, ami egy átlagos 750 nsec tárelérési és 50 nsec asszociatív keresési idővel számolva csak mintegy 16-26%-os lassulást jelent. A lapozás másik jelentős előnye, hogy a közös programok több felhasználó közt megosztva futtathatók. Akármennyien dolgoznak például egy szövegszerkesztővel, ha annak kódja újra beléphető, egyetlen példányt elegendő a fizikai tárban tartani és, mindenki ezt használja. Egy program kódja akkor újra beléphető (angolul: reentrant), ha futás közben nem változik. Ilyenkor, ha mindegyik folyamatnak saját regiszterkészlet-másolata és adatterülete van, az osztott felhasználásnak nincs akadálya. Ha n felhasználó megosztva futtat egy programot, a megtakarítás a program tárigényének (n-1)-szerese. A megoldás modelljét a 10.6. ábra mutatja. A három lap hosszúságú szerkesztőprogram mindhárom felhasználó laptáblája szerint ugyanarra a fizikai címtartományra képződik le. A lapozáshoz természetesen külön tárvédelmi stratégia is tartozik, ezt a 10.8. pontban tárgyaljuk. Az a tény, hogy lapozásnál a felhasználó a fizikaitól különböző tárat lát, további lehetőségeket is tartogat. Mivel a logikai címek fizikaiakra való leképezését az operációs rendszer rejtett címfordító eljárása végzi, megvan annak a lehetősége, hogy a logikai és fizikai tár ténylegesen különböző méretű legyen. Ha például a logikai tár a használható fizikai tár negyedrésze (minden felhasználó csak legfeljebb ekkora tárigényű programot írhat), akkor a négyszeres multiprogramozás -- legalábbis a tárat tekintve -- automatikusan biztosított. Ezt a technikát a 60-as években (amikor a tár még drága volt) tervezett kisgépek alkalmazták előszeretettel az olcsó félvezetős tár megjelenésekor. A fizikai tár könnyen bővíthető volt, de a címtartomány növelése az utasításrendszer áttervezését és az addig megírt programok használhatatlanságát vonta volna maga után. A megfelelő címfordító eljárással és multiprogramozással ki lehetett használni a nagyobb tárat, bár egy-egy felhasználó most sem írhatott nagyobb programot, mint azelőtt. Ilyen volt például a Nova 3/D, amely az 5 bites lapcímet 7 bites keretsorszámmá; valamint a DEC-10, amely a 9 bites lapcímet 13 bites keretsorszámmá konvertálta. Ezt a címfordítást teljes mértékben az operációs rendszer vezérli, és természetesen ki/be kapcsolja saját maga, illetve a felhasználó számára. A keretek nyilvántartására egy külön adatstruktúra, az ún. kerettábla szolgál, amelyben minden fizikai kerethez egy elem tartozik, mely mutatja, hogy a keret szabad vagy melyik laphoz kapcsolódik. Mivel a címfordításra mindenképpen szükség van, érdemes a felhasználók kedvében járni oly módon, hogy a logikai tár olyan legyen, amilyet a felhasználó ténylegesen elképzel. Ez pedig nem bájtok lineáris, számozott sorozata, hanem funkcióval bíró, különböző nagyságú, sokszor rendezettséget nem mutató szegmensek gyűjteménye (l. a 3.7. ábrát). Egy-egy szegmens lehet egy eljárás, egy modul, egy táblázat, a főprogram stb. A felhasználó számára ezek tárbeli helye és
sorrendje teljesen közömbös, méretük különböző. A szegmensekre nevükkel, elemeikre pedig egy -- a szegmens kezdetétől mért -- relatív távolsággal hivatkozhatunk (pl. egy program vagy táblázat 20. sora). A szegmentálás olyan tárkezelés, amely ilyen jellegű logikai tárral dolgozik. A logikai címtartomány szegmensek halmaza, melyek mindegyikéhez egy név és egy hossz tartozik. A logikai cím a szegmens nevéből és a szegmensen belüli relatív címből áll. Emlékezzünk vissza, hogy a lapozásnál a felhasználó egyetlen címét a hardver vágta szét lap- és relatív címre a felhasználó "háta mögött". Az egyszerűbb megvalósítás érdekében a szegmensekre név helyett szegmensszámmal hivatkozunk. A tárgyprogramot a fordítóprogram állítja elő, amely automatikusan úgy építi fel a szegmenseket, hogy azok a forrásprogram szerkezetét tükrözzék. Egy Pascal fordító pl. a következő szegmenseket generálhatja: * * * *
globális változók verem az eljárások számára az eljárástörzsek kódja lokális változók eljárásonként
A felhasználó kétdimenziós logikai címeit természetesen most is fizikai címekké kell alakítani, amit a szegmenstábla segítségével tehetünk meg. A szegmensszámból (s) és a relatív címből (d) álló logikai címet a 10.7. ábrán látható hardver dolgozza fel. A szegmenscím a szegmens-tábla indexeként szolgál, a megfelelő elem pedig megadja a szegmens hosszát és bázisát. Ha d>=limit, címzési hiba történt, különben a fizikai cím a bázis és d összege.
SZEGMENSTÁBLA
0
+---------+ +-------+-------+
|
| 0.|
...
|
...
|
|
+-------+-------+
|
| ~~~~~~~~~~~~~ |
|
+---------------+
|
x-----> s.| LIMIT | BÁZIS |
|
| | | | | SZEG- |
+---|---+---|---+
VÉGCÍM
|
MENS- |
| ~~|~~~|~~~|~~ |
x-------->|
+---|---+---|---+
|
|
| | CÍM
|
| |
|
|
|
|
| SZÉT-
|
|
|
|
| VÁGÁS
|
|
|
|
/\|
|
|
|
TÁR
| --| /
\
| ( CPU )--->(s,d) | \
/ VIRT.
|
ELTO- /
|
|
|
|
|
LÁS
|\IGEN
|
|
|
d
|
| ---
CÍM
/
| x------x | HATÁR-
\
/
VÉGCÍMSZÁMÍTÁS
|
| ELLEN-
\
/
|
\/NEM
|
| ŐRZÉS | |CÍMZÉSI HIBA
MAX
+---------+ 10.7. ábra. Szegmenscím ellenőrzés bázis/limit regiszterpárral A 10.8. ábrán konkrét szegmentálási példát láthatunk öt szegmensre. A szegmentálás egyik előnye, hogy a tárvédelmet (l. 10.8.) szegmensekhez lehet rendelni, az utasítás szegmensek lehetnek pl. csak olvashatók vagy csak végrehajthatók (modern architektúránál az utasítások nem módosítják egymást vagy magukat). A közös szegmenshasználat szintén előnyös, hiszen ez is a szegmensek szintjén folyik, tehát lehetőséget nyújt bármilyen, önálló szegmensként definiált információ osztott használatára.
A szegmentálásnál fellépő elaprózódásra többé-kevésbé igaz, amit a lapkezelésnél elmondtunk, hiszen a szegmensek tulajdonképpen változó méretű lapoknak is felfoghatók. Ez esetben a dinamikus relokáció természetes, a külső elaprózódást ezért tömörítéssel lehet csökkenteni. Minél kisebbek a szegmensek, annál kisebb a külső elaprózódás is. A lapozást és a szegmentálást gyakran együtt alkalmazzák, igyekeznek mindkettőből csak az előnyöket megtartani. A két általános megközelítés az ún. szegmentált lapozás, illetve a lapozott szegmentálás. Ezeket a példák között mutatjuk be a 10.9. pontban.
.---------------------. +------------+ ( +-------+ ) / | | +---------+ | | | | / / / / / /| | | | | 3. | | / | | | 0. | | | | +------------+ | | | | | | | | |SZUBRUTIN| | VEREM | | 0.SZEGMENS | | |SZEGMENS | | SZEG- | | | | | | | MENS | | +------------+ | | | | | | / | | +---------+ | | | | / / / / / /| | +-------+ | +------------+ | +---------+ | | | | | | 3.szegmens | | +-------+ | 4. | | | | | 1. | | | | +------------+ | | SQRT | |SZIMBÓLUM| | 2.szegmens | | | SZUB- | | TÁBLA | | +------------+ | | RUTIN | | | | | | +-------+ | | | 4.SZEGMENS | | +---------+ | | | +------------------+ | +------------+ | | 2. | | / | | |FŐPROGRAM SZEGMENS| | +------------+ ( +------------------+ ) 1.SZEGMENS | *---------------------* +------------+
0 |/ / / / /
|/ / / / / LAPTÁBLÁZAT
1400 |
LIMIT BÁZIS
|
+-----+-----+
|
S 0.| 1000| 1400| Z
+-----+-----+
E 1.| G
2400
400| 6300|
+-----+-----+
M 2.|
|/ / / / /
3200
400| 4300|
|
+-----+-----+
|
N 3.| 1100| 3200|
|
E
S
+-----+-----+
4300
4.| 1000| 4700| +-----+-----+
| 4700 | | | 5700 |/ / / / / 6300 |
LOGIKAI TÁR
FIZIKAI
TÁR 10.8. ábra. Logikai szegmensek, szegmenstábla és fizikai szegmensek
10.6. Virtuális tár Az eddig bemutatott tárkezelési technikák közös célja, hogy minél több folyamatot tartsanak párhuzamosan a tárban a multiprogramozás elősegítése érdekében. A célt sokféleképpen közelítették, de a korábbi megoldásokban kikötés volt, hogy a végrehajtandó munkának teljes egészében a tárban kell lennie. Ha ezt az elvet is feladjuk (mint a lapozásnál a tárfolytonosságot), és kimondjuk, hogy nem kell okvetlenül a teljes munkát a tárban tartani a végrehajtás során, elérkezünk a virtuális tárkezeléshez. Az ötlet egyszerűnek tűnik, és sok előnnyel kecsegtet. A legszembetűnőbb talán, hogy a felhasználó programjai meghaladhatják a fizikai tár méretét. Másrészt az is gyakori, hogy az egyszerű ötletek megvalósítása nem könnyű, amint ezt a virtuális tár esetében is látni fogjuk. Az a felismerés, hogy egy program végrehajtásához rendszerint nincs szükség a teljes program jelenlétére, nem új. Jó példái ennek a többmenetes assemblerek vagy egyéb fordítóprogramok, de az adatfeldolgozó rendszerek is -- jó tervezés esetén -- egymással csak adatstruktúrákon keresztül érintkező modulokból állnak. Ma már személyi számítógépeken megvalósított nyelvek (pl. Pascal) is megengedik a programok ún. átlapoló (angolul: overlay) végrehajtását. Az általános megoldás szerint a program egy rezidens és egy tranziens területen helyezkedik el. A vezérlőrész a rezidens területen működik, és fő feladata, hogy a tranziens részre a program logikája szerinti sorrendben behívja az egymást átlapoló programrészeket. Természetesen több tranziens rész is lehet, de az egy logikai címre "beosztott" modulok egymást nem hívhatják. A tranziens részek hívása értelemszerűen egy dinamikus betöltést is magával vonhat, hacsak a hívott modul nincs éppen a tárban. Ha az átlapolási technikát a programozási nyelvek keretéből kiemelve az operációs rendszer szintjén valósítjuk meg, virtuális tárról beszélünk. A virtuális tár tehát automatikus átlapolási technológia. A virtuális tár a számítógépes rendszer számára legalább három szempontból előnyös: * A programokat nem köti a fizikai tár mérete, sőt a nagy virtuális címtartomány felhasználásával feltehetően egyszerűsödik a programozók dolga, munkájuk termelékenyebb lehet, hiszen nem kell az átlapolási algoritmus belövésével küszködniük (még talán el is felejthetik). * Mivel az egyes felhasználók kevesebb fizikai tárat kötnek le, több felhasználó szolgálható ki, növekszik a központi egység kihasználtsága és a rendszer átbocsátó képessége. * Kevesebb B/K műveletre kell, elmarad a munkák ki-be másolása, a rendszer hatásfoka javul.
LAPTÁBLÁZAT +-----+ KERET ÉRVÉNYESSÉGI 0| A | SZÁM BIT +-----+ +----+---+ + .----------------. 1| B | L 0| | N | ) +-----+ +----+---+ *----------------*| 2| C | A 1| | N | | +-----+ +----+---+ | 3| D | P 2| 9 | I | | +-----+ +----+---+ | 4| E | S 3| | N | | +-----+ +----+---+ | 5| F | Z 4| | N | | +-----+ +----+---+ | 6| G | Á 5| 6 | I | | +-----+ +----+---+ | 7| H | M 6| | N | | +-----+ +----+---+ | LOGIKAI O 7| 4 | I | | TÁR +----+---+ | K |
+-----+ 0| | +-----+ 1| | +----2|
|
(
+-----+
|
3|
SWAP
|
|
+-----+
|
+-+
+-+
+-+
|
|
| |
| |
| |
+-----+
|
+-+
+-+
+-+
4|
A
5|
TÁRKÉPEK
|
|
+-----+
|
+-+
+-+
+-+
|
|
| |
|A|
|B|
+-----+
|
+-+
+-+
+-+
6|
C
7|
|
|
+-----+
|
+-+
+-+
+-+
|
|
|C|
|D|
|E|
+-----+
|
+-+
+-+
+-+
8|
9|
|
|
+-----+
|
+-+
+-+
+-+
|
|
|F|
|G|
|H|
+-----+
|
+-+
+-+
+-+
10|
F
| 11|
|
|
+-----+
|
+-+
+-+
+-+
| ~~~ |
|
| |
| |
| |
+-----+
(
+-+
+-+
+-+
| | | )
MAX|
|
*----------------* +-----+ FIZIKAI TÁR
HÁTTÉRTÁR
10.9. ábra. Laptáblázat virtuális tárkezelésnél A virtuális tár megvalósítása több, néha bonyolult tevékenységből áll. Többféle gyakorlati megoldás létezik, ezek közül a legelterjedtebb az ún. igény szerinti lapozás (angolul: demand paging). Ez a technika leginkább a swappinggal kombinált lapozásra emlékeztet. A programot végrehajtás előtt egy esetleges cserével egybekötve olvassuk be. Az eltérés annyi, hogy a beolvasó (a swapper) csak akkor olvas be egy lapot, ha arra a program futása során ténylegesen szükség van. Annak érdekében, hogy a program ne próbáljon még be nem hozott lapon lévő címre hivatkozni, a laptáblában a már említett érvényességi bitet lehet használni. Legyen ez a bit 1, ha a lap a tárban van, egyébként pedig 0. A címtranszformáció természetesen az érvényességi bit vizsgálatával indul. Figyeljük meg, hogy ha a program nem hivatkozik a kérdéses lapra, nem is derül ki, hogy az nincs a tárban. Egy ilyen helyzetet szemléltet a 10.9. ábra. Ha az érvényességi bit alapján kiderül, hogy a lap még nem érhető el, ún. "laphibáról" beszélünk, de tudjuk, hogy ez az -- operációs rendszer által -- a gazdaságosabb üzemelés érdekében tudatosan elkövetett "hiba", amit a rendszer a következő lépésekben hoz helyre: 1) A folyamat vezérlőblokkjához tartozó táblában megnézi, hogy a kérdéses címet a folyamat jogosan használja-e. Ha nem, akkor igazi címhibáról van szó, a folyamatot meg kell szakítani. 2) Ha a cím jogos, a kérdéses lapot be kell olvasni: Ehhez először egy szabad keret kell, majd ütemezni kell a lemezről való olvasást, végül módosítani kell mind a folyamat saját tábláját, mind a laptáblát, hogy az új helyzetet fejezze ki. 3) Újra kell indítani a laphibát okozó utasítást ( l. 10.10. ábra).
(
+----------+ |OPERÁCIÓS-| | RENDSZER | | - - - - | | LAPHIBA |<----------x | | | MEGSZA- | | | | | KÍTÁS | | (3)A DISZKEN VAN | | | KEZELŐ >---------------------------------->x +------+ +----------+ |(2) .----|----. |LOAD B|>--------x(1)KERESÉS | C | ) | |<<<<<<<x | | Í |*----|----
*| +------+
(6)
| |
+-----------+ | M
|
|
| |
|AZ UTA-| |
|
| | H
+-------+
|
+-+
|
| SÍTÁS | |
|
| | I
|
|
|
| |
|
| ÚJRA- | |
+-----------+ | B
+-------+
|
+-+
|
| INDUL | x->| - - - ->N>--x A
|SZABAD |
|
|
|
|
|
|
| | | | x<<<<|<- - - - I*<<<<<<<<| LAP- <<<<<<<<<<x
| +-----------+
(5)
|KERET
|
|(4)A LAP
| | | BEOLVASÁSA) PROGRAM
|
| A LAP +-------+
+-----------+ ÉRVÉ- | | LAPTÁBLA NYES! | | | | | | +-------+ FIZIKAI TÁR
( *---------* HÁTTÉRTÁR
10.10. ábra. Lapkeresés és belapozás Az igény szerinti lapozás lényegében nem igényel több hardver támogatást, mint a swapping-gal egybekötött közönséges lapozás, bár azt is lehetővé kell tenni, hogy a laphiba miatt félbeszakadt utasítás újraindítható legyen. Ez a legtöbb esetben automatikusan teljesül, de vannak olyan utasítások is, amelyek pl. blokkosított adatátvitellel több cím tartalmát változtatják meg. Ilyen például az IBM 370 MVC utasítása, mellyel akár 256 bájtot is át lehet vinni a tár egy másik (esetleg az eredetit átfedő) részére. Ha egy ilyen átfedéses átvitelnél valamelyik terület laphatárt is tartalmaz, és a laphiba akkor következik be, amikor a forrásterület már megváltozott, az utasítást nyilván nem lehet újraindítani. A megoldást vagy egy mikroprogramozott vizsgálat jelenti, amely előre felderíti, hogy lesz-e laphiba; vagy a célterület eredeti tartalmát átmeneti regiszterekbe kell kimenteni, hogy onnan szükség esetén visszaállítható legyen. Hasonló probléma merült fel olyan utasításokkal is, amelyek mintegy mellékhatásként regisztereket automatikusan inkrementálnak vagy dekrementálnak. (Ez például a PDP-11-nél gyakori esemény.) Amíg tehát az egyszerű lapkezelés nem okoz számottevő architekturális problémát, ugyanez
már nem mondható el az igény szerinti lapozásról. Az igény szerinti lapozás hatékonyságát nem egyszerű kielemezni. Nyilván be kell vezetnünk a laphiba valószínűségét (p) és meg kell becsülnünk a laphiba feldolgozásához szükséges időt, ami feltehetően négy nagyságrenddel nagyobb, mint a normál tárhozzáférés ideje (ebben a keresett lap háttértárból való beolvasása is benne van). Ilyen feltételezések mellett arra a meglepő eredményre jutunk, hogy p=1/1000 esetében a gép működési sebességét az igény szerinti lapozás az eredeti 1/11 részére lassítja. Ahhoz, hogy a lassulás 10%-on belül maradjon, p nem haladhatja meg az 1/100 000-et. Ez azt jelenti, hogy egymillió címhivatkozásból csak mintegy 10 okozhat laphibát. Így az igény szerinti lapozásnál elsődleges szempont a laphiba-arány alacsonyan tartása. A multiprogramozás fokozásával könnyen előállhat az a helyzet, hogy a párhuzamosan futó programok számára együttesen kiosztott tár meghaladja a fizikai tár méretét. Ilyenkor ki vagyunk téve annak, hogy egy laphibánál azért nem lehet behozni a kívánt lapot, mert nincs szabad fizikai tárkeret. Ebben a helyzetben két megoldás van: swapping vagy lapcsere. Most az utóbbival foglalkozunk.
|
+-----------+ | | | | | | | | |
+--------+--+ | | | | | | | | | .-----------. | | |
|
|
(
|
|
|
|*-----------
+--------+--+
|
|
|
|ÁLDOZAT |I |
|
|
|
|
|
|
+--------+--+ MÓDOSÍTÁS
|
|
|
|
| (NEM ÉRVÉ-
+-----------+ SWAP KI| |
|
|
|
|
|
|
|
|
|
|
|
+-----------+
) |
|
*| | +-+
| CÍME
|N*|(2)TÁBLA-
x------>| |
| (1)
| |
+-+
| | NYES LAP)
ÁLDOZAT
|>-------x |
+-+
| |<<<<<<<<<<<<<<<<| |
| (3)
|
+-+
| +--------+--+
|
| SWAP BE
|
|KERESETT|N |
|
|
|
|
|
|
|
+--------+--+ BEÁLLÍTÁS
|
|
(
|
|
|
| | CÍME
|I*|(4)TÁBLA-
| ) |
| (MÁR ÉRVÉ-
*-----------
* | | | | | | | | | +--------+--+ LAPTÁBLA
NYES LAP)
| | | | | | | | | | | | | | +-----------+ FIZIKAI TÁR
10.11. ábra. Kilapozás
HÁTTÉRTÁR
A lapcsere, mint ezt a 10.11. ábra is mutatja, a laphiba-kezelő rutin módosított változatával oldható meg. 1) Az igényelt lap felkutatása a háttértárban. 2) Egy szabad keret keresése a) Ha van szabad keret, annak lekötése, b) Különben egy algoritmus kijelöli az "áldozat" lapot, c) Az áldozat kivitele a háttértárba, valamint a lap- és kerettábla megfelelő módosítása. 3) Az igényelt lap behozatala az áldozat helyére; a lap és kerettábla megfelelő módosítása. 4) A megszakított folyamat folytatása. Akkor a legnagyobb a veszteség, ha nincs szabad keret, mert ilyenkor két háttértárműveletre van szűkség. Ezen egy kis hardver segítséggel -- az ún. Írásjelző (Dirty = piszkos) bittel -- szoktak segíteni. A laponként vagy keretenként beépített és hardver úton kezelt bit jelzi, hogy a lap tartalma az utolsó beolvasás óta változott-e. Lapcserénél megvizsgálhatjuk az írásjelzőt, és ha nem volt változás a lapon, megtakaríthatjuk a fenti 2.c lépést.
10.7. Lapozási stratégiák A virtuális tárkezelés tulajdonképpen az igény szerinti lapozás minél gazdaságosabb megvalósítását követeli, ami viszont két központi problémakör megoldását teszi elkerülhetetlenné: megfelelő lapcsere algoritmusokra és jó keretkiosztási módszerekre van szükség. 10.7.1. Lapcsere algoritmusok A lapcsere algoritmusok célja a laphiba-arány csökkentése. Az algoritmusok értékelését egy címhivatkozási próbasorozattal lehet elvégezni, melynek végrehajtása során meghatározzák a laphibák számát. A próbasorozatot mesterségesen vagy valódi programokból vett minták alapján szokták előállítani. Az egyszerűség kedvéért a próbasorozatban elegendő csak a lapcímeket feltüntetni, és értelmetlen egy lapcímet kétszer egymás után szerepeltetni, hiszen a második hivatkozásnál soha nem fordulhat elő laphiba. Természetesen a laphibák számának meghatározásához ismerni kell a rendelkezésre álló keretek számát is. Az egyik legegyszerűbb algoritmus az ún. "előbb be-előbb ki" (angolul: First-In-First-Out, rövidítve: FIFO). A behozott lapokat egyszerűen egy sor végére állítjuk, laphiba esetén pedig az áldozatot a sor elejéről vesszük. Példaként tekintsük a következő próba sorozatot: 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1 Ha azt feltételezzük, hogy a tár három keretből áll, a 10.12. ábra mutatja a laphibákat:
7
0
1
2
0
3
0
4
2
3
0
3
2
1
2
0
1
7
0
1 +- +- +- +-
+- +- +- +- +- +-
+- +-
+- +-
|7 |7 |7 |2
|2 |2 |4 |4 |4 |0
|0 |0
|7 |7 |
+- +- +- +-
+- +- +- +- +- +-
+- +-
+- +-
|
|0 |0 |0
|3 |3 |3 |2 |2 |2
|1 |1
|1 |0 |
+- +- +- +-
+- +- +- +- +- +-
+- +-
+- +-
|
|1 |1
|1 |0 |0 |0 |3 |3
|3 |2
|2 |2 |
+- +- +- +-
+- +- +- +- +- +-
+- +-
+- +-
+7 +0 +|
1 +10.12. ábra. Laphiba-sorozat példa A 20 címhivatkozás tehát 15 lapcserét igényelt. A FIFO algoritmust egyszerű megvalósítani, de hatásfoka néha elég rossz, különösen, ha van egy nagyon gyakran használt, központi irányító lap a programban, amit állandóan célszerű lenne bent tartani, de ezt az algoritmus sokszor lecseréli. A FIFO másik problémája az ún. Belady-féle anomália. Ez érdekes jelenség, amely más lapcsere algoritmusnál is előfordul: bizonyos helyzetekben a keretek számának növelésével nem csökken, hanem növekszik a laphibák száma. Legyen például a próbasorozat a következő: 1 2 3 4 1 2 5 1 2 3 4 5 Ez a sorozat négy keret esetében 10, három kerettel viszont csak 9 laphibát ad a FIFO algoritmus alapján, pedig azt várnánk, hogy a tár növelésével a program gyorsulni fog. Létezik egy optimális lapcsere algoritmus (OPT), mellyel nem fordul elő a Belady-féle anomália: azt a lapot kell lecserélni, amelyet a folyamat a leghosszabb ideig nem igényel (tehát előre tekint, ami elvileg megoldhatatlan!). Ez a módszer adott keretszám mellett garantálja a minimális laphibaszámot. A 10.13. ábra az eredeti 20 tagú próbasorozattal mutatja be az optimális algoritmust. 7
0
1
2
+|7 +| +| +-
+|7 +|0 +| +-
+|7 +|0 +|1 +-
+|2 +|0 +|1 +-
0
3
0
4
2
3
0
3
2
1
2
0
1
7
0
1 +|2 +|0 +|3 +-
+|2 +|4 +|3 +-
+|2 +|0 +|3 +-
+|2 +|0 +|1 +-
+|7 +|0 +|2 +-
10.13. ábra. Optimalizált laphiba-kezelés Láthatjuk, hogy az OPT 9 laphibát ad, de mivel ebből az első három elkerülhetetlen, azt mondhatjuk, hogy az algoritmus megfelezte a FIFO laphibáinak számát. Az OPT megvalósításához azonban ismerni kellene előre a címhivatkozások sorozatát, ezért csak összehasonlító értékelésre használható. A gyakorlatban legtöbbször meg kell elégednünk az OPT valamilyen közelítésével,
erre a 10.9. pontban adunk példát. 10.7.2. Keretkiosztási algoritmusok A lapcsere algoritmus birtokában a tárgazdálkodás következő megoldandó problémája a rendelkezésre álló keretek szétosztása a multiprogramozásban részt vevő folyamatok között. Az egy folyamathoz rendelhető keretek száma nem csak felülről, hanem alulról is korlátozott. A felső korlátot a keretek száma, az alsót a számítógép architektúrája határozza meg, mert -- mint már említettük -- laphiba esetén a félben hagyott utasítást újra kell indítani. Ha az utasítások egycíműek, akkor legalább kettő, ha indirekt címzés is megengedett, legalább három keretre van szűksége minden folyamatnak, hiszen az egyik lapon lévő utasítás címe hivatkozhat indirekten egy másik lapra, ahol a harmadik lapra mutató cím található. Általában legalább annyi keretet kell egy folyamathoz rendelni, amennyi az egyetlen utasítással érinthető különböző lapok mentéséhez kell. Az egy szónál hosszabb utasítások esetében a helyzetet bonyolítja, hogy maga az utasítás is két lapra kerülhet. Az alsó határ a PDP-8-nál három, a PDP-11-nél 6, az IBM 370-nél 8. Olyan gépeknél, mint például a Data General Nova, ahol eredetileg tetszőlegesen hosszú indirekt címláncot engedtek meg, a lapozás bevezetésekor ezt 16 szintre korlátozták, különben elvileg egyetlen utasítással a teljes tár összes lapjára hivatkozni lehetett. Anélkül, hogy az egyes folyamatokhoz rendelt keretek számát megadnánk, két alapvető stratégiát különböztethetünk meg, a globális és a lokális kiosztást. Globális kiosztásnál minden folyamat keretigénye a szabad keretek közös halmazából elégíthető ki, míg lokális esetben a folyamat csak saját kereteivel gazdálkodik. A két megoldás közötti alapvető eltérés -- és egyben a globális kiosztás hibája -- , hogy egy munka nem szabályozhatja a saját laphiba-gyakoriságát, mert ez a többi folyamat viselkedésétől is függ. A legegyszerűbb algoritmus az ún. egyenlő kiosztás. Ez azt jelenti, hogy minden folyamathoz ugyanannyi ( n keret és m folyamat esetén n div m) keret tartozik, és a maradék a szabad keretek halmazát alkotja. Ha észrevesszük, hogy a nagyobb programok általában több keretet igényelnek, mint a rövidek, az egyenlő kiosztást arányos kiosztásra finomíthatjuk a folyamatok virtuális tárigényeinek arányában. A rendszer működése során a folyamatok keretállománya mindkét esetben a multiprogramozás fokával fordítva arányos. A következő lépés mindkét esetben a folyamatok prioritásának figyelembe vétele lehet: magasabb prioritás esetén több tárral gyorsítani lehet a folyamatot. Hasonló hatás úgy is elérhető, hogy lapcserénél az alacsony prioritású folyamatoktól veszünk el tárat. Ilyen stratégiánál azonban körültekintően kell eljárni, mert ha egy folyamat rendelkezésére álló keretek száma az abszolút szükséges minimum közelébe kerül, fellép az ún. vergődés (angolul: thrashing), amikor a folyamat több időt tölt lapcserével, mint futással. Globális kiosztásnál egy folyamat vergődése miatt létrejött magas laphiba-gyakoriság láncreakciószerűen elterjedhet a rendszerben, ami a központi egység kihasználtságának hirtelen zuhanását eredményezi, és megoldást csak a multiprogramozás fokának csökkentése jelent. Lokális kiosztásnál a vergődés kisebb problémát jelent, a többi folyamat tára megmarad, csupán a lapcserére váró sor és ezzel együtt a folyamatok futási ideje növekszik. A vergődés elkerülésére többféle módszert dolgoztak ki. Az egyik lehetőség azon a feltételezésen alapszik, hogy egy folyamat kis környezetből kis környezetbe vándorolva működik, egy ideig főleg lokális címekre hivatkozik, majd átáll egy másik környezetbe és ott újra a lokális címhivatkozások dominálnak stb. Ezt hívják röviden lokalitásnak. A lokalitás kihasználásával meg lehet keresni és állandóan karban lehet tartani azt a lapcímhalmazt, amely várhatóan az aktív lapokat tartalmazza. Ennek érdekében felvesznek egy H értéket, és a kritikus halmazba besorolják az első H tárhivatkozásban szereplő lapcímeket. Ezt az eljárást időnként megismétlik. Ha H értékét jól
becsültük (a szakirodalom 10 000-et javasol), a program lokalitásai követhetők. A lokalitás számontartása sok gyakorlati problémát vet fel, ezért általában a vergődés megelőzésére közvetlenebb módszert, a laphiba arány figyelését használják. Meghatároznak egy alsó és egy felső laphiba-arány határt, s ha a folyamat a felső határ fölé kerül, további kereteket kell hozzárendelni; ha pedig az alsó határ alá esik, el lehet venni tőle néhány keretet. Ha a szabad keretek halmaza kiürülne, további igény esetén sor kerülhet folyamatok felfüggesztésére is.
10.8. Tárvédelem Az abszolút-címzésű rendszerek határregiszterétől hosszú út vezetett a korszerű tárvédelemig. Ennek csak fontosabb állomásait foglaljuk össze. Az MFT és az MVT algoritmus közös tárvédelmi igényeket támaszt. Minden programot védeni kell az összes többi programtól, ezért egy helyett két határregiszterre van szükség, amint ezt a 10.4. ábra is mutatja. A határregiszterek vagy a partícióban generálható legkisebb és legnagyobb címet, vagy a legkisebb címet (bázis cím) és a partíció hosszát, az ún. limitet tartalmazzák. Az első csak a programok statikus (fordításkor, vagy legkésőbb a betöltéskor) rögzített relokációját engedi meg, míg a bázis- és limitértékekkel már a logikai címek is ellenőrizhetők (nem haladhatják meg a limitet), a bázis hozzáadásával pedig a relokáció futás közben, dinamikusan végezhető el. Az IBM 360 a statikus, a CDC 6600 és utódai a dinamikus relokációt alkalmazták. A lapozással kapcsolatos tárvédelmet laponként valósítják meg egy vagy több védőbit segítségével. A védőbiteket a laptáblában tartják. Egy bittel egy lapot csak olvashatónak vagy írható-olvashatónak lehet minősíteni. Amíg a fizikai cím meghatározódik, ellenőrizni lehet a védőbitet is. A védelem megsértése címzési hibát, megszakítást eredményez. A védelmet gyakran tovább finomították -- általában hardvertámogatással -- például abba az irányba, hogy csak olvasható, írható--olvasható és végrehajtható minősítéseket lehessen kezelni. A laptáblabeli védőbitet pedig jól lehet érvényes--érvénytelen jelzésként is használni olyan munkáknál, melyeknél a címterület a munka méretéből következően nem fedheti le a teljes címtartományt. Így a program címzési hibái könnyebben behatárolhatók. +---------------+ | 4.FELHASZNÁLÓ | +---------------+ | 3.FELHASZNÁLÓ | | | .-----------. +===============+<<<<<<<<( FELSŐ HATÁR ) | 2.FELHASZNÁLÓ | *-----------* | | .-----------. +===============+<<<<<<<<( ALSÓ HATÁR ) | 1.FELHASZNÁLÓ | *-----------* +---------------+ | MONITOR | HATÁRREGISZTEREK +---------------+ FŐTÁR 10.14. ábra. Címellenőrzés határregiszterekkel
.--------. .---------. (ALSÓ HATÁR) (FELSŐ HATÁR) *---|----* *----|----* +----------+ | | | | --/ \ / \ | | / \ CÍM / \ IGEN / \ IGEN | | ( CPU )------>x >= x------>x < x---------->| TÁR | \ / \ / \ / | | --\ / \ / | | | NEM | NEM | | | | | | CÍMZÉSI --- HIBÁK +----------+
(a)
.--------. .---------. LIMIT ) ( BÁZIS ) *---|----* *----|----* +----------+ | | | | --/ \ | | | / \ CÍM / \ IGEN | | | ( CPU )------>x < x---------(+)------------>| TÁR | \ / \ / | | --\ / | | | NEM | | | | | CÍMZÉSI HIBA +----------+
(b)
(
10.15.
a) ábra. Címzési hiba két határregiszter esetén b) ábra. Címzési hiba bázis/limit regiszterpárnál
10.9. Mintapéldák A fejezet előző pontjaiban kifejtett általános megoldásokon túlmenően igen sok, szellemes, de csak egy-egy géptípusra megvalósított technika és algoritmus él. Az alábbiakban ezekből ismertetünk néhányat. 10.9.1. Tömörítés, dinamikus relokáció Ha a munka által igényelt tárat két részre bontjuk, az elaprózódás csökkenthető. A PDP-10 két bázis--limit regiszterpárt használ, a tárigényt pedig a legmagasabb helyiértékű címbit szerint elfelezi. A tár alsó részét az egyik, felső részét a másik regiszterpár segítségével relokálja. Megállapodás szerint a fordítóprogramok a csak olvasandó értékeket (utasításokat, konstansokat stb.) a felső részbe teszik, a változókat pedig az alsó részben helyezik el. Mindkét regiszterpárhoz védőbitek tartoznak, melyek segítségével a felső részbe való írás megakadályozható. Ilymódon lehetőség van programok osztott használatára is. Természetesen minden felhasználónak külön alsórészbeli szegmense van. A UNIVAC 1108 hasonló megoldást követ, de a tár szétválasztása más. A központi egység tudja, hogy utasítást akar-e kiválasztani, vagy adatot olvasni, illetve írni. A két bázis--limit regiszterpár egyikét csak utasítás-kiválasztásra, a másikat csak adatok mozgatására alkalmazza. A programok
természetesen így is osztottan használhatók. Mindkét megoldás a programok utasításainak és adatainak szétválasztásával éri el a szétaprózódás csökkenését és az osztott programhasználatot. 10.9.2. Szegmenstáblák A szegmenstáblák leghatékonyabban regiszterek segítségével valósíthatók meg. A PDP-11/45 például 8 szegmensregisztert alkalmaz, és a 16 bites címet hárombites szegmenscímre és 13 bites relatív címre osztja. Ez 8 darab, 8K méretű szegmenst jelent, melyek mindegyikéhez saját báziscím, limit és több védőbit tartozik. A védőbitekkel teljes tiltás, csak írás, valamint írás--olvasás állítható be. A GE 645 a MULTICS-nál 256 darab, egyenként 64K szavas szegmenst használ. Ennyi szegmensnél már nem ésszerű a szegmenstáblát regiszterekre alapozni, hanem a tárban kell tartani. A szegmenstábla kezdőcímét azonban egy regiszter, az ún. STBR (SzegmensTábla BázisRegiszter) tartalmazza. Mivel egy program által használt szegmensek száma gyakran változik, másik regisztert célszerű alkalmazni a szegmenstábla aktuális hosszának tárolására. A címszámítás a lapozáshoz hasonlóan történhet, még az is igaz, hogy a rendszer jelentős lassulását általában csak egy közbeiktatott asszociatív regiszterkészlettel lehet megakadályozni. 10.9.3. Kombinált megoldások A lapozás és a szegmentálás együttes alkalmazásától azt várják, hogy jobb eredményt ad, mint bármelyik technika egyedüli használata. Az egyik kombinációs lehetőség, amit az IBM 360/67-nél vezettek be, a szegmentált lapozás volt. A gép 24 bites címeit 12 bites lapcímre és 12 bites relatív címre osztották, a laptáblában minden elem 2 bájtot foglalt el és 12 bites keretszámot, valamint egy érvényességi bitet tartalmazott. A lapcím alapján tehát 8 Kbájt hosszúságú laptáblákra volt szükség. A helyzetet tovább nehezítette, hogy 32 bites logikai címeket akartak használni 20 bites lapcímmel, ami már 2 Mbájtos laptáblákat jelentett. A gyakorlatban természetesen a laptábla legnagyobb része üres lenne, mert a programok túlnyomó többsége csak a logikai címtartomány egy töredékét használja. Ezért a laptáblát szegmentálták. A lapcím felső négy bitjét szegmenscímnek tekintik, amely egy 16 elemű szegmenstábla indexeként szolgál. A szegmenstábla egy eleme a megfelelő szegmens laptáblájának kezdőcímét és hosszát tartalmazza (l. 10.16. ábra), így a laptábla üres része nem foglal le tárat. Ez a megoldás rossz esetben csak három tárhivatkozással ér el egy címet, ezért 8 asszociatív regiszterre itt is szükség van.
VIRTUÁLIS CÍM SZEGMENS/LAP ELTOLÁS +-------------+-------+ | p | d >------------------------------x +------|------+-------+ | | | +---+--|------+ | | s | p’ | | MAX+---------+ +-|-+----|----+ | | | | | SZEGMENSTÁBLA | | | | | (LAPTÁBLA ADATOK) | | | | | 15+-------+-------+ | | | | | | | | | | | | | | | | | | | | | +-------+-------+ | | | (+)-----|->s| LIMIT | BÁZIS >--x | | | | | +---|---+-------+ | | | | | | | ~~|~~ ~~~~~ | | | | | | | 0+---|-----------+ | | ~~~~~ | | | | STBR | | | +-------+ | | | (SZEGMENS-| / \ | | | | | | TÁBLA | / \ IGEN | +-------+ +-+-+ +---------+ BÁZISx----x < x--------->(+)->p’| f ---->|f|d|--->>+-| REGISZ\ / +-------+ +-+-+ f| | d | TER) \ / | | FIZIKAI ++-------+ | NEM +-------+ CÍM | LAPKERET | | | ~~~~~ | | | CÍMZÉSI HIBA LAPTÁBLA | | RÉSZLET | |
| | 0+--------+ FIZIKAI TÁR 10.16. ábra. Szegmentált lapozás A MULTICS-nál más jellegű probléma jelentkezett. Itt a logikai cím 18 bites szegmenscímből és 16 bites relatív címből állt, de a változó szegmensszám, illetve a szegmenstábla hosszát tartalmazó regiszter miatt a tábla méretével nem volt probléma. Nagyok voltak azonban a 64K szavas szegmensek, ami komoly külső elaprózódást jelentett volna, ha pedig valamilyen, legjobb illeszkedést biztosító algoritmust használnak, a rendszer megengedhetetlenül lelassul. Ezért a szegmenseket osztották lapokra, amint ezt a 10.17. ábra is mutatja: A lapozás lecsökkentette a külső elaprózódást, hiszen a szegmens-relatív címet 6 bites lapcímre és 10 bites laprelatív címre bontották. Minden szegmensnek ugyan külön laptáblája van, de ezek is csak annyi eleműek, amennyire ténylegesen szükség van. A közönséges szegmentálástól abban tér el lényegesen, hogy a szegmenstáblában a szegmens bázisa helyett a megfelelő laptábla kezdőcíme van. Az igazság kedvéért megjegyezzük, hogy a MULTICS valójában bonyolultabb: kénytelen a legfeljebb 262.144 szegmenst nyilvántartó szegmens tábláját is lapozottan kezelni .
VIRTUÁLIS CÍM SZEGMENS LAP/ELTOLÁS +---+-----------------+ +-----+-----------+ | s | d >------------->| p | d’ | +-|-+-----------------+ +--|--+-----|-----+ | | | | | / \ | | / \ IGEN MAX+---------+ | | x->x < x-------x | | | SZEGMENSTÁBLA | | \ / | | | | (LAPTÁBLÁK ADATAI) | | \ / | | | | +-------+-------+ | | | NEM | | | | | ~~~~~ | ~~~~~ | | | | | | | | | x-----------------X CÍMHIBA | | | | +---|---+-------+ | | | | (+)------->s| LIMIT | BÁZIS | | +-------+ | | | | +-------+---|---+ | | | | | | | | ~~~~~ ~~|~~ | | +-------+ | | | | 0+-----------|---+ | | | | | | STBR | | +-------+ | | | (SZEGMENS| | | | | | | TÁBLA | | +-------+ +-+--+ +---------+ BÁZISx---->(+)-->p| f ---->|f|d’|-->>+-| REGISZ+-------+ +-+--+ f| | d’ | TER) | | FIZIKAI ++-------+ +-------+ CÍM | LAPKERET | | | | | +-------+ | | 0| | | | +-------+ | |
AZ ‘s’ SZEGMENS 0+---------+ LAPTÁBLÁJA
FIZIKAI
TÁR 10.17. ábra. Lapozott szegmentálás 10.9.4. Az optimális lapozás közelítései Mint láttuk a FIFO algoritmus a tárban legrégebben tartózkodó lapot cseréli le és ezzel néha komoly hátrányba kerül az OPT algoritmussal szemben, amit azonban nem lehet a gyakorlatban megvalósítani, mert a folyamatok jövőjére támaszkodik. Ha a jövő helyett a közvetlen múltat vesszük figyelembe, az OPT egy elég jó közelítését kapjuk. Az az elv, hogy ha azt nem is ítélhetjük meg, hogy melyik lapra nem lesz még sokáig szükség, azt esetleg tudhatjuk, hogy melyikre nem volt már régóta hivatkozás. Az algoritmus a "legrégebben használt" (angol rövidítése: LRU= Least Recently Used) nevet viseli és kimondja, hogy lapcserénél a legrégebben használt lap legyen az áldozat. Az algoritmust a 10.18. ábra szemlélteti. 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1 +- +- +- +++- +- +- ++++|7 |7 |7 |2 |2 |4 |4 |4 |0 |1 |1 |7 +- +- +- +++- +- +- ++++| |0 |0 |0 |0 |0 |0 |3 |3 |3 |0 |1 +- +- +- +++- +- +- ++++| | |1 |1 |3 |3 |2 |2 |2 |2 |2 |7 +- +- +- +++- +- +- ++++10.18. ábra. A legrégebben használt lap kilapozása (LRU algoritmus) Észrevehetjük, hogy az LRU a FIFO 15 laphibáját 12-re csökkenti. Az LRU algoritmus esetén a probléma nem a hatékonysággal, hanem a megvalósítással van, mert komoly hardvertámogatást igényel. Általában két megoldást alkalmaznak: az egyik egy számláló, amit a központi egység minden címhivatkozáskor megnövel, a laptábla rovatai pedig ennek másolatait tartalmazzák. A választás még így is egy keresés eredménye. A másik, kicsit egyszerűbb megoldás: a lapcímeket egy veremben tárolják. Ha egy lapra hivatkozás történik, azt a veremből kivéve ráteszik a verem tetejére. Így a verem tetején mindig az utoljára, az alján pedig a legrégebben használt lapcím van. Mivel a verem közepéről is ki kell emelni elemeket, a vermet célszerű kétszeresen (a két szomszéd irányában) láncolt listával megvalósítani. Ez a megközelítés különösen a tisztán szoftver vagy mikroprogramozott megvalósításoknál célszerű. Az LRU jóval egyszerűbb, de csak közelítő változata az ún. "második lehetőség", ami a laphoz csatolt hivatkozási biten alapszik. A hivatkozási bit értéke a lap behozatalakor 0, a hardver akkor állítja 1-re, ha hivatkozás történt a lapra. Az algoritmus csak abban különbözik a FIFO-tól, hogy ha az áldozat hivatkozási bitje 1, akkor ad neki egy második lehetőséget, és olyan áldozatot keres, amelyikre behozatala óta még nem hivatkoztak. Ha ilyen nincs, az algoritmus azonos a FIFO-val. 10.9.5. Egyéb megfontolni valók A lapozási és lapkiosztási algoritmusok igen fontosak lehetnek, de néhány egyszerű ötlet is további segítséget nyújthat. Az igény szerinti lapozásnál nyilvánvaló, hogy azonnal a program indulásakor sok laphiba keletkezik, és ugyanez történik a swapping során is, amikor a folyamat újra visszakerül
a tárba. Ezen segíthet az ún. előlapozás. Ha például a folyamatok aktív lapjainak halmazát a rendszer folyamatosan nyilvántartja (l. 10.7.2.), az előlapozás azt jelenti, hogy minden megszakítás utáni folytatáskor az aktív lapokat kérés nélkül betöltik a tárba, és ezzel egy laphiba sorozatot eliminálnak. Egy másik fontos tervezési szempont a lapok mérete. A két egymásnak ellentmondó cél a laptábla méretének csökkentése, illetve a belső elaprózódás féken tartása, ami a lapok méretének csökkentésével azonos. Ha ehhez még hozzávesszük a lapok kivitelének és behozatalának idejét is -- mint újabb szempontot -- meglehetősen komplex problémát kapunk, amelynek nincs egyértelmű megoldása. Még azt sem lehet általában eldönteni, hogy a B/K időt a lapméret csökkentése vagy növelése redukálja. Mivel az átvitelnél nem az átviteli, hanem a várakozási idő dominál, nagyobb lapmérettől kevesebb átvitel várható. Ugyanakkor kisebb lapmérettel a lokalitás jobban kihasználható és több szabad tár marad, mert nem hozunk be egy lappal együtt sok felesleges, soha nem használt bájtot is. Néhány gyártó azzal ismerte el a probléma súlyát, hogy kétféle lap méretet engedélyez. (GE 645-nél 64K, ill. 1 Kszó; az IBM/370-nél 2K ill. 4 Kbájt).
10.10. Gyakorlatok 10.10.1.
Mi a tárkezelés szerepe és jelentősége a számítógépes rendszerekben?
10.10.2.
Mi a különbség a logikai és fizikai címek között?
10.10.3.
Miért nem képes az OS/MVT az IBM 360-on tömörítésre? Hogyan oldják meg ezt más gépeken?
10.10.4.
Mi a különbség a külső és belső elaprózódás között?
10.10.5.
Milyen hardvertámogatást igényel a lapozás, ha elfogadható hatékonyságot követelünk meg?
10.10.6.
Tekintsük a következő szegmenstáblát: Szegmens
Bázis Hossz 0 1 2 3 4
219 2300 90 1327 1952
600 14 100 580 96
Határozzuk meg a következő logikai címeknek megfelelő fizikai címeket: a) b) c) d) e) f)
0,450 1,10 1,2 2,500 3,400 4,100
10.10.7.
Miért szokták a szegmentálást és a lapkezelést együttesen alkalmazni?
10.10.8.
Miért könnyebb egy újra beléphető modult megosztottan használni szegmentált, mint csak tisztán lapozott környezetben?
10.10.9.
Milyen mechanizmussal lehet egy szegmenst két különböző folyamat logikai címtartományába illeszteni?
10.10.10.
Mi a laphiba? Mi az operációs rendszer teendője, ha előfordul?
10.10.11.
Rendezzük a következő lapcsere algoritmusokat laphiba-arány szerinti sorrendbe: a) b) c) d)
LRU FIFO OPT Második lehetőség
10.10.12.
Egy 460 bájtos programban a következő címhivatkozási sorozat fordul elő (0. relatív!): 11, 10, 104, 170, 73, 309, 185, 245, 246, 434, 458, 364 * * * *
Adjuk meg a megfelelő lapcímsorozatot 100 bájtos lapméret mellett! Mekkora a laphiba-arány 200 bájtos fizikai tár és FIFO algoritmus mellett? LRU algoritmus mellett? OPT algoritmus mellett?
10.10.13.
Hogyan lehetne hardvertámogatás nélkül egy, a tárban lévő lapokra való hivatkozást regisztráló bitet szimulálni?
10.10.14.
Tekintsük a következő lapcím-hivatkozási sorozatot: 1
2
3
4
2
1
5
6
2
1
2
3
7
6
3
2
Hány laphiba fordul elő a következő algoritmusok használata esetén: a) LRU b) FIFO c) OPT 10.10.15.
Mi a vergődés fogalma? Mi okozza? Hogyan lehet megelőzni?
1
2
3
6
10.10. Appendix: A cc-NUMA, a VLMS és társai {2001 -- ZSP:}Itt maradt egy üres lap, amit nehezen tűr meg egy igazi szerző. A témába vágó, aktuális problémát azonban nem nehéz találni. Ilyen a nagy teljesítményű, többprocesszoros szerverek tárgazdálkodásának a problematikája. UMA (Universal Memory Access). Az ősi processzorok még nem tartalmaztak gyorsító tárakat. Ezért minden hardver elem egységes módon érhette el a tárbuszt (UMA). Ez jelentősen megváltozott a gyorstárak bevezetése után. A DMA (Direct Memory Access -- direkt tárhozzáférés) technológiája pedig egyenesen kikerülte még a gyorstárakat is, illetve a perifériákon rendszeresített gyorstárakkal, inkább használt nevükön: puffertárakkal, került kapcsolatba (és olykor összetűzésbe). NUMA (Non-Uniform Memory Access). A tárhozzáférés tehát egyre kevésbé univerzális. Az ilyen gépeket nevezik NUMA-architektúrájú gépeknek. cc-NUMA (Cache Coherent Non-Uniform Memory Access). Amint egyre szaporodtak a gyorstárak a nagy teljesítményű hardverekben, úgy merült föl egyre több gond amiatt, hogy a tárban és a gyorstárakban nem azonos értékek szerepeltek. Ez kulminált akkor, amikor megjelentek a többprocesszoros gépek, mindegyik processzorhoz tartozó külön gyorstárakkal. A mai szerverek kritikus működési problémája tehát az, hogy ilyen sokprocesszoros és sok-gyorstáras konfigurációkban hogyan tartható kézben a gyorstárakban tárolt adatok koherenciája. Azokat a megoldásokat, amelyek ezt jól tudják támogatni, cc-NUMA architektúrájú gépeknek nevezik. Ne feledjük, ma már ezerszámra raknak processzorokat egy multiprocesszoros számítógépbe, mindannyihoz tartozó belső és külső gyorstárakkal, amelyek szinkronban tartása nem hétköznapi probléma. A dolgot nehezíti, hogy a cc-NUMA architektúrának még a bővíthetőséget is minél kevésbé szabad korlátoznia. Élenjáró megoldások születtek a Sequentnél, amelyre az IBM rá is tette a kezét, a Data Generalnál, a Digitalnál, amelyet azóta az induláskor az első sikeres hordozható gépével föltűnt Compaq gyűrt maga alá, de a technológia már elég széles körben elterjedt (néhány változatban) az összes fontos szervergyártó körében. VLMS (Very Large Memory Systems), avagy a tárba ágyazott állományok. Az operatív tárak gyártási technológiája folytán áruk drasztikusan csökken (bár nagyon sokáig árkartellt sejtett az ember a minden más hardver eszközhöz képest hosszú ideig egyforma árszintjük miatt). Ez lehetővé teszi, hogy ma már akkora tárakat rakhassunk a hardvereinkbe, amelyeket korábban el sem lehetett volna képzelni. A Terabájtok sem irreálisak. De mi a francra lehet használni ilyen marha nagy tárakat. Hacsak azt nem vesszük figyelembe, hogy van olyan operációsrendszer-gyártó cég, amely tán a világ összes hardver erőforrásának az elfecsérelésére alkalmas operációs rendszerek készítésére is képes (hogy újjal ne mutogassak). Továbbá a programozó, persze, légnemű állapotú lény: minden rendelkezésre álló teret betölt. Nos, túl a kajánkodásokon, hasznosan tényleg mire jók ekkora tárak? A világháló talán az élenjárók között volt abban, hogy ilyen eszközökre szükség legyen. Így sikerült fantasztikus hírnévre tennie a Digital Alpha technológia bázisán megalkotott Altavista Internetes kereső szolgálatnak. A VLMS technológia haszonélvezői tehát egyértelműen az olyan adatbázis-technológiás megoldások lehetnek, amelyek a működésükhöz szükséges adatbázisnak egy bájtját sem tartják háttértáron, hanem a nagy sebességű operatív tárba ágyazva. Ezt támogató operációsrendszeri funkciók is szükségesek hozzá, persze. Nem csoda, hogy ezeket éppen a 64-bites UNIX-ban lehetett legkönnyebben megvalósítani, bár azóta a 64-bites VMS-ben és Windows NT-ben is használható. Hatékony működtetéséhez elengedhetetlen a CPU-kban a 64-bites ofszet címtartomány kezelése! Eggyel több ok a 64-bites processzorkorszak széles körű elterjedésére. És ahogy a szervertechnológiák sorra terjednek az alacsonyabb gépkategóriákra,
várhatóan a tárba ágyazott állományok technológiája is tért fog hódítani szinte a legkisebb gépkategóriákig mindenhol. OS11V06.RTF,2000-04-20,ZSP
11. ÁLLOMÁNY- ÉS OBJEKTUMKEZELÉS
A számítógépes rendszerekben az operatív táron kívül igen változatos módon lehet adatot tárolni. A tárolóeszközök közül az operációs rendszerek szempontjából a mágneses alapú háttértárak érdekesek, a technikailag már elavult mágnesdobokat a mágneslemezek váltották fel, a mágnesszalagok pedig -- különösen a nagygépek mellett -- még ma is nélkülözhetetlenek.
11.1. Állományok és állományrendszerek A háttértárak sokfélesége miatt, valamint kezelésük egységesítése érdekében, az eszközök fizikai tulajdonságaitól elvonatkoztatva, az adatokat logikai egységekben, adatállományokban, rövidebb szóval állományokban, tárolják. Egy állomány a létrehozója által definiált logikailag összetartozó adathalmaz. Az állományokat kézenfekvően osztályozhatjuk tartalmuk szerint. Beszélhetünk programállományokról, melyekben forrás-, tárgy-, bináris- és egyéb formátumú programokat tárolnak. Az adatállományok a legkülönbözőbb formájú adatokat, numerikus, alfabetikus, alfanumerikus információt tartalmazhatnak. Az alfanumerikus adatállományokat szövegállománynak is nevezik. Szerkezetüket tekintve, az állományok bájtok, szövegsorok vagy rekordok sorozatai, a komponensek jelentését pedig az állományt létrehozó felhasználó határozza meg. Az állományokhoz több jellemző (attribútum) tartozik, melyek közül a legfontosabbak: * * * * * *
az állomány neve, hossza, típusa, tulajdonosa, létrehozásának dátuma és a hozzáférési jogkörök.
Az operációs rendszerek és az állományok kapcsolatában alapvető kérdés, hogy a rendszer milyen állománytípusokat ismerjen és támogasson. Egy típus támogatása azt jelenti, hogy az állománnyal kapcsolatos műveleteket az operációs rendszer rutinjai végzik, a felhasználó csak ezek hívásáról és paraméterezéséről gondoskodik. Ebben az esetben olyan szolgáltatások is rendelkezésre állnak -- mint például az IBM PC TURBO Pascal rendszerében --, ahol egy program végrehajtásakor a nyelvi rendszer ellenőrzi, hogy az utolsó fordítás óta nem módosították-e a programot. Ha igen, az indítást automatikus fordítási menet előzi meg. A szövegállományokat kezelő rendszereknél is természetes, hogy a felhasználót kilépéskor figyelmeztetik, ha a munkaállományt még nem mentette ki.
Ugyanakkor a sokféle állománytípus operációs rendszer szintű felismerése azzal a következménnyel jár, hogy megnő a rendszer mérete, és ennek dacára is lesznek olyan alkalmazások, ahol újabb állományszerkezetre lenne szükség. Általában az operációs rendszer csak néhány alapvető állománytípust ismer (pl. ASCII karakter és bináris, végrehajtható programokat tartalmazó állományok), a többi, ezekre épülő állományszerkezetet pedig az egyes alkalmazási rendszerek kezelik. Több sikeres rendszer, mint például a UNIX csupán egyetlen állományszerkezetet ismer: minden állomány bájtok sorozata. Ebből -- alkalmazói szinten -- tetszőleges állománytípusok alakíthatók ki. A különböző állományok támogatásától függetlenül minden operációs rendszernek gondoskodnia kell az állományok nyilvántartásáról és -- mint látni fogjuk -- védelméről, mert ez csak ezen a szinten oldható meg.
11.2. Adatok, perifériák, adatkezelés Mivel a számítógépes rendszerben a háttértárakon minden adatot állományokban tárolnak, az operációs rendszer legnagyobb része is állományokat alkot. Ilyen szempontból a rendszer három részre oszlik: * A ROM tárban tárolt kezdeti betöltőprogram és a rendszermag fix része. * Az indításkor betöltendő ún. rezidens rész, amely üzem közben állandóan a RAM tárban tartózkodik. * A különböző szolgáltatásokat megvalósító, de csak hívás esetén beolvasott, ún. tranziens rutinok. Az IBM PC MS-DOS rendszerében például rezidens az állományokat másoló COPY és tranziens a teljes lemezt másoló DISKCOPY rutin. Ennek megfelelően az operációs rendszerek az általuk elsődlegesen használt háttértárak szerint is osztályozhatók, amint ez a mai rendszerek nevében gyakran szereplő DOS (Disk Operating System = Mágneslemezes Operációs Rendszer) rövidítésből is sejthető. A régi rendszerek mágnesdob vagy mágnesszalag alapúak voltak. Manapság azonban a dobok feledésbe merültek, a szalagok pedig csak kiegészítő tárakként használatosak. Az operációs rendszerek alapvető háttértára a mágneslemez lett. A mágnesszalagoknál két alapvető tárolási forma létezik: a több állományt tartalmazó tekercs és a több tekercsből álló állomány. Az utóbbi viszonylag ritkán, speciálisan nagy (pl. egy ország népességét nyilvántartó) állományok esetében fordul elő. Az állományok többsége általában a mintegy 800 méter hosszú tekercsnek csak egy töredékét foglalja le, ezért egy tekercsen több állomány is tárolható. Ebben az esetben azonban már nyilván kell tartani, hogy melyik állomány melyik tekercsen található. Ezt a tekercs és az állományok elején elhelyezett jegyzékek, szakszóval címkék (angolul: labels) segítségével oldják meg, amelyek tulajdonképpen maguk is speciális, az operációs rendszer által automatikusan kezelt állományok. A címkék az állományok nevén és szalagon elfoglalt pozícióján kívül egyéb adatokat is tartalmazhatnak (például az írás dátumát, az állomány hosszát stb.). A mágnesszalagos adattárolás több szempontból igen nehézkes. Az állományok csak szekvenciálisan, felírásuk sorrendjében érhetők el, ami leküzdhetetlen akadályt jelent például akkor, amikor egyetlen tekercsről két állományt kell felváltva olvasni. Az állományok minden módosítása a teljes állomány átmásolását igényli, ami igen időigényes lehet. Ezért nem csoda, hogy a mágneslemezek megjelenésekor a szalagok főleg archívum jellegű tömegtárolókká degradálódtak.
E szerepük azonban ma is megvan, sőt a személyi számítógépekhez speciális mágnesszalagos tárakat készítettek a lemezes tárak tartalmának biztonsági mentésére, illetve archiválására. A mágneslemezek a fenti problémák nagy részét megoldották, és ezért ma már jóformán minden számítógépes rendszer ezekre támaszkodik. Két nagy csoportjuk a cserélhető és a fixlemezek. Emellett a cserélhetők merevek és rugalmasok (floppy) lehetnek. Az előbbi általában a nagy- és kisgépekre, az utóbbi a személyi számítógépekre jellemző. Míg a rugalmas lemezek kétoldalasak, a merev lemezek gyakran több (általában 10), párhuzamos, egymáshoz rögzített lemezből álló csomagot alkotnak. A jelenleg tömegesen elterjedt fixlemezek között a legkorszerűbb a személyi számítógépekhez kifejlesztett Winchester típusú háttértár (a hasonló nagygépes eszköz miniatürizálásával). A mágneslemezeken az adatokat speciális módszerekkel tárolják. Általában megkülönböztetnek fizikai és logikai tárolási szerkezetet. Kezdjük a fizikai szerkezettel! Minden mágneslemezen párhuzamos pályákat (angolul: track), más elnevezéssel sávokat jelölnek ki, amelyek a lemez szélétől befelé haladva egyre kisebbedő koncentrikus körök. A pályák száma 35 és olykor pár 1000 között változik. A pályákat rövidebb szakaszokra, ún. szektorokra osztják. Ezek száma általában 4 és 40 között van. A szektor a lemez legkisebb, önállóan írható--olvasható fizikai egysége, kapacitása 32 bájttól egészen 4 Kbájtig terjedhet. A lemezen a címzés tehát a pálya és ezen belül a szektor sorszámát jelenti. A többlemezes csomagok esetében az azonos pozíciójú pályákat együtt cilindernek hívják. Ezek jelentősége abban áll, hogy a csomag egy cilinderének összes pályája elérhető az író--olvasó fejek mozgatása nélkül. A lemezen egy szektor elérése két "ütemben" megy végbe: először a fej beáll a kívánt pályára (keresési idő), majd ott megvárja, hogy a keresett szektor odaérjen (késleltetési idő). Lemezcsomagok esetében a fej beállása után nemcsak két sávon, hanem a teljes cilinderen levő összes szektor újabb keresési idő nélkül érhető el. A külső tárakban előreláthatólag nagy előrelépést jelent majd a nemrég megjelent, ún. CD (Compact Disc)-lemez, amely lézerrel készül és lézerrel olvasható. Egy 12 cm átmérőjű, 1,2 mm vastag műanyag lemez kapacitása 550 Mbájt, ami mintegy 1500 darab hajlékony lemezt jelent. Az elérési idő jelenleg 2-3 másodperc, ami várhatóan csökkenni fog. A CD-lemez egyelőre csak ROM típusú tárként alkalmazható, de már előrehaladott kísérletek folynak írható-olvasható- módosítható CD-lemezek előállítására is. A mágnesszalaggal szemben a lemeznek több előnye van, melyek közül számunkra különösen kettő érdekes: a szektorok tartalma címzés szerint tetszőleges sorrendben elérhető és saját helyén módosítható. A lemezek e tulajdonságát közvetlen elérésnek (angolul: direct access) nevezik. A közvetlen elérés természetesen nagymértékben gyorsítja az adatátvitelt. A keresési és késleltetési idő együttesen átlagosan csak ezredmásodperc nagyságrendű, ami hihetetlenül nagy előrelépést jelentett a szalagokhoz képest. Mivel a lemezen az állományváltás is csak címzés kérdése, a keresést itt tartalomjegyzék, más néven katalógus, segítségével oldják meg. Minden lemezhez vagy lemezcsomaghoz külön katalógus tartozik, amelynek tartalma a különböző rendszerekben is többé-kevésbé azonos (l. később), és a lemez rögzített helyén található. A tényleges adatátvitellel kapcsolatban fontos kérdés, hogy az írás és olvasás mekkora egységekben menjen végbe. A hardver szempontjából a helyzet egyszerűnek tűnik: az egyszerre átvihető adatmennyiséget a szektorméret egyértelműen meghatározza. Ezt fizikai blokkméretnek nevezik, és hossza bájtokban kifejezhető (egy tipikus érték 512 bájt). A felhasználó azonban saját, alkalmazásonként változó hosszúságú rekordjaival (logikai blokkjaival) dolgozik, amelyből esetenként több is elférhet egy fizikai blokkban, de az is lehet, hogy több fizikai blokk kell egy rekord tárolására. Az alapvető B/K műveletek blokkokkal dolgoznak. A rekord --> blokk leképezést szoftver úton kell megoldani, amit vagy az operációs rendszer vagy az alkalmazási
program végez el. A blokkosított és ezért egységes adatátvitel ára bizonyos mértékű belső elaprózódás, ami abból adódik, hogy a rekordhossz általában nem osztója (vagy nem többszöröse) a fizikai blokkhossznak. A belső elaprózódás a blokkhosszal együtt növekszik. 11.2.1. Állományokon végezhető műveletek Az állomány -- mint absztrakt adattípus -- fogalma csak akkor lehet teljes, ha meghatározzuk a rá vonatkozó műveletek körét is. Elegendő néhány alapművelet megadása, s ezekből azután további, összetett tevékenységek is felépíthetők. A mai mágneslemezes rendszerekben általában a következő öt állományművelet (adatkezelési művelet) képezi az alapot: * Állomány-létrehozás: ami egyrészt fizikai helykijelölést, másrészt a katalógus bővítését jelenti. * Írás: amely adott állomány adott című blokkjára vonatkozik. A cím megadását gyakran egy mutató segítségével oldják meg, amely mindig az állomány aktuális blokkjára mutat (állománymutató). A művelet az állománymutatót automatikusan a következő blokkra állítja át, s ez a szekvenciális írást egyszerűsíti. * Olvasás: amely szintén egy blokkra vonatkozik. A címkezelés azonos az írásnál leírtakkal. * Pozicionálás: az állománymutató értékének beállítása. Ez a művelet a blokkok közvetlen elérését teszi lehetővé. Általában valamilyen védelmi mechanizmus szolgál az állomány aktuális területén kívül eső cím beállításának megakadályozására. * Állomány törlése: ami egyrészt a lefoglalt tárolóhely felszabadítását, másrészt a katalógus módosítását jelenti. Ezek az alapműveletek a legtöbb esetben további, a felhasználót támogató lehetőségekkel bővülnek. Ilyen lehet az állományok logikai elnevezése, amit csak a konkrét program futása során kell (a katalógusban szereplő vagy oda kerülő) fizikai állománynévhez kapcsolni. A megfeleltetést például állományvezérlő táblában (angol rövidítése: FCB = File Control Block) tárolják az operációs rendszer területén. A megfeleltetés bármikor létrehozható és megszüntethető, a létrehozást általában az OPEN vagy ASSIGN, a megszüntetést pedig a CLOSE művelet végzi, mint erről korábban már volt szó. A műveletek szokásos bővítései lehetnek még: az állományok fizikai nevének megváltoztatása, bizonyos pozicionálások (pl. az állomány elejére vagy végére állás), kiemelések, az állomány tartalmának törlése stb. A kényelmes alkalmazói rendszerek természetesen nem blokkokban, hanem rekordokban vagy más logikai állománykomponensekben bonyolítják le a műveleteket, ami az alaprendszerre épülő, további szoftverréteg(ek)et jelent.
11.2.2. Katalógusok és katalógusrendszerek Már az eddigiekből is láthattuk, hogy a katalógusok központi szerepet játszanak az állományok kezelésében. Lemezes állományoknál a katalógus általában a következő adatokat tartalmazza: * * * * * * * *
az állomány fizikai neve, az állomány típusa, az állomány címe a lemezen, az állomány mérete, az aktuális állománypozíció, védelmi információ (hozzáférési jogok), az állományt felhasználó folyamatok száma, különböző időadatok (létrehozás, utolsó módosítás stb.).
A katalógus mérete nagyobb számítógépes rendszereknél több száz kilobájt is lehet, ezért a benne való keresés problémája nem elhanyagolható. A lineáris keresés igen lassú, amit a katalógus rendezésével kiválthat a sokkal gyorsabb bináris keresés. Ennek hátránya, hogy viszonylag bonyolult algoritmust igényel. Előre rögzített katalógusméret esetén (ami a lemezen tárolható állományok számát korlátozza) jó eredményt ad az állománynevek egész számokra (katalógusbeli címekre) való egyértelmű leképezése (angolul: hashing) is. A katalógusokkal kapcsolatban a problémák az állományok számának növekedésével nemcsak a keresésnél jelentkeznek. Különösen a többfelhasználós rendszereknél nem szabad kizárni azt, hogy a katalógusban több, azonos nevű állomány szerepeljen. Ezt "egyszintű" katalógusokkal nem lehet megoldani, ezért ma már általában ún. többszintű katalógusrendszereket alkalmaznak. Ezek közül a legegyszerűbb a kétszintű katalógus, melyben minden felhasználónak (ezek neve szerepel a katalógus felső szintjén) külön katalógusa van, a közös használatú állományokat pedig külön "rendszerkatalógusban" tartják nyilván. A következő, ma már általánosan elterjedt megoldás a fastruktúra, amely azon alapul, hogy a katalógust speciális állománytípusnak tekintik. A teljes rendszer ún. gyökérkatalógussal indul, amelyben közönséges állományok és további katalógusok leírásai szerepelhetnek. Ha ezt minden katalógusban így szervezzük, a 11.1. ábrához jutunk, ahol a fa levelei jelzik a közönséges állományokat.
0.SZINT
1.SZINT
2.SZINT
3.SZINT
GYÖKÉR | +----+----+----+ | K1 | K2 | K3 | +----+----+----+ / | \ / | \ / | \ +----+----+----+ / +----+----+ \ +----+----+----+----+ | A1 | K4 | A2 |/ | A3 | A4 | \| K5 | K6 | A5 | A6 | +----+----+----+ +----+----+ +----+----+----+----+ | | | | | / \ | | (_) | (_) (_) (_) / \ (_) (_) | / \ | / \ +----+----+----+----+ +----+----+----+ +----+----+----+ | K7 | A7 | A8 | K8 | | A9 | K9 | A10| | A11| A12| A13| +----+----+----+----+ +----+----+----+ +----+----+----+ | | | \ | \ | | | | | (_) (_) \ (_) \ (_) (_) (_) (_) | \ \ | \ \ +----+----+----+ +----+ +----+----+ K = KATALÓGUS | A14| A15| A16| | A17| | A18| A19| +----+----+----+ +----+ +----+----+ A = ÁLLOMÁNY | | | | | | (_) (_) (_) (_) (_) (_) 11.1. ábra. Fa-struktúrájú katalógusrendszer
Minden állományhoz egy, a gyökértől induló út vezet, ami az állományt akkor is azonosítja, ha a neve csak az őt közvetlenül tartalmazó katalóguson belül egyértelmű. Minden felhasználóhoz egy pillanatnyilag aktuális katalógust lehet rendelni, az egyik katalógusból a másikba való átkerülés pedig (bizonyos megszorításokkal) a felhasználó hatáskörébe tartozik. Mivel a katalógusok létrehozása és megszüntetése szintén a felhasználó kezében van, saját állományaiból is tetszőleges mélységű fa-struktúrát szervezhet, tehát különböző katalógusaiban használhat azonos nevű állományokat is. A 11.5. pontban egy konkrét fa-szerkezetű állományrendszert mutatunk be, jóllehet az MS-DOS kapcsán már láttunk ilyet. A hierarchikus katalógusok legfontosabb szerepe: az alkalmazók és az alkalmazások szétválasztása. Gyakran szükség van arra, hogy egy állomány több katalógusban is szerepelhessen. Ezt vagy az állomány több példányban való tárolásával vagy egy speciális katalógusbeli bejegyzéssel oldják meg, amit kapcsolatnak (angolul: link) neveznek. Ezután a katalógusokban már háromféle bejegyzés szerepelhet: közönséges állományok, katalógusok és kapcsolatok leírásai. A kapcsolat tulajdonképpen egy állományra hivatkozó mutató, amely az állomány tényleges másolatát pótolja. A kapcsolatok segítségével egy állomány több különböző úton is elérhető (11.2. ábra).
0.SZINT
1.SZINT
2.SZINT
GYÖKÉR | +----+----+----+ | K1 | K2 | K3 | +----+----+----+ / | \ / | \ +----+----+----+ +----+----+ +----+----+----+ | A1 | KL4| L1 | | A2 | A3 | | L2 | K5 | A4 | +----+----+----+ +----+----+ +----+----+----+ | \ \ | | / / | (_) \ *--->(_) (_)<---* / (_) \ / *>---------------->* / \ / K = KATALÓGUS +----+----+----+ L = LINK (KAPCSOLÁS) | A5 | A6 | A7 | A = ÁLLOMÁNY +----+----+----+ | | | (_) (_) (_) 11.2. ábra. Fa-struktúra kapcsolatokkal
A faszerkezetű állomány-nyilvántartó rendszer a kapcsolatok miatt általános, ún. ciklusmentes gráffá vált, ami lehetővé teszi, hogy a felhasználók igényeik szerint alakítsanak ki közös és saját állománycsoportokat. A több kapcsolattal rendelkező állományok bevezetésével egyes állományműveletek bonyolultabbá válnak. Egy állomány például ténylegesen csak akkor törölhető, ha már minden kapcsolata törlődött. Ha a kapcsolatokat nem önálló katalóguselemként, hanem a már meglévő állományok újabb attribútumaként valósítjuk meg, kevesebb csomópontból álló, ún. általános egyszerű gráfhoz jutunk, amely azonban a ciklusok veszélyét hordozza magában. A gráfban akkor beszélünk ciklusról, ha a kapcsolatok egyszer már érintett csomópontra vezetnek vissza. A szokásos gráfbejárási módszerek ciklikus esetben csődöt mondanak, a különböző cikluselkerülő, illetve ciklusfelderítő algoritmusok pedig meglehetősen bonyolultak és időigényesek. 11.2.3. Elérési módszerek Mivel az állományokban nagy adattömegeket tárolunk, az adatok elérésére használt módszer nem lehet közömbös. Sok esetben az operációs rendszer csak egyféle elérést támogat (ilyen esetekben az alkalmazási rendszerek tartalmazzák az erre épített speciális elérési technikát), de az is gyakori, hogy már alacsony szinten is több elérési módszer között válogathatunk (ilyen pl. az IBM OS). Az elérési módszerek két alaptípusa a szekvenciális vagy soros és a direkt vagy közvetlen elérés. Szekvenciális elérésnél az állomány blokkjai kizárólag felírásuk sorrendjében olvashatók vissza, tehát a 149. blokk csak az első 148 elolvasása után érhető el. Ezen csak kicsit egyszerűsít az esetleg rendelkezésre álló, adott számú blokkot előre vagy hátrafele kihagyó művelet. Mágnesszalagon egyedül a soros elérés használható, de lemezek esetében természetesen csak akkor alkalmazzák, ha a munka nem igényel más módszert, (a tapasztalatok szerint azonban még ma is az esetek több mint felében a szekvenciális feldolgozás a jellemző).
A közvetlen elérés lényege, hogy tetszőleges sorszámú blokk írása vagy olvasása megengedett. Ezt a gyakorlatban vagy állománymutatóval és külön pozícionáló utasításokkal oldják meg, vagy az író és olvasó műveletek paramétereként adható meg a kívánt blokk sorszáma. Nem szorul külön bizonyításra, hogy a legtöbb alkalmazás igényel közvetlen hozzáférést. A közvetlen elérési módszerre további módszerek építhetők. Nagy állományoknál például a kulcs szerinti keresést ún. indextábla segítségével oldják meg. Az indextábla olyan szótár, amely az egyes kulcsértékekhez megadja azon blokk sorszámát, amelyben a kérdéses kulcs szerepel. Az elérés így két lépésre bontható: először meg kell keresni a kulcsot az indextáblában, majd az innen kapott blokksorszámmal közvetlenül elvégezhető a művelet. Ha a kulcsok száma nagy, többszintű indextáblát szoktak alkalmazni. Erre jó példa az IBM ISAM (Indexed Sequential Access Method=Index-szekvenciális elérési módszer) rendszere. Az ISAM-ban egy kis főindextáblát a tárban tartanak, melynek elemei a lemezen tárolt ún. másodlagos indextábla blokkjaira mutatnak. A másodlagos tábla egy blokkjában több mutató van, melyek már a tényleges állomány blokkjait jelölik ki. Magát az állományt egy kulcs szerint rendezve tartják. Ha el akarunk érni egy adott kulcshoz tartozó rekordot, először a főindex bináris keresésével meghatározzuk a másodlagos index egy blokkját. Ezt beolvasva újra bináris keresést kell végezni, ami egy adatblokk címét eredményezi. Az adatblokk behozatala után már a soros keresés is elegendő a kívánt rekord eléréséhez. A módszer azt teszi lehetővé, hogy egy kis rezidens indextáblával és legfeljebb két direkt olvasással bármely rekord elérhető. 11.2.4. Háttértár-kiosztási módszerek Az állományok gyakorlati megvalósításához -- a felhasználó által már nem látható szinten -- a tárolóterület állományok közötti fizikai felosztása is hozzátartozik. A probléma nyilván csak mágneslemez esetében merül fel, szalagoknál a lehetőségek igen korlátozottak, mert műszakilag nincs megoldva, hogy a szalagról leolvasott blokkot pontosan ugyanarra a helyre vissza lehessen írni. Lemezes állományoknál lehetőleg úgy kell a területeket az állományokhoz rendelni, hogy a lemez kapacitását jól kihasználjuk, és az adatok elérése a lehetőségekhez képest gyors legyen. A lemezterület kiosztására három alapvető módszer terjedt el: a folytonos, a láncolt és az indexelt. Mindegyik kiosztási módszerben fontos szerepet játszik az ún. szabadhely-kezelés, a foglalt és még nem foglalt blokkok nyilvántartása, amit általában szabadhely-listának neveznek, és többféleképpen valósítanak meg. A szabadhely-listát gyakran bittérképpel reprezentálják, ahol minden blokknak egy bit felel meg. Az 1 a foglalt, a 0 a szabad blokkot jelöli. Más módszerek a szabad blokkokat listára fűzik oly módon, hogy minden szabad blokk egy mutatót tartalmaz, amely a következő szabad blokkra utal. A lista úgy is szervezhető, hogy elemei egy címből és egy számlálóból álljanak; a számláló az egymás utáni szabad blokkok számát tartalmazza. A folytonos kiosztás megköveteli, hogy minden állomány egymás után következő blokkok sorozatát foglalja el. A helyfoglalás a katalógusban kezdőcímmel és az elfoglalt blokkok számával (az állomány hosszával) adható meg (11.3. ábra).
.---------------------------. ( [ F = FOGLALT ] ) |*---------------------------*| | +---+ +---+ +---+ +---+ | | 0 | F | | F | | F | | F | | | +---+ +---+ +---+ +---+ | | | | +---+ +---+ +---+ +---+ | | 4 | | | | | F | | F | | | +---+ +---+ +---+ +---+ | | | | +---+ +---+ +---+ +---+ | | 8 | F | | F | | | | | | | +---+ +---+ +---+ +---+ | | | | +---+ +---+ +---+ +---+ | | 12 | | | | | | | | | | +---+ +---+ +---+ +---+ | | | | +---+ +---+ +---+ +---+ | | 16 | F | | F | | F | | | | | +---+ +---+ +---+ +---+ | | | | +---+ +---+ +---+ +---+ | | 20 | | | | | | | | | | +---+ +---+ +---+ +---+ | | | | +---+ +---+ +---+ +---+ | | 24 | | | | | F | | F | | | +---+ +---+ +---+ +---+ | | | | +---+ +---+ +---+ +---+ | | 28 | F | | F | | F | | F | | ( +---+ +---+ +---+ +---+ ) *---------------------------*
KATALÓGUS ÁLLOMÁNY
KEZDET
HOSSZ
A1
0
4
A2
16
3
A3
10
4
A4
26
6
11.3. ábra. Folytonos helykiosztás a lemeztárakon A folytonos kiosztás első problémája a megfelelő méretű szabad terület megkeresése, ami a szabadhely-lista valamilyen feldolgozását igényli. A feladat általános megoldása a dinamikus kiosztás, amely több szabad szegmensből, ún. lyukból elégíti ki valamilyen algoritmus alapján az igényt. A legegyszerűbb az igényt az első elég nagy lyukból kielégíteni, aminek az a hátránya, hogy a lyukak mérete állandóan csökken. Az összes lyuk számbavétele után ki lehet választani azt a legkisebbet, amelyik már alkalmas az igény kielégítésére. Ez gazdaságosabb tárkihasználást, de hosszabb keresést igényel. Érdekes módon a legnagyobb lyuk választása is gazdaságos lehet, mert így több esély van arra, hogy a maradék lyuk még használható. Statisztikai mérések azt mutatják, hogy az első két módszer általában jobb, mint a harmadik, de egyik sem ad megfelelő tárkihasználást. Az algoritmusok közös hibája a külső elaprózódás. Ez azt jelenti, hogy a szabad terület egy idő után sok kis darabra osztódik. Ez ellen egy tömörítő program időszakonkénti futtatásával szoktak
védekezni, amely az állományok másolásával az összes szabad területet egyesíti. A folytonos kiosztás igazán komoly hiányossága, hogy az állományok általában nem bővíthetők, mert lehet, hogy mindkét végükön foglalt terület van. A létrehozáskor adott méretbecslés meglehetősen kényelmetlen, gyakran túlbiztosításhoz vezet, és -- a lassan gyarapodó állományok esetén -- feleslegesen köt le tároló-területet. A fenti problémákat megoldja a láncolt kiosztás, amikor minden állomány blokkok láncolt listája, s, ezek a lemezen tetszőleges összevisszaságban helyezkedhetnek el. A katalógus az első és az utolsó blokkra utaló mutatót tartalmaz, az állomány minden blokkjában megtalálható a következő blokk sorszáma (címe), amint ez a 11.4. ábrán látható. .---------------------------. ( ) |*---------------------------*| | +---+ +---+ +---+ +---+ | | 0 | | | | | | | | | | +---+ +---+ +---+ +---+ | | .<----------------------<. | +---+ +-/-+ +---+ +---+ | \ | 4 | | |10 | | | |15 | | \ KATALÓGUS | +---+ +-\-+ +---+ +/-\+ | \ | *--. *-* \ \ | +---+ +---+ +\-/+ +---+\ | ÁLLOMÁNY \ KEZDET VÉG | 8 | | | | | 7 | | | *| \ | +---+ +---+ +---+ +---+/ | A1 *<5 30 | / | / | +---+ +---+ +---+ +--/+ | / | 12 | | |16 | | | |17 | | / | +---+ +/|-+ +---+ +/--+ | / | .-* | .-------* | / | +--/+ +-|/+ +---+ +---+ | / | 16 |22 | |13 | | | | | | / | +--\+ +---+ +---+ +---+ | / | *-------. | / | +---+ +---+ +\--+ +---+ | / | 20 | | | | |30 | | | | / | +---+ +---+ +/--+ +---+ | / | / | / | +---+ +---+.+---+ +---+ | / | 24 | | | ||| | | | | / | +---+ +---+*+---+ +---+ | / | \ .<-----------------<* | +---+ +---+ +\/-+ +---+ | | 28 | | | | |-1 | | | | ( +---+ +---+ +---+ +---+ ) *---------------------------* 11.4. ábra. Láncolt helykiosztás a lemeztárakon Figyeljük meg, hogy az állomány utolsó blokkjában a mutató értéke (-1) is jelzi a lánc végét. Ennél a módszernél nem probléma az állomány bővítése, csak el kell venni a szabadhely lista
következő elemét és beláncolni a állomány végére. Hasonló módon, a külső elaprózódás sem léphet fel, minden állomány pontosan annyi blokkot kap, amennyit igényel. Az, hogy ennek ellenére sem a láncolt kiosztás az egyedüli módszer, annak köszönhető, hogy csak szekvenciális állományok esetén biztosít megfelelő hatékonyságot, hiszen minden blokk eléréséhez elölről kezdve be kell járni az összes őt megelőző blokkot. Ha ehhez még hozzávesszük a sok mutató által elfoglalt területet, valamint azt, hogy az állomány igen könnyen sebezhető (ha megsérül egy mutató, az állomány többi része hozzáférhetetlenné válik), természetesnek tűnik egy jobb kiosztási módszer kidolgozása. Az indexelt kiosztás úgy oldja meg az adatok közvetlen elérésének problémáját, hogy a mutatókat az adat blokkokból kiemelve, egy ún. indexblokkba tömöríti. Az indexblokk i-edik (a továbbiakban i.) eleme az állomány i. blokkjára mutat. A állomány létrehozásakor a mutatók még "sehova sem mutatnak", értékük például -1, amint ez a 11.5. ábrán is látható. .---------------------------. ( [ F = FOGLALT, I = INDEX ] ) |*---------------------------*| | +---+ +---+ +---+ +---+ | | 0 | | | | | | | | | | +---+ +---+ +---+ +---+ | | | | +---+ +---+ +---+ +---+ | KATALÓGUS | 4 | | | F | | | | F | | | +---+ +---+ +---+ +---+ | ÁLLOMÁNY INDEXBLOKK | | | +---+ +---+ +---+ +---+ | A1 19 | 8 | | | | | F | | | | / | +---+ +---+ +---+ +---+ | / | | / | +---+ +---+ +---+ +---+ | / | 12 | | | F | | | | F | | / | +---+ +---+ +---+ +---+ | / | .<-----------------<* | +---+ +---+ +---+ +--/+ | +-------+ | 16 | F | | F | | | | I >>>>>>>>>| 5 | AZ INDEXBLOKK | +---+ +---+ +---+ +---+ | | 10 | | | | 7 | TARTALMA | +---+ +---+ +---+ +---+ | | 15 | | 20 | | | | | F | | | | | 17 | | +---+ +---+ +---+ +---+ | | 13 | | | | 16 | | +---+ +---+ +---+ +---+ | | 22 | | 24 | | | | | | | | | | 30 | | +---+ +---+ +---+ +---+ | | -1 | | | | -1 | | +---+ +---+ +---+ +---+ | | -1 | | 28 | | | | | F | | | | | -1 | ( +---+ +---+ +---+ +---+ ) | -1 | *---------------------------* +-------+ 11.5. ábra. Indexelt helykiosztás a lemeztárakon
A katalógus az indexblokk címét tárolja, ami az állományműveletek alatt a tárban tartózkodik. Ez a megoldás már majdnem tökéletes, egyetlen probléma az indexblokk méretével van, mivel ebben nemcsak a létező, de az egyáltalán létrehozható indexeknek kell helyet biztosítani, ami mindenképpen pazarlással jár. Nagyobb állományok esetén lehet, hogy egy fizikai blokk nem elegendő az indexek számára, hanem indexblokkok láncolt listáját kell használni. A láncolás és az indexelés kombinációja adja a kiosztási probléma általános megoldását.
11.3. Adatvédelmi rendszerek A számítógépes rendszerben tárolt adatok védelme kétirányú: az adatokat védeni kell a fizikai sérüléstől (véletlen vagy szándékos rongálástól, balesettől) és a jogtalan hozzáféréstől. A sérüléstől való védelemmel részleteiben nem foglalkozunk, jóllehet ehhez vannak operációs rendszeri eszközök is. Az ebből eredő problémát általában több példány előállításával és azok rendszeres ellenőrzésével oldják meg. Az operációs rendszerek számára védelem főleg a jogtalan hozzáférés kizárását jelenti, ami nagymértékben függ a számítógépes rendszer működési környezetétől. Személyi számítógépek esetén például a védelem megoldható a cserélhető lemezek biztonságos őrzésével, de többfelhasználós rendszer esetén más módszerekre van szükség. Az általános megoldás szerint az állományokra vonatkozó bizonyos műveleteket (pl. olvasás, írás, végrehajtás, másolás, törlés stb.) az operációs rendszer csak korlátozó feltételek teljesülése esetén enged végrehajtani. A különböző védelmi rendszerek más és más feltételeket igényelnek. A legegyszerűbbek közül való az operációs rendszerbe való bejelentkezésnél is gyakran használt jelszó. Az állományokhoz jelszavakat lehet rendelni, a védett műveleteket csak a jelszó ismeretében kezdeményezheti a felhasználó. Ha a jelszavakat gyakran változtatják, a védelem elég megbízható lehet. Egy másik megközelítés a hozzáférést a felhasználó személyétől teszi függővé. Az állományokhoz vagy a katalógusokhoz egy -- a hozzáférésre jogosultakat tartalmazó -- névsor kapcsolható, amit a rendszer ellenőriz. Az állományok védelmének külön fejezetét alkotják a hajlékony lemezen rögzített, szerzői joggal védett, személyi számítógépen működő programok másolását akadályozó módszerek. Itt általában nem állományokat, hanem teljes lemezeket kell védeni. A megoldások igen változatosak, de általában a fizikai szintű lemezkezelés speciális, a felhasználók többsége által nem ismert sajátosságain vagy a lemezen lévő szoftverbe épített csapdákon vagy az utóbbi időben sajnálatosan terjedő kifejezetten rongáló rutinokon (számítógépes vírusok) alapulnak.
11.4. Háttértárak kezelése A számítógépek hasznos teljesítménye nemcsak a többfelhasználós nagy rendszereknél, hanem a személyi használatú gépeknél is nagymértékben függ a háttértár -- elsősorban a mágneslemez -sebességétől. Mint ezt a 10. fejezetben láttuk, a lemezek a hatékony tárkezelés nélkülözhetetlen eszközei, tehát nemcsak a felhasználó adatainak tárolása, hanem a teljes rendszer működése szempontjából is igen fontos szerepet játszanak. Ezért a lemezegységeket a többi alapvető
erőforráshoz hasonlóan minél jobb kihasználtságot biztosító módszerekkel ütemezik. Az ütemezők itt is a már megszokott -- az igényeket tartalmazó várakozási sorok alapján működnek. A lemezt igénylő folyamat a következő adatokat közli: * * * *
A művelet típusa (írás/olvasás) A lemezen elérendő cím (pl. meghajtó, pálya, szektor) A tárcím Az átvitelre kerülő adatmennyiség (blokkok vagy bájtok)
Ha a kért vezérlő vagy meghajtó foglalt -- és általában ez a helyzet -- az igény a várakozási sorba kerül. A sorok feldolgozására három algoritmus vált általánosan használttá. 11.4.1. FCFS ütemezés Ezt az algoritmust már a processzorkezelésnél megismertük (9.3.1. pont), elve igen egyszerű és igazságos: a korábban bejelentett igény előbb teljesül. Egyetlen komoly hibája, hogy a sor kiszolgálásához szükséges író/olvasófej mozgatások átlagos összege általában távolról sem optimális. Tegyük fel például, hogy a sorban a következő pályacímek szerepelnek: 90, 180, 35, 120, 14, 60, 100 Ha a fej a 30. pályáról indul az FCFS alapján 572 lépést kell a fejnek megtenni, ami a nagy odavissza mozgások miatt igen sok. Nem igényel különösebb találékonyságot egy ennél jobb ütemezés kidolgozása. 11.4.2. Legközelebbi előnyben Az FCFS algoritmus lényegesen javítható, ha a soronkövekező helyett mindig azt az igényt elégítjük ki, amelyhez a fej éppen a legközelebb van. Az algoritmust angol nevének (ShortestSeek-Time-First) rövidítésével SSTF-nek is nevezik. Az előző példánál maradva könnyen belátható, hogy a fej mozgatás közel harmad részére (192 lépés) csökkent. Az SSTF tulajdonképpen a 9.3.2. pontban bemutatott SJF algoritmus egy változata, amiről tudjuk, hogy a kiéheztetés (9.3.3. pont) veszélyét hordozza magában. Egy távoli pályára a fej "soha" nem jut el, ha közben állandóan közelebbi pályákra vonatkozó igények futnak be. Bár az algoritmus sokkal jobb eredményt ad, mint az FCFS, nem optimális, javítása viszont már nem gazdaságos. 11.4.3. A SCAN algoritmus Alapelve az, hogy a fej a két végállása között ide-oda jár és útja során minden pályánál elintézi az esetleg erre a pályára várakozó igényeket. A módszer láthatóan a dinamikusan változó, a lemezen egyenletesen eloszló igényeknek kedvez. Előnye, hogy a kiéheztetés veszélye nem áll fenn és megvalósítása elég egyszerű. A gyakorlatban természetesen a fejet nem kell okvetlenül a végállásig elvinni, ha már egy igény sincs előtte, vissza lehet fordulni. A 11.4.1.-ben szereplő példában, ha a fej éppen a 0. pálya felé mozog, 210 lépést igényel a sor feldolgozása. Ez kicsit rosszabb, mint az SSTF volt, de könnyen lehetne a helyzet fordított is.
11.5. Mintapéldák Az állományok kezelésének korszerű és az utóbbi időben több más operációs rendszerben is alkalmazott megoldását tartalmazza a UNIX rendszer. Az alapötlet igen egyszerű: a rendszerben tartott minden információ állományokban helyezkedik el, legyen az forrásprogram, bináris program, egy felhasználó által írt levél vagy az operációs rendszer egy fizikai B/K rutinja. A rendszer számára minden állomány bájtok sorozata, melyek akár egyenként is hozzáférhetők. Az állományok nyilvántartását fa-szerkezetű katalógusrendszer biztosítja. A fa csomópontjai állományok, melyek vagy szintén katalógusok (ezekből újabb ágak indulnak ki) vagy közönséges állományok (ezek levelek). Maga a teljes UNIX operációs rendszer is itt tárolódik. A rendszer gyökere az ún. "root" katalógus, amelyben a többi között a következő katalógusok találhatók: bin: lib: usr: dev:
bináris rendszerprogramok könyvtári programok a felhasználók katalógusai külső egységeket kezelő programok leírásai.
Minden felhasználó a usr katalógusban kap saját báziskatalógust, ahol állományait tárolhatja. A bázis katalógus szerkezetének és tartalmának formálása a tulajdonos kizárólagos hatáskörébe tartozik. Katalógusok létrehozására és megszüntetésére egyaránt jogosult. Az egyes állományokra a hozzájuk a gyökértől vezető úttal hivatkozhatunk. Ha például F1 egy felhasználó neve, akkor báziskatalógusának neve root/usr/F1, amit /usr/F1-nek rövidíthetünk, mivel megállapodás szerint a gyökér nevét az első / helyettesíti. Ha az F1 felhasználó ír egy P1 nevű programot azt elhelyezheti a báziskatalógusába a következő néven: /usr/F1/P1. A hosszú állományhivatkozások rövidítésére bevezették az aktuális katalógus fogalmát. Bejelentkezéskor minden felhasználó a saját báziskatalógusába kerül és ezen belül a hivatkozási utakat csak innen kezdve kell megadnia (pl. P1 lesz a fenti program neve). Ezeket nevezzük relatív útneveknek. Az aktuális könyvtár kijelölésére külön utasítás szolgál. Több felhasználó által közösen használt állományok többszörös tárolásának elkerülésére a UNIX-ban megvan a link létesítés lehetősége, azaz egy állományt több katalógushoz is hozzákapcsolhatunk (l. 11.2.2. pont). Az állományvédelmet a UNIX-ban a felhasználók személyére alkalmazott hozzáférési korlátozásokkal oldották meg. Minden állományra háromféle engedély adható: olvasási (r), írási (w) és végrehajtási (x). Az x engedélynek természetesen csak programok esetén van értelme, katalógusok esetében pedig a katalógusban való keresési jogot kódolják vele. A felhasználókat az állományok szempontjából három kategóriába osztják: tulajdonos, egy kijelölt csoport és az egyéb felhasználók. Mindhárom engedély az összes kategóriára egymástól függetlenül szabályozható (megadható vagy megtagadható), így egy állomány hozzáférési státuszát 9 bittel lehet jellemezni. Egy állomány létrehozásakor a UNIX ésszerű alapértéket állít be, amit a tulajdonos bármikor megváltoztathat. Az állományok általános kezelését (másolás, listázás, átnevezés, átvitel egyik katalógusból a másikba, összehasonlítás, adott bájt-sorozat keresése, rendezés, stb.) jól használható, egyszerű, programkönyvtári parancsok végzik (ld. 2.2.-t is). A UNIX hatása jól látható a CP/M és az MS-DOS rendszereken, melyek állományszerkezete lényegében ugyanez. Mivel ezek egyfelhasználós rendszerek, az állományok kapcsolataira és a hozzáférési jogok szabályozására nem volt szükség, így azokat kihagyták.
11.6. Gyakorlatok 11.6.1.
Hasonlítsuk össze a mágnesszalagos és a mágneslemezes háttértárat! 11.6.2. Adjunk példákat olyan alkalmazásokra, ahol az adatok szekvenciális, illetve közvetlen elérésére van szükség.
11.6.3.
Mi a katalógusok szerepe az állományrendszerben? 11.6.4. Milyen védelmi problémák merülnének fel, ha a katalógusokat minden felhasználó egyaránt módosíthatná?
11.6.5.
Milyen szerkezetű katalógusokat ismer?
11.6.6.
Hogyan lehet egy állományt több felhasználó számára elérhetővé tenni?
11.6.7.
Melyek a legfontosabb állományvédelmi módszerek?
11.6.8.
Értékelje röviden a háttértár kiosztási módszereket!
11.6.9.
Tekintsünk egy 100 blokkból álló állományt. Hány B/K műveletre van szükség folytonos, láncolt és indexelt módszerrel, ha egy blokkal a következő műveletet végezzük: a) b) c) d) e) f)
Beszúrjuk az állomány elejére. Beszúrjuk az állomány közepére. Beszúrjuk az állomány végére. Töröljük az állomány elejéről Töröljük az állomány közepéről. Töröljük az állomány végéről.
11.6.10. Minden állomány rendszerben lehetőség van állományok törlésére. Milyen alapvető különbséget kell tenni katalógusok és egyéb állományok törlése között? 11.6.11.
Mi az indexelt szekvenciális adat-elérés lényege?
11.6.12.
Mikor lép fel a lemezterület elaprózódása és hogyan lehet ellene védekezni?
11.6.13.
Érdemes lehet-e egyfelhasználós rendszernél az FCFS-től különböző ütemezőt használni? 11.6.14. Miért részesíti előnyben az SSTF ütemezés a lemez középső területén levő pályákat a szélsőkhöz képest?
11. Mit jelent a kiéheztetés a háttértár-ütemezésnél, és melyik algoritmusban léphet fel?
OS12V08.RTF,2001-04-23,ZSP, végleges
12. KONKURENS FOLYAMATOK
Az erőforrások megosztott, párhuzamos használatát eddig csak a hardvereszközökre vonatkoztattuk, amikor a tár, a központi egység és a perifériák ütemezéséről beszéltünk. A korszerű gépek azonban lehetőséget adnak arra is, hogy a szoftvererőforrásokat, a folyamatokat és algoritmusokat is párhuzamosan végrehajtott, ún. konkurens (egymással versenyző) részekből építsük fel. A konkurencia egyaránt értelmezhető egy folyamaton belül és több folyamat között.
12.1. Párhuzamosság és szinkronizálás Egy algoritmuson belül az utasítások végrehajtásának sorrendje -- eltekintve a speciális, vezérlőutasításoktól, -- a jelenleg legelterjedtebb, tulajdonképpen a Neumann-féle számítógép-architektúrához igazított, szekvencializált algoritmusok használata esetén azonos a programszövegben leírt sorrenddel. Gyakran előfordul azonban, -- és az ötödik generációs számítógépek kutatási célkitűzései többek között erre irányulnak --, hogy néhány utasítás végrehajtása párhuzamosítható lenne, ha például több processzorral vagy egy processzoron belül több funkcionális egységgel rendelkeznénk. Tekintsük például a következő aritmetikai jellegű algoritmust: u1: u2: u3: u4: u5: u6: u7:
x:= 12; y:=x/4; a:=x+y; b:=x-y; c:=a*b; d:=x+1; e:=c+d;
Itt u3 és u4 nyilván csak u1 és u2 után hajtható végre, u6 azonban már u1 után, u2, u3, u4 és u5-tel párhuzamosan is elvégezhető. Általánosabban megfogalmazva azt mondhatjuk, hogy az utasítások végrehajtási sorrendjét elsőbbségi szabályok korlátozzák. Ha egy utasítás egy másik utasítás eredményét akarja használni, akkor végrehajtási sorrendjük kötött. A lehetséges párhuzamosításokat és kötöttségeket egy ciklusmentes gráf, az ún. precedenciagráf segítségével lehet szemléletesen ábrázolni. A fenti példa precedenciagráfját a 12.1. ábra mutatja: A gráf csomópontjai utasítások. Ha a cs1-ből cs2-be él vezet, akkor a cs2-nél lévő utasítás csak a cs1-nél álló utasítás után hajtható végre. Ilyen rövid algoritmusnál a precedenciagráf meghatározása nem okoz problémát, nagyobb programoknál azonban további formális eszközökre van szükség. Ennek érdekében minden utasításhoz bevezetik az R, olvasási és a W, írási halmazokat. R-hez tartozik minden olyan változó, amelynek értékét az utasítás felhasználja. W-hez tartozik minden olyan változó, amelynek értékét az utasítás
megváltoztatja. (u1) | \ | \ (u2) \ / \ \ (u3) (u4) \ \ / \ (u5) (u6) \ / \ / (u7) 12.1. ábra. Precedenciagráf Az ún. Bernstein féle feltétel szerint egy program két, u1 és u2 utasítása csak akkor hajtható végre konkurens módon, ha R(u1) és W(u2)-nek, W(u1) és R(u2)-nek, valamint W(u1) és W(u2)-nek nincs közös eleme. Ha a precedenciagráf több éle egy csomópontban találkozik, ott a párhuzamosan végrehajtott utasításokat szinkronizálni kell, mert a programot csak akkor szabad folytatni, ha már minden ág tevékenysége lezajlott.
12.2. Szoftvermegoldások A precedenciagráfok jól kifejezik a folyamaton belüli párhuzamossági feltételeket, de programozásra közvetlenül nem használhatók. A programozási nyelvekben a konkurens végrehajthatóságot megpróbálták utasítások formájába önteni, ami először M. Conway-nak sikerült 1963-ban. Bevezette a fork és a join utasításokat, melyekkel a konkurens végrehajtás kezdetét és végét lehet szabályozni. A fork L utasítás hatására a program végrehajtása két párhuzamos ágra szakad, az utasítást követő programrész mellett, vele párhuzamosan megindul az L címkénél álló utasítással kezdődő programrész végrehajtása is (az algoritmus precedenciagráfját a 12.2. ábra mutatja): u1; fork L; u2; . . . L: u3; (u1) | ( fork ) / \ (u2) (u3) 12.2. ábra. Az elágazás (fork) precedenciagráfja
A join utasítás két, vagy több párhuzamos ág egyesítését, szinkronizációját valósítja meg. Az az alapelv, hogy a join utasítást minden egyesítendő ágon végre kell hajtani. A különböző időpontokban befejeződő ágak közül csak a legutoljára véget érő marad életben, a többiek a join-nál elhalnak. Két ág esetén a join-nak megfelelő precedenciagráf igen egyszerű: (u2) (u3) \ / ( join ) | (u6) 12.3. ábra. Az egyesítés (join) precedenciagráfja Több ág egyesítése csak úgy oldható meg, ha az utasításhoz paraméterként egy számlálót rendelünk, amely az egyesítendő ágak számát tartalmazza. A join minden végrehajtásnál a számlálót eggyel csökkenti, és ameddig az pozitív, a megfelelő ágat befejezettnek nyilvánítja. Az egymás utáni join utasítások hatásának függetlennek kell lennie a végrehajtás sorrendjétől. Példaként tekintsük a 12.1. ábrának megfelelő programot:
L2: L3: L1: L4:
u1; s1:=2; fork L1; u2; s2:=2; fork L2; u3; goto L3; u4; join s2; u5; goto L4; u6; join s1; u7;
Láthatjuk, hogy a fork/join utasításpár jól használható a konkurencia kifejezésére, egyetlen problémájuk, hogy goto utasításokkal tűzdelt, áttekinthetetlen programszerkezetet eredményeznek. A strukturált programozásra vonatkozó eredményei között Dijkstra 1965-ben olyan megoldást javasolt, amely nem rontja a program eredeti szerkezetét. A begin/end utasítás-zárójel mintájára bevezette a parbegin/parend "párhuzamosító" utasítást a következő formában: parbegin u1; u2; ...
parend;
Ahol u1, u2 ... tetszőleges, párhuzamosan végrehajtható utasítások.
Ennek segítségével a 12.1. ábrának megfelelő program már sokkal áttekinthetőbb lesz: u1; parbegin u6; begin u2; parbegin u3; u4 parend; u5 end parend; u7; Az utasítás használatát egy Pascal nyelvű másoló program szemlélteti, amely az R típusú rekordokból álló F1 állományt másolja át F2-be, de F1 olvasása és F2 írása párhuzamosan történik: reset(F1); rewrite(F2); read(F1,R); while not eof(F1) do begin S:=R; parbegin write(F2,S); read(F1,R) parend end; write(F2,R); A fork/join és a parbegin/parend szerkezet összehasonlításából a jobb programstruktúra miatt persze a parbegin/parend kerül ki győztesen. A teljesség kedvéért azonban meg kell jegyeznünk, hogy ez az utasítás nem minden precedenciagráf kifejezésére alkalmas. Könnyű olyan gráfot szerkeszteni (l. 12.4. ábra), amely csak fork/join szerkezettel programozható, parbegin/parend-el nem. Mint a későbbiekből kiderül, a parbegin/parend utasítás még további támogatást kap, hogy a két szerkezet ilyen szempontból egyenrangú legyen. (u1) / \ (u2) (u3) | / (u4) / / \ / (u5) (u6) \ / (u7) 12.4. ábra. Tiszta fork/join szerkezet
12.3. A folyamatok hierarchiája A párhuzamos végrehajtást, amit eddig egy program utasításaira értelmeztünk, most kiterjesztjük teljes folyamatokra is. Ha minden utasítást külön folyamatként kezelnénk, az operációs rendszerre túl nagy adminisztratív munka hárulna a rengeteg folyamatindítás és befejezés miatt. Nyilvánvaló, hogy a csak szekvenciálisan végrehajtható utasításokat az algoritmusban
megengedett párhuzamosság mértékének csökkentése nélkül egy folyamattá lehet tömöríteni. Első lépésként az előző pontban szereplő két szerkezet közötti megfeleltetést tisztázzuk. Tekintsük a következő általános utasítást: parbegin U1; U2; ... Un parend; Az ennek megfelelő fork/join program:
L2: L3:
Ln: Lv:
s:=n; fork L2; fork L3; . . . fork Ln; U1; goto Lv; U2; goto Lv; U3; goto Lv; . . . Un; join s;
Ha egy F folyamat végrehajtja a fork L utasítást, egy új, Q folyamat jön létre, amelynek programkódja és globális változói az F folyamatéval azonosak (itt természetesen csak újra beléphető kódról lehet szó). Eltérés csak abban van, hogy a Q belső utasításszámlálója L-re mutat, és belső hardverregiszterei ennek megfelelően kapnak értéket. A join s hatására az s számláló tartalma eggyel csökken; ha az eredmény zéró, a folyamat tovább él, ellenkező esetben befejeződik. A folyamatok dinamikus létrehozása hierarchiát teremt, amit közös gyökerű irányított fával, az ún. folyamatgráffal fejezhetünk ki, hiszen minden folyamatnak pontosan egy szülője van, és akárhány gyereke lehet (12.5. ábra). (F1) /\ / \ (F2) (F3) / /\ / / \ (F4) (F5) (F6) 12.5. ábra. Folyamatok dinamikus létrehozása A Fi csomópontból Fj-be mutató nyíl azt fejezi ki, hogy a Fj folyamatot Fi hozta létre. A folyamatok létrehozásakor mind az új folyamat végrehajtásával, mind a szülő erőforrásainak (első közelítésben változóinak) újraosztásával kapcsolatban többféle megoldás létezik: 1) Végrehajtás
a) A szülő a gyerekekkel párhuzamosan fut. b) A szülő megvárja minden gyerekének befejezését. 2) Osztott használat a) A közös változókat osztottan használják. b) A gyerek a szülő változóinak csak egy részét kapja. Az 1.a. változat szerepel a fork/join szerkezetekben, az 1.b. pedig a parbegin/parend utasítás által választott út, hiszen ez utóbbi utasítást kiadó folyamat (a szülő) bevárja a parbegin/parend-ben szereplő folyamatok (gyerekek) befejeződését. A 2.a. változat közös a fork/join és a parbegin/parend esetében, szülő es gyerekek korlátozás nélkül használhatják a szülő globális változóit. A UNIX operációs rendszerben végül a 2.b. megoldást választották, ahol a gyermek globális változókat nem örököl, de megkapja szülője összes állomány-hozzáférési jogát (l. 11.5. pont), lokális változói pedig az utoljára kapott értéket fogják tartalmazni. Szülő és gyermeke tehát csak közös állományokon keresztül kommunikálhat egymással. A UNIX erre egy különleges állományt, a csővezetéket (pipe) használ előszeretettel, s ennek speciális operációs rendszeri támogatást nyújt. A csővezeték egy speciális pufferelési technika, amely a szülő és gyermek között kétirányú adatforgalmat (üzenet--válasz) biztosít. A többi erőforrással kapcsolatban két alapvető megoldás van: az új folyamat vagy közvetlenül az operációs rendszertől kapja erőforrásait (CPU, tár, háttértár stb.) vagy szülőjétől örököl valamennyit. Az utóbbi megoldás hasznos lehet abból a szempontból, hogy korlátozza az egy folyamat által létrehozható újabb folyamatok számát. A folyamatok létrehozása mellett foglalkozni kell befejezésükkel is. Természetes módon akkor fejeződik be egy folyamat, ha utolsó utasítása is végrehajtódott. Szükség van azonban olyan utasításra is, melynek segítségével egy folyamat erőszakosan is befejeződésre bírhat (megölhet) egy másikat. Erre általában a kill utasítás szolgál, melynek teljes alakja a következő: kill Fa; ahol Fa a bejezendő folyamat azonosítója. A kill műveletet rendszerint csak a folyamat szülője hajthatja végre. Figyeljük meg, hogy az Fa paraméter nem nélkülözhető, ezért a folyamat azonosításáról már születésének pillanatában célszerű gondoskodni. Ezt például úgy tehetjük meg, hogy a fork utasítás egy azonosító értéket ad vissza: Fa:= fork L; Egy folyamat erőszakos befejezésére több okból is szükség lehet: * A gyerek átlépett valamilyen erőforráskorlátot. * A létrehozó folyamatban olyan helyzet állt elő, hogy már nincs szükség a gyerek tevékenységére. Sok rendszerben alapszabály, hogy egy folyamat befejeződése maga után vonja minden leszármazottjának a befejeződését is (teljes családirtás!).
12.4. A kritikus szakasz problémája A konkurens folyamatok eddig adott modellje meglehetősen egyszerű, de sajnos még adósak vagyunk néhány kérdés feltárásával. Közülük talán az ún. kritikus szakasz problémája a legfontosabb, amit első közelítésben úgy fogalmazhatunk meg, hogy párhuzamosan végrehajtható folyamatokban is lehetnek olyan szakaszok (utasítássorozatok), amelyek konkurens végrehajtása hibás eredményre vezethet. A problémát az operációs rendszerekben igen gyakran használt, ún. termelő--fogyasztó konkurens folyamatpár segítségével mutatjuk be. A termelő adatokat állít elő, s ezeket a fogyasztó folyamat "elfogyasztja". A sornyomtató kiszolgáló programja például karaktereket produkál, melyeket a sornyomtató (fizikai szintű rutinja) elfogyaszt; állományok másolásánál a forrásállomány olvasórutinja rekordokat állít elő, melyeket a célállományt író rutin fogyaszt el. A termelő és a fogyasztó folyamat azonban csak akkor működhet párhuzamosan, ha létrehozunk egy pufferhalmazt, amit a termelő folyamatosan tölt, a fogyasztó pedig folyamatosan ürít. A két folyamat között annyi szinkronizálásra van szükség, hogy a termelő ne termeljen tovább, ha már minden puffer betelt, a fogyasztó pedig észrevegye, ha minden puffer üres. A következő programban legyen a puffer N elemű, "végtelenített" tömb, melynek elemei a termelőtől T-vel jelölt értékeket vehetnek fel, s melyeket a fogyasztó F néven használ el. A puffer indexelésére a termelő a BE, a fogyasztó a KI változót használja, mindkettő a [0, N-1] intervallumban változhat. BE az első üres, KI az első foglalt elemre mutat. A puffer üres, ha BE=KI és tele van, ha (BE+1) mod N=KI. BE:=0; KI:=0; parbegin termelő:
repeat ... {T előállítása} ... while (BE+1) mod N = KI do; puffer[BE]:=T; BE:=BE+1 mod N until false;
fogyasztó: repeat while BE = KI do; F:=puffer[KI]; KI:=KI+1 mod N; ... {F elfogyasztása} ... until false parend; Az algoritmus egyetlen szépséghibája, hogy egyszerre csak legfeljebb N-1 pufferelem lehet foglalt. Ha ezt ki akarjuk küszöbölni, a puffer üres vagy tele állapotát új, S számlálóval ellenőrizhetjük. Ez kezdetben üres, majd töltéskor nő, ürítéskor csökken. A módosított program a következő:
BE:=0; KI:=0; S:=0 parbegin termelő: repeat ... {T előállítása} ... while S = N do; puffer[BE]:=T; BE:=(BE+1) mod N; S:=S+1 until false; fogyasztó: repeat while S = 0 do; F:=puffer[KI]; KI:=KI+1 mod N; S:=S-1; ... {F elfogyasztása} ... until false parend; Az algoritmus most már kihasználja a puffer minden elemét, a termelő és fogyasztó folyamat azonban párhuzamosan nem működhet, mert hibás eredményt adhat. A baj az S:=S+1, illetve az S:=S-1 utasítással van, melyek nem elégítik ki a Bernstein féle feltételt, hiszen ugyanazt a változót módosítják. Előfordulhat például, hogy az S+1 érték meghatározása után, de tárolása előtt a párhuzamosan futó másik folyamat végrehajtja S csökkentését, ami nyilvánvalóan hibás. Az S:=S+1 utasítás a termelő, az S:=S-1 pedig a fogyasztó folyamat kritikus szakaszai. A kritikus szakaszok tehát csak egymást időben kölcsönösen kizáró módon hajthatók végre. Ezért a kritikus szakaszba való belépést a folyamatnak igényelnie kell a kritikus szakaszt megelőző, ún. belépési szakaszban. A kritikus szakasz után a folyamat tartalmazhat még maradék szakaszt is. Ha általános formában több konkurens folyamatból álló rendszert tekintünk, a kölcsönös kizárás, azaz a kritikus szakaszok figyelembevétele három feltétel teljesítését igényli: 1) Kölcsönös kizárás. Ha egy folyamat saját kritikus szakaszában van, másik folyamat nem léphet be a kritikus szakaszába. 2) Ha egyik folyamat sincs a kritikus szakaszában, az oda következőként belépőt a belépési szakaszukban lévő folyamatokból véges idő alatt kell kiválasztani. 3) Várakozási korlát. Ha egy folyamat igényelte a kritikus szakaszába való belépést , a többi folyamat kritikus szakaszba lépésének számát korlátozni kell, ameddig ez az igény nem teljesül. Léteznek olyan algoritmusok, melyekkel a kritikus szakasz problémája megoldható. Ezeknél közös feltételezés, hogy vannak primitív gépi utasítások (pl. értékadás és vizsgálat), amelyek oszthatatlanok, azaz ha párhuzamosan hajtódnak végre, az eredmény akármilyen (ismeretlen) sorrendben való végrehajtásuk esetén is azonos. Először a legegyszerűbb esettel foglalkozunk, amikor két párhuzamos folyamatot kell szinkronizálni:
begin {Közös változók deklarációja} parbegin F0; F1; parend end. F0 és F1 szerkezete legyen a következő: repeat belépési szakasz; kritikus szakasz; kilépési szakasz; maradék szakasz until false; A feladat a be- és kilépési szakasz megfelelő kialakítása, valamint a folyamatok közös változóinak megadása. Az általunk bemutatott algoritmus G.L.Peterson-tól származik 1981-ből, és -- bár bonyolultabb, mint szeretnénk -- valószínűleg a legegyszerűbb általános megoldást adja. A folyamatoknak két közös változója van: var igény: array[0..1] of boolean; T: 0..1; Kezdetben legyen igény[0] = igény[1] = false, T értéke pedig 0, vagy 1. Az F0 szerkezete a következő: repeat igény[0]:=true; T:=1; while igény[1] and (T=1) do; kritikus szakasz igény[0]:=false; maradék szakasz until false; Az F1 természetesen az ennek megfelelő "tükörkép", melyben 0 helyett 1, 1 helyett 0 áll. A megoldás azon alapszik, hogy a belépési szakaszban a folyamatok egyrészt előre jelzik belépési szándékukat, másrészt megadják a másik folyamatnak a belépés lehetőségét. Az algoritmusról belátható, hogy teljesíti mindhárom fenti feltételt. Mi csak arra hívjuk fel a figyelmet, hogy a kölcsönös kizárás valóban azon múlik, hogy például ha a T:=1 (és a neki megfelelő T:=0)
értékadást a két folyamat egyszerre hajtaná végre, T értéke vagy 0, vagy 1 lenne, de ez az algoritmus szempontjából mindegy. Érdekes módon az általános, N párhuzamos folyamatra vonatkozó megoldás korábbról, 1974-ből származik, és L. Lamport nevéhez fűződik. Az alapötletet valószínűleg a különböző tömegkiszolgáló helyeken (orvosi rendelő, gépkocsi-vásárlás stb.) szokásos sorszámrendszer adta. Az összes, kritikus szakaszba belépni szándékozó folyamat sorszámot kap, és mindig a legkisebb sorszámú folyamat kerül sorra. Mivel az algoritmus nem garantálja, hogy a sorszámok különböznek, több legkisebb esetén, a "legkisebb nevű" folyamatnak van elsőbbsége. A folyamatok neve okvetlenül egyedi, ezért az algoritmus determinisztikus. A folyamatok közös adatstruktúrái a következők: var választás: array[0..N-1] of boolean; sorszám: array[0..N-1] of integer; Ezek kezdőértéke false, ill. 0. A programban az egyszerűség kedvéért a következő két jelölést alkalmazzuk: * (a,b) < (c,d), ha a0) and (sorszám[j],j)<(sorszám[i],i) do; end; kritikus szakasz; sorszám[i]:=0; maradék szakasz until false; A folyamatok kritikus szakaszukba alapvetően az FCFS algoritmus (l. 9.3.1.) alapján lépnek be, ami a fenti 2. és 3. feltételt garantálja, a kölcsönös kizárás pedig könnyen belátható. Ha Fi már kritikus szakaszában van, és egy Fk folyamat is próbál oda belépni, a 2. while utasítás j=i melletti mindkét feltétele teljesül, Fk tehát ott várakozik, ameddig Fi el nem hagyja a kritikus szakaszt. A kritikus szakasz természetesen hardvereszközökkel is kezelhető. Lényegében arról van szó, hogy olyan, oszthatatlan módon (egy tár-cikluson belül) végrehajtott gépi utasítást valósítanak meg, melynek segítségével a belépési és kilépési szakasz megírható. A konkrét megoldások igen változatosak, az utasítások elve azonban csak kétféle: az ún. TAS (a Test-And-Set rövidítése), amely egy változó vizsgálat utáni módosítását végzi, illetve a SWAP (csere) utasítás, amely két
változó értékét felcseréli. A TAS definíciója : function TAS(var x: boolean): boolean; begin TAS:=x; x:= true end; A SWAP hatása: procedure SWAP(var a,b: boolean); var t: boolean; begin t:=a; a:=b; b:=t end; A TAS segítségével a kölcsönös kizárás már egyszerűen biztosítható. Legyen "zár" egy logikai változó, melynek kezdőértéke false: repeat while TAS(zár) do; kritikus szakasz; zár:= false; maradék szakasz; until false; Ugyanez a SWAP felhasználásával kicsit bonyolultabb, egy lokális logikai változó (kulcs) is kell hozzá: repeat kulcs:= true; repeat SWAP(zár,kulcs) until not kulcs; kritikus szakasz zár:= false; maradék szakasz until false; Az algoritmusok a várakozási korlát feltételét nem teljesítik. Ez valamivel bonyolultabb megoldást igényel.
12.5. Szemaforok A kritikus szakasz problémájának, azaz a párhuzamos folyamatok szinkronizációjának eddig bemutatott megoldásai inkább csak modell jellegűek, összetett feladatok esetében nehézkes adaptációt igényelnek. A szinkronizálás általános eszköze, a szemafor E. W. Dijkstra-tól származik. A szemafor lehet például egy S egész típusú változó, amely -- a kezdőérték beállításától eltekintve -- csak két oszthatatlan alapművelettel érhető el: P(S): while S<=0 do; S:=S-1; V(S): S:=S+1; A P és a V műveletet oszthatatlanul kell elvégezni, azaz amikor egy folyamat a szemafor értékét módosítja, másik folyamat ugyanezt a szemafort párhuzamosan nem módosíthatja. A P művelet esetében ez a teljes while ciklusra is vonatkozik. A szemafor segítségével az N folyamatból álló rendszer kritikus szakasz problémája egyszerűen kezelhető. Legyen SN egy közös szemafor, melynek kezdőértéke 1. Minden Fi folyamat (i=0,1..N-1) szerkezete: repeat P(SN); kritikus szakasz V(SN); maradék szakasz until false; A szemaforok más szinkronizációs feladatok megoldására is alkalmazhatók. Legyen például F1 és F2 két konkurens folyamat, legyen az F1-ben egy U1, az F2-ben pedig egy U2 utasítás, melyeket csak U1, U2 sorrendben szabad végrehajtani. A feladat közös Z szemaforral oldható meg, melynek kezdőértéke 0. F1-ben: U1; V(Z); F2-ben: P(Z); U2; Mivel Z kezdőértéke 0, U2 csak akkor hajtódhat végre, ha F1-ben már végrehajtódott a V(Z) művelet, azaz U1 után. A 12.4. ábrán olyan precedenciagráf szerepel, amely parbegin/parend utasítással nem kezelhető. Ha szemaforokat is igénybe veszünk, a feladat megoldható és a parbegin/parend utasítás nem csak egyenértékű, hanem jobb is lesz a fork/join szerkezetnél, hiszen goto nélküli programot eredményez. A megoldáshoz az S1, S2, ... S7 szemaforokra van szükség, melyek kezdőértéke 0:
begin parbegin begin U1; V(S1); V(S2) end; begin P(S1); U2; U4; V(S3); V(S4) end; begin P(S2); U3; V(S5) end; begin P(S3); U5; V(S6) end; begin P(S4); P(S5); U6; V(S7) end; begin P(S6); P(S7); U7 end parend end; A szemaforok gyakorlati megvalósításában a legnagyobb problémát a folyamatok aktív üresjárata okozza. A kritikus szakaszba való bejutásra váró folyamat belépési szakaszában "helyben jár", ami átlagos multiprogramozott környezetben -- ahol csak egy fizikai CPU működik -komoly pazarlás, mert a központi egység más folyamat által jobban hasznosítható idejét fogyasztja. Ezért a szemafor-műveleteket kissé módosított formában valósítják meg, a P műveletben az aktív üresjárat helyett a folyamat "leállítja" önmagát és ezzel várakozó állapotba kerül, a CPU ütemezője pedig másik folyamatot aktivizálhat a készenléti sorból. Az S szemaforra való várakozás közben leállított folyamatot egy, valamely más folyamat által végrehajtott V művelet fogja "felébreszteni", amely várakozó állapotból kész állapotba kerül és beáll a készenléti sorba. Az ilyen szemaforokat nem egész változókkal, hanem rekordokkal lehet reprezentálni: type szemafor = record érték: integer; L: folyamatok listája end; Minden szemaforhoz egy egész érték és a kapcsolódó folyamatokat tartalmazó lista tartozik. Amikor egy folyamatnak a P szemafor-műveletben kell várakoznia, felkerül a listára, a V művelet pedig egy folyamatot a listáról levéve aktívvá tesz. A szemaforműveletek módosított definíciója tehát: P(S): S.érték:=S.érték-1; if S.érték<0 then begin a folyamat felvétele S.L-be; passzív end; V(S): S.érték:=S.érték+1; if S.érték<=0 then begin egy F folyamat levétele S.L-ről; aktív(F) end A definícióban két új művelet szerepel: a "passzív" felfüggeszti az őt kiadó folyamatot, az "aktív(F)" pedig újra aktivizálja az F azonosítójú folyamatot. E műveletek az operációs rendszer privilegizált állapottal támogatott, a felhasználói programokból is hívható szolgáltatásai. Az eredeti szemaforral ellentétben, a fenti S érték negatív is lehet, s ekkor abszolút értéke a szemaforra váró folyamatok számát adja. A folyamatok listáját legegyszerűbben a folyamatvezérlő blokkban (l. 9.1. pont) elhelyezett, a
listában következő PCB-re utaló mutatóval lehet megoldani, a szemaforban pedig egy mutató a PCB lista elejére mutat. A lista kezelése bármelyik sorkezelő stratégiával elvégezhető (FIFO, LIFO, prioritás stb.), ez a szemafor-elv érvényesülését nem befolyásolja. A szemaforok legfontosabb tulajdonsága, hogy a műveletek oszthatatlanok, nem fordulhat elő egy szemaforral sem, hogy két folyamat egyidejűleg végez rajta P vagy V műveletet. Egyetlen CPU esetén ez úgy valósítható meg, hogy a P és V művelet alatt a megszakítást letiltják. Ez több processzor esetén nem alkalmazható, ott speciális hardvertámogatásra van szükség (TAS vagy SWAP). Ennek hiányában a fenti algoritmusokra vagyunk utalva, ahol a kritikus szakasz a P és V műveletből áll. A tisztánlátás kedvéért meg kell jegyezni, hogy a szemaforok fenti, módosított definíciója nem küszöböli ki teljesen az aktív üresjáratot, hanem azt a felhasználói programok belépési részéből (ahol komoly teljesítménycsökkenést okozhat) áthelyezi a P és V műveletek kritikus szakaszába, melyek általában igen rövidek, ezért az üresjárat gyakorlatilag elhanyagolhatóvá válik.
12.6. Folyamatközi kommunikáció A konkurens folyamatok szinkronizálása tulajdonképpen egy általánosabb probléma, az együttműködő folyamatok egymás közti kommunikációjának speciális esete. A folyamatok közötti adatcserének két alapvető megközelítése alakult ki, az osztott tár és az üzeneti rendszer. Osztott tár esetén a folyamatokhoz közös változók tartoznak, az ezekkel megvalósított adatátvitelért az alkalmazói programok felelősek, az operációs rendszer csak a közösen használható tárat biztosítja. Ezzel ellentétben, az üzeneti rendszerben a folyamatok üzeneteket küldhetnek egymásnak, a kommunikáció megvalósítása az operációs rendszer közvetlen feladata. A kétféle megoldást általában vegyesen alkalmazzák. Mi elsősorban az üzeneti rendszerekkel foglalkozunk, mivel a másik erősen alkalmazásorientált. Folyamataink logikai címterületeinek tehát nincs közös része. Az üzeneti rendszer alapja két művelet a KÜLD(üzenet) és a FOGAD(üzenet). Ha két folyamat kommunikálni akar egymással, valamilyen kapcsolatnak kell lenni közöttük. Mi nem a kapcsolat fizikai megvalósításával (a kapcsolat kapacitásával, irányításával, az üzenetek méretével stb.), hanem elsősorban logikai tulajdonságaival foglalkozunk. Két folyamat között a kommunikáció közvetlen vagy közvetett lehet. Közvetlen kommunikációnál a feladót, illetve a címzettet meg kell nevezni, ezért a két alapművelet formája: KÜLD(F1, üzenet): üzenetküldés az F1 folyamatnak; FOGAD(F2, üzenet): üzenetvétel az F2 folyamattól. Ekkor a két folyamat közötti kapcsolatnak a következő tulajdonságokkal kell rendelkeznie: * A kapcsolat automatikusan létrejön két -- kommunikációs igényét kifejező -- folyamat
között. A folyamatoknak csak egymás nevét kell ismerniük. * Bármely két kommunikáló folyamat között pontosan egy kapcsolat jön létre. * A kapcsolat kétirányú. A két művelet alkalmazásával például a termelő--fogyasztó probléma programja a következő lehet: parbegin termelő: repeat ... {T előállítása} ... KÜLD(fogyasztó,T) until false; fogyasztó: repeat FOGAD(termelő,F); ... {F elfogyasztása} ... until false parend; A címzett és a feladó explicit megnevezésének hátránya, hogy a rendszer nehezen módosítható, ha egy folyamat neve megváltozik. A közvetett kommunikáció ezen úgy igyekszik segíteni, hogy az üzeneteket postaládákba küldik, és azokból emelik ki. Minden postaládához egyértelmű azonosító tartozik. Két folyamat több, számukra közös postaládán keresztül is érintkezhet. Ebben az alapműveletek formája: KÜLD(A,üzenet): az üzenet elhelyezése az A postaládába. FOGAD(A,üzenet): az üzenet átvétele az A postaládából. E módszernél a kommunikációs kapcsolat tulajdonságai: * Két folyamat között csak akkor jön létre kapcsolat, ha közös postaládájuk van. * Egy kapcsolat kettőnél több folyamatot is összeköthet. * Két folyamat között több -- különböző postaládán át vezető -- kapcsolat is lehet. * A kapcsolatok akár egy-, akár kétirányúak lehetnek. A következő kérdés annak eldöntése, hogy ha F1 elhelyez egy üzenetet az A postaládába, és azt F2, illetve F3 egyszerre akarja onnan, ki fogja ténylegesen megkapni az üzenetet? Többféle megoldásból lehet választani: * A kapcsolatot két folyamatra korlátozzuk. * A FOGAD művelet végrehajtását egyidejűleg csak egy folyamatnak engedélyezzük. * A döntést az operációs rendszerre bízzuk (aki a feladó előtt majd azonosíthatja a fogadót).
A postaládák tulajdonosai lehetnek a folyamatok vagy lehet az operációs rendszer. Ha a postaládák a folyamatok "magán-tulajdonában" vannak, különbséget kell tenni a tulajdonos (aki üzenetet kaphat a ládából) és a felhasználó (aki üzenetet helyezhet el a ládában) között. Ebben az esetben a tulajdonos folyamat megszűnésével postaládái is megszűnnek, amit a rendszer valamilyen módon nyilvántart. A tulajdonosi és felhasználói viszony természetesen sokféle módon rendezhető (kizárólagos, osztott jogok stb.). A postaládák létrehozása a programozási nyelvekben általában valamilyen deklaráció jellegű tevékenység szokott lenni. Ha az összes postaláda tulajdonosa az operációs rendszer, akkor ezek az egyes folyamatoktól függetlenül léteznek, a folyamatok csak átmeneti tulajdonjogot kaphatnak, amit például leszármazottaik örökölhetnek, de a folyamat befejezésekor a postaláda visszakerül a rendszer kezelésébe. A folyamatok közötti kapcsolat logikai szintű megvalósításának két legfontosabb kérdése a kapcsolat kapacitása és az üzenetek jellemzői. A kapcsolat kapacitása azt határozza meg, hogy egyidejűleg hány üzenet tartózkodhat a "kapcsolatban". Itt tulajdonképpen egy, a kapcsolathoz tartozó, üzeneteket tartalmazó sorra kell gondolni, melynek három változata alakult ki: * Zéró kapacitás. A kapcsolat üzenetet nem tárol, a küldőnek meg kell várnia az üzenet átvételét. Ez szinkronizációt igényel, amit "randevúnak" neveznek. * Korlátos kapacitás. A sor véges hosszúságú , ha a sorban van hely, a feladó futhat tovább, különben meg kell várnia, hogy a sorban hely szabaduljon fel az üzenet számára. * Korlátlan kapacitás. A sor elvileg végtelen hosszú, a feladó soha nincs várakozásra kényszerítve. Randevú esetében a feladó a KÜLD művelet után nem lehet biztos abban, hogy az üzenet meg is érkezett. Ha ez valamilyen szempontból fontos, további kommunikáció útján kell róla meggyőződnie. Ha például F1 üzen F2-nek, az átvétel nyugtázása : F1-ben: KÜLD(F2,üzenet); FOGAD(F2,üzenet); F2-ben: FOGAD(F1,üzenet); KÜLD(F1,"nyugta"); Az üzenetek két alapvető jellemzője a hossz és a típus. Lényegében három változat létezik: * Rögzített hosszúságú. A fizikai megvalósítás egyszerű, a felhasználóra viszont néha bonyolultabb előkészítés hárul. * Változó hosszúságú. Megvalósítása bonyolultabb, programozása egyszerűbb. * Típus szerinti. Az üzenet a programozási nyelv valamilyen megengedett típusához tartozik, amit rendszerint a postaláda deklarációjával együtt kell megadni. Az üzeneti rendszerek természetesen a fentieken kívül még sok problémát vetnek fel, melyeket csak éppen megemlítünk. Különleges kezelést igényel például a folyamatok befejeződése, mert előfordulhat, hogy egy folyamat üzenetre vár, de a küldő időközben befejeződött. A vonal- vagy hardverhiba miatt elveszett üzenetek is problémát okozhatnak, ami további terheket ró az operációs rendszerre. Az átviteli csatorna zaja miatt torzult üzenetek kiszűrése és javítása
szintén ebbe a témakörbe tartozik.
12.7. Mintapéldák A példák között két klasszikusnak és tipikusnak számító, gyakorlati jelentőségű szinkronizációs feladat és egy üzeneti rendszer bemutatása szerepel.
12.7.1. Termelő--fogyasztó probléma A 12.4. pontban e feladatnak csak egy viszonylag speciális esetét elemeztük, most a szemaforok segítségével megmutatjuk ennek általános megoldását. Tegyük fel, hogy N pufferünk van, melyek mindegyikében egy terméket lehet elhelyezni. A termelő a terméket egy T változóban állítja elő, a fogyasztó pedig az F változóból használja el. A feladathoz három szemafort alkalmazunk. A "közös" szemafor a pufferhez való hozzáférés kölcsönös kizárását biztosítja, az "üres" és a "tele" szemaforok pedig a foglalt , illetve szabad puffereket tartja számon. var T, C: termék; közös, üres, tele: szemafor; begin tele:=0; üres:=N; közös:=1; parbegin termelő: repeat ... T előállítása; ... P(üres); P(közös); ... T átvitele a pufferbe; ... V(közös); V(tele) until false; fogyasztó: repeat P(tele); P(közös); ... egy termék kivétele a pufferből C-be; ... V(közös); V(üres); ... C tartalmának elfogyasztása; ... until false parend end.
A termelő és a fogyasztó szempontjából a program teljesen szimmetrikus. 12.7.2. Író--olvasó probléma Adatállományok konkurens folyamatok közötti megosztása gyakori jelenség. Az állományt használó folyamatokat két csoportba soroljuk: az "olvasók", akik csak használják, de nem módosítják az adatokat, valamint az "írók", akik olvashatják, de át is írhatják az állomány tartalmát. Két olvasó párhuzamos működése nem zavarja egymást, az írók azonban a többiekkel nem ütközhetnek, mert az bajt okozhat. Ezért az íróknak kizárólagos hozzáférést kell biztosítani. A feladat több változatban terjedt el. A legegyszerűbb esetben az olvasókat nem várakoztatják, hacsak egy író nem foglalja le éppen a közös állományt. Az olvasók tehát nincsenek figyelemmel az esetleg várakozó írókra. (Egy másik változat -- várható módon -- éppen az íróknak kedvez. Ha egy író várakozik, egyetlen újabb olvasó sem férhet az állományhoz). Mi az első változattal foglalkozunk, megjegyezve, hogy az írók kiéheztetése nem zárható ki. A program két szemafort használ, a "közös" szemafort mind a két folyamat, a "kizárás" szemafort csak az olvasás kezeli. Mivel egyszerre több olvasó is használhatja az állományt, ezek számontartására is szükség van. Erre az "osz" nevű változó szolgál. Az írók kizárását az első olvasó állítja be és, az utolsó oldja fel. A két eljárás vázlata: var kizár, közös: szemafor; osz: integer; begin osz:=0; közös:=1; kizár:=1; olvasás: P(kizár); osz:=osz+1; if osz=1 then P(közös); V(kizár); ... az olvasás végrehajtása; ... P(kizár); osz:=osz-1; if osz=0 then V(közös); V(kizár); írás:
P(közös); ... az írás végrehajtása; ... V(közös);
end. Figyeljük meg, hogy ha egy író éppen a kritikus szakaszban van, és több olvasó várakozik, ezek közül egy a "közös", a többiek a "kizár" szemaforra várnak. 12.7.3. Az Accent operációs rendszer A rendszert a Carnegie-Mellon egyetemen fejlesztették 1980 körül a Perq gép számára. Az Accent
egymással kizárólag üzenetek segítségével kommunikáló folyamatok létrehozására és megszüntetésére képes, melyek mindegyikéhez saját, 32 bites címtartományú virtuális tár tartozik. Az Accentben még az operációs rendszeri hívásokat is üzenetek segítségével valósították meg. Minden folyamat születésekor két speciális postaládát kap, a "Kernel"-t és a "Data"-t. Egy rendszerhívás a "Kernel"-be küldött üzenet, amire az esetleges válasz "Data"-ba érkezik. Külön rendszerhívás szolgál új postaládák létrehozására, ami egyben a hozzátartozó üzenetsort is kialakítja. Paraméterként az üzenetsor maximális hosszát kell megadni. A postaláda létrehozója egyrészt a tulajdonossá, másrészt felhasználóvá válik, aki a ládából üzenetet is kaphat. Egy ládának egyszerre csak egy tulajdonosa és egy felhasználója lehet, de ezek a jogok más folyamatokra átruházhatók. Az üzenetsorokat prioritásos alapon kezelik. Két osztályt különböztetnek meg: a sürgős és a normál üzeneteket. Maguk az üzenetek rögzített hosszúságú fejből és változó hosszúságú törzsből állnak. A fej a teljes üzenet hosszát, prioritási osztályát, valamint két postaláda nevét tartalmazza. Az egyik név a címzett, a másik pedig a feladó által adott cím, ahova az esetleges választ várja. A törzs különböző típusú komponensekből álló lista. A KÜLD és a FOGAD műveletek meglehetősen rugalmasak. Ha például a címzett postaládasora tele van, a feladó négy lehetőség közül választhat: 1) Meghatározatlan ideig várakozik, ameddig helyet nem kap a sorban. 2) Korlátos ideig várakozik. 3) Várakozás nélkül visszatér. 4) Egyetlen üzenetet minden feladó -- későbbi kézbesítés céljából -- az operációs rendszerre bízhat. A rendszer értesíti a feladót, ha sikerült az üzenetet a kívánt postaládában elhelyezni. A FOGAD műveletnél meg kell adni, hogy melyik postaládá(k)ból kell az üzenetet kivenni. A kivételhez természetesen felhasználói jogra van szükség, de a postaláda még zárva is lehet, ekkor a tartalma nem elérhető. Az Accesst elsősorban osztott rendszerek számára tervezték, de egyprocesszoros esetben is használható. Fő problémája -- ami az üzenet alapú rendszereknél közös -- a teljesítmény. Az üzenetek ide-oda másolgatása sok munkát igényel. Az Access ezen ügyes lapkezeléssel, a laptábla megfelelő manipulációjával, igyekszik segíteni.
12.8. Gyakorlatok 12.8.1.
Mi a precedenciagráf?
12.8.2.
Mi a két párhuzamosan végrehajtott utasításra vonatkozó Bernstein féle feltétel?
12.8.3.
Mi a fork/join szerkezet?
12.8.4.
Mi a parbegin/parend utasítás?
12.8.5.
Írjuk meg a 12.6. ábrán látható precedenciagráfhoz tartozó: a) fork/join szerkezetet, b) parbegin/parend szerkezetet. (u1) /| \ / | \ (u2)(u3)(u4) \/ / (u5) / \ / (u6) 12.6. ábra. Hatelemű precedenciagráf
12.8.6.
Miért kell a join utasítást oszthatatlanul végrehajtani?
12.8.7.
Mi a folyamatgráf?
12.8.8.
Mit nevezünk kritikus szakasznak?
12.8.9.
Mikor és miért van szükség a kölcsönös kizárásra?
12.8.10.
Mit nevezünk szemafornak, és mi a szerepük a konkurens folyamatok kezelésében?
12.8.11.
Mutassuk meg, hogy ha a P És V műveletet nem oszthatatlan módon hajtjuk végre, a kölcsönös kizárás nem biztosított!
12.8.12.
A bináris szemafor olyan egész változó, amely csak 0 vagy 1 értéket vehet fel. Mutassuk meg, hogyan lehet egy általános szemafort binárisakkal megvalósítani!
12.8.13.
Mit nevezünk aktív várakozásnak, és mit szoktak tenni ellene?
12.8.14.
Tegyük fel, hogy az F folyamat egy postaládával megvalósított kommunikációban egy-egy üzenetre vár az A és B postaládából. Milyen KÜLD és FOGAD utasításokat kell kiadnia?
12.8.15.Tegyük fel, hogy az F folyamat egy postaláda segítségével megvalósított kommunikációban egy üzenetre akar várni az A vagy a B postaládából (vagy mindkettőből). Milyen KÜLD és FOGAD utasításokat kell kiadnia?
12.9. Appendix: Monitorok {2001 -- ZSP:} A korábbi fejezetek "összementek" az ökonomikusabban szerkesztett ábrák, az A4es formátum és a betűtípusból eredő tördelési előnyök miatt. Ugyanakkor az eredeti könyvből is kimaradt egy fontos téma ebből a fejezetből, amely a korábbi fő forrásunkban sem szerepelt, de annak későbbi kiadásaiba már belekerült. Ez a Monitorok problematikája, ami a szemaforokhoz hasonló technológiai megoldást nyújt a konkurens problémák bizonyos típusainak a jobb kezelésére. 12.9.1. A monitorok koncepciója A monitorok, akár a szemaforok, magas szintű szinkronizációs eszközök, azonban nem változó, hanem eljárás koncepciójú megoldásban. Ezzel, jóval rugalmasabb szinkronizálási eszközt adnak a programozó kezébe, mint a szemaforok. .---------------------------. (
OSZTOTTAN KEZELT
|
ADATOK
Belépésre várók sora )
+---+ +---+ +---+ +---+ +---+
----+F3 +-+F1 +-+F3 +-+F2 +-+-1 |
+-----------------------------+
+---+ +---+ +---+ +---+ +---+
| +---+ +-----+ +--+ +------+ | | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |F1 | |
F2 | |F3| |
F4
láncvég
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| +---+ +-----+ +--+ +------+ | |
MONITOR MŰVELETEK
|
+-----------------------------+ (
INICIALIZÁLÓ FOKOZAT
)
*---------------------------* 12.7. ábra: A monitorok koncepciója A monitorműveletek a monitor belsejében, tehát jól védett helyen tárolt (adatrejtés módszere!), osztott adatmezőket használják, a saját lokális változóik mellett. Az osztott változókhoz tehát az alkalmazó csak úgy férhet hozzá, hogy meghívja a monitort, és megmondja, melyik művelet végrehajtását kéri. Egyszerre tehát a monitorba csak egyetlen igénylő léphet be, és ezzel csak egy férhet hozzá a kölcsönösen kizárt módon kezelendő adat erőforrásokhoz. A monitor végrehajtási
sorának kezelését természetesen az operációs rendszerre kell bízni. Ez annak egy rutin FIFO feladat lehet. A tapasztalat megmutatta, hogy bár ez a konstrukció nagyon tisztának tűnik, és elkerüli a szemaforok siserehadának a kezelési problémáit, miközben a kölcsönös kizárás (mutex az angol irodalomban) kezelését elegánsan megoldja, a használata korántsem optimális, nagy a többletráfordítása (overhead). Ez azonban javítható néhány egyszerű fogással. A megoldás a feltételek szisztematikus kezelése. Ez a további szinkronizációs eszköz feltétel változók definiálásával teszi lehetővé, hogy egyes monitor műveletekhez "wait" várakozási, vagy "signal" startjel információt juttathassunk el. A "wait" jelet kapott művelet addig vár, akárhányszor is hívnák közben, amíg nem kap egy "signal" startjelet. A "signal" mindig csak egyetlen folyamatot indíthat. Ha egyetlen várakozó sincs, akkor hatástalan marad. Szemben a szemaforműveletekkel, amelyek mindig hatnak, és ezzel esetleg jókora zavarokat okozhatnak. 12.9.2. Monitor algoritmusok A tipikus monitor programstruktúra az alábbi lehet: type monitornév = monitor változó deklarációk procedure entry F1 (...); begin ~~~ end; procedure entry F2 (...); begin ~~~ end; ~ ~ ~ procedure entry Fn (...); begin ~~~ end; begin inicializáló kód end. Feltételek tipikus deklarációjának a példája: var x,y: conditon; Hivatkozás rájuk: x.wait vagy x.signal Tegyük föl, hogy ha a P folyamat az x.signal feltételt viszi a monitorba, akkor van egy Q folyamat, amely éppen fölfüggesztett állapotban várakozik az x feltétel miatt. Mivel a Q vár az x-re, a startjelet küldő P-nek is várnia kell. Különben mindkét folyamat egyidejűleg aktív lehetne a monitorban. Ami fontos, hogy koncepcionálisan mindkét folyamat végrehajtódhat, ami két esetet eredményez. 1) P vagy addig vár, amíg Q ki nem lép a monitorból, vagy addig, amíg Q ismét elcsendesül valamelyik más feltétel miatt. 2) Q vár addig, amíg P el nem hagyja a monitort, vagy várakozásra nem kényszerül valamelyik más feltétel folytán. Hoar az első megoldás implementálását ajánlotta, az egyszerűbb és elegánsabb programozási megvalósíthatóság miatt. Mások inkább a másodiknak adnának több esélyt, mivel a signalt küldő P már éppen benn van a monitorban. A kompromisszumos megoldást Concurrent Pascal nyelven
fogalmazták Brinch Hansen és társai. E szerint a signalt hozó P a monitort rögtön el is hagyja, de az osztott tármezőben újabb sorokat kell képezni a feltételek előtt. Így Q rögtön indulhat. A Hoar-féle megoldásban azonban a P akár egyszerre több feltételre is hozhat signal jelzést, tehát hatékonyabb. Ebből is látható, hogy az élet a programozásban sem folyton habos torta.
12.9.3. Monitor példák Nézzünk példát a szemaforok használatára, monitor konstrukcióban! Minden monitorhoz tartozzon egy mutex (1-re inicializált) szemafor. Monitorhívás előtt minden folyamatnak wait(mutex) utasítást kell végrehajtani, visszatérése után pedig signal(mutex) hívást. A sorban állás kezelésére be kell még vezetnünk a next szemafort. Továbbá a next-count egész változót a sor hosszának számlálására. Ezek után egy F monitor művelet, külső eljárásként programozva, a következő konstrukciójú lehet: Wait(mutex); F kódja if next-count > 0 then signal(next) else signal(mutex); Most jöhetnek a feltétel változók. Az x feltételváltozóhoz hozzárendeljük az x-sem szemafort és az x-count egész változót, 0-ra inicializálva. Az x.wait és az x.signal ezek után így implementálható: x-count := x-count + 1; if next-count > 0 then signal(next) else signal(mutex); wait(x-sem); x-count := x-count – 1;
{x.wait}
if x-count > 0 then begin next-count := next-count + 1; signal(x-sem); wait(next); next-count := next-count – 1; end
{x.signal}
A fenti kód túl általános megoldás, és egyszerűsíthető, de belőle a szemaforok kínjai jól láthatók. És most nézzünk meg egy tiszta monitoros megoldást egy erőforrás elosztására! Egy folyamat a kér(idő) utasítással foglalhat, és az elenged hívással szabadíthat föl egy erőforrást. A foglalást időhöz is kötjük, ezt jelzi a kér idő paramétere, ami prioritásként is felfogható. A monitor a legrövidebb időt kérőt elégíti ki (az SJF algoritmus megoldása). A megoldás túl egyszerű, vannak korlátai, de javítható. type eröforráslekötö = monitor var foglalt: boolean; x: condition; procedure entry kér (idő: integer); begin if foglalt then x.wait(idő); foglalt := true; end; procedure entry elenged; begin foglalt := false; x.signal; end; begin
foglalt := false; end.
12.9.4. Gyakorlatok Nos, néhány gyakorlati példa esetleg abból adódhat, hogy elemezzük a fenti példák hibáit. Továbbá vizsgálhatjuk, hogy lehet monitor-kordába terelni a kritikus szakasz problémát, vagy a tipikus konkurens programozási problémákat, mint például a termelő--fogyasztó problémát. 12.9.1.
Tervezzünk "ébresztőórát" monitorral, óraütemnyi időegységeket (tic) feltételezve!
12.9.2.
Tervezzünk két-három tranzakciós lépésből álló mini tranzakciós monitort!
További példákért forduljon az olvasó az irodalomhoz, főként Silberschatz-Galvin Operating System Concepts című könyvének 5. kiadásához! (Nem elérhetetlen.)
OS13V07.RTF,ZSP,2001-04-22
13. RENDSZERHATÁSFOK-VEZÉRLÉS
A 8. fejezetben általánosságban tárgyaltuk az erőforrás-kezelést. Ott elemeztük, hogy az erőforráskezelés statikus vagy dinamikus stratégiát követhet. A továbbiakban egyes konkrét erőforrások (CPU, tár, perifériák, adatállományok) lefoglalásának ütemezési algoritmusait vizsgáltuk. Ezek az allokátorok és ütemezők azonban csak lokális optimumokat tudnak megkeresni, mert csak egy adott típusú erőforrás elosztását tudják elvégezni. E szűk látókörű működés miatt egymás munkájáról nem tudnak, döntéseik egymásnak ellentmondanak, de legalábbis megkérdőjelezhetők. (Például: a diszpécser már éppen be tudna ütemezni egy programot, de a tárkezelő elveszi tőle a folytatásához éppen szükséges egyik lapkeretet, és ezzel újra blokkolja.) A nagyteljesítményű számítógépek operációs rendszereiben ezért szükség van olyan szoftver algoritmusokra, amelyek globálisan át tudják tekinteni az erőforráshelyzetet és a rendszerben futó munkák haladását. Ezek a rendszerhatásfok-vezérlők. A problémát az IBM 370 OS/MVS rendszer erőforrás--kezelőjének (angolul: SRM = Systems Resource Management) példáján mutatjuk be, így ez az egész fejezet egy komplett mintapélda.
13.1. Az IBM SRM alapelvei Az IBM OS/MVS SRM nem más, mint a korábbi fejezetekben már emlegetett közbenső szintű ütemező. Amint a 13.1. ábra mutatja, az IBM OS/MVS-ben három ütemező van: * Vezérlőáram-olvasó és főütemező, amelyet itt JOB-beléptető alrendszernek (angolul: JES = Job Entry Subsystem) neveznek, amelyről korábban már említettük, hogy nem igazi alrendszer (5.7); * Közbenső szintű ütemező, amelyet itt SRM-nek hívnak; * Diszpécser a CPU-idő(k) ütemezésére. A JES gondoskodik arról, hogy a munkákat beolvassa, majd a végrehajtásra várakozó sorból egyenként átadja a multiprogramozott környezetnek. A képződő újabb vezérlőtáblázatokat azonban nemcsak a diszpécser kezeli (mint a közbenső szintű ütemező nélküli operációs rendszerekben), hanem a diszpécser és az SRM közösen. A közösen kezelt táblázatnak ezért külön neve van: a megkezdett munkák sora. Az MVS-ben a diszpécser további táblázatokat használ a ténylegesen futó munkák nyilvántartására (l. 13.1. ábra). A várakozó munkák sorából akkor kerülhet át egy munka a diszpécser soraiba, ha az SRM ezt engedélyezi. Ennél fontosabb, hogy az SRM a diszpécser soraiból a már átadott munkákat is visszahívhatja átmenetileg, sőt ennél finomabb beavatkozásokkal is befolyásolni tudja a már futó munkák ütemezési esélyeit, ha a rendszerterhelés szélsőséges, vagy ha valamelyik sürgős munka nem a kívánt ütemben halad.
O===============o | Végrehajtásra | | várakozó sor | multiprogo===============o
+---------------+ | JES | | JOB beléptető | | alrendszer | +---------------+
Magas szintű ütemező Beléptetés a ramozott környezetbe.
-----------------------------------------------------------------Közbenső szintű ütemező O===============o | Megkezdett | | munkák sora | o===============o
+---------------+ | | | SRM | | | +---------------+
Figyeli az elindított munkák haladását. Módosítja a rendszer terhelés-eloszlását a kitűzött rendszercélok teljesítése érdekében.
-----------------------------------------------------------------o===============o ütemező | Aktivizálható | | folyamatok | o===============o o===============o akti| Futó | | folyamat(ok) | o===============o
Alacsony szintű
+---------------+ | |
Eldönti, hogy
| Diszpécser | | | | | +---------------+
vizálható folyamatok sorából melyik kapja meg a CPU-vezérlési jogot.
az
O===============o | Blokkolt | | folyamatok | o===============o o===============o | Felfüggesztett| | folyamatok | o===============o 13.1. ábra. Az IBM 370 OS/MVS ütemezői Az SRM fő feladata tehát a rendszerterhelés szabályozása. Alacsony és magas rendszerterhelés esetében alkalmasan választja meg az ütemezési politikát. Nagy terhelésnél például segít "átvészelni" a helyzetet. A felhasználó számára ennél fontosabb, hogy az SRM képes a munkák előrehaladásának figyelésére, és el tudja hárítani az esetleges "igazságtalanságokat". Képes a
lassan haladó munkák meggyorsítására, és a túl erőszakosak megfékezésére. Az eddigi fejtegetésekből persze még nem lehet világos, hogy lehet megoldani ezt a nagyon heurisztikus döntéseket igénylő feladatot egy számítógépes szoftverrel. Egyáltalán: hogy lehet megtanítani egy programot heurisztikus döntésekre? Természetesen meg kell figyelni, hogy az ember milyen módszerrel alapozza meg döntéseit. Az ember a döntéseit úgy alapozza meg, hogy elegendően sok információt gyűjt össze a vizsgált problémáról. Számítógéppel ugyanezt a szisztémát követhetjük. Adatokat kell gyűjteni a munkák erőforrás-felhasználásáról. Valóban, az SRM munkáját egy adatgyűjtő fokozat támogatja, amely méri a folyamatok erőforrás-használatát természetes egységekben (másodperc, lapkeretszám, B/K átvitelek száma/hossza stb.). Ez azonban további gondokat okoz. Hogy lehet összevetni a különböző egységekben mért adatokat. Tulajdonképpen sehogy, mint ahogyan két körtét sem lehet öt almával összehasonlítani.
13.2. A szolgáltatás egysége Az SRM leglényegesebb ötlete éppen az, ahogyan a folyamatok előrehaladását mérni tudja. Abból indul ki, hogy a folyamatok a működésükhöz szükséges erőforrásokat komplex módon fogyasztják. Így az előrehaladás méréséhez nem tisztán az egyes erőforrásokból fogyasztott naturáladatokból kell kiindulni, hanem komplex alapegységet kell használni az előrehaladás megítélésére. A folyamatokat emellett célszerű kisebb kiszolgálási egységekre, ún. tranzakciókra szabdalni, és az egyes tranzakciók erőforrás--fogyasztását kell vizsgálni. A szolgáltatás egységét a naturálegységek komplex struktúrájaként lehet megfogalmazni. A szolgáltatás egységének effajta kijelölése során felmerül, hogy az egyes naturál erőforrásokat milyen súllyal vegyük figyelembe. Ennek megállapítását a gyakorlati tapasztalatra lehet csak bízni. Ez tehát egy heurisztikus (szigorú logikával meg nem alapozható) mozzanat, amelyet az SRM üzembeállításakor a rendszerprogramozónak kell megadnia. (Az SRM tehát itt támaszkodik emberi segítségre a heurisztikusnak tűnő döntések megalapozásában.) Az SRM filozófiája szerint a szolgáltatás egységének négy komponense van: * CPU kiszolgálási sebesség (a választott mérési időegység alatt rendelkezésre bocsátott CPU-idő); * B/K kiszolgálási sebesség (az időegység alatt teljesített B/K átvitelek száma); * Tárkiszolgálási tényező (az időegység alatt adott lapkeretek száma); * Rendszerhívás-kiszolgálási sebesség (az időegység alatt a rendszerhívásoknak megadott CPU-idő). Egy tranzakció kiszolgálási sebességét a választott időegység alatt felhasznált (megkapott) szolgáltatási egységekben mérjük. Az OS/MVS rendszerstatisztikai funkciói ezt mérik a folyamatokról vezetett statisztikai adatok alapján. Ez azt jelenti, hogy a folyamatok vezérlőtáblázatait az SRM működtetésének biztosítására újabb adatelemekkel kell bővíteni. Ezek az adatelemek azonban többcélúak, s nemcsak az SRM igényei miatt merülnek fel. Így például ezek alapján történik a számlázás, és ezekre alapozhatók az eseti hardver-karbantartási igények. Végeredményben azt is mondhatjuk, hogy az SRM--szolgáltatásokat melléktermékként kapjuk. A mérési adatok meghatározásánál fontos tényező az időegység megválasztása. Korábban már
beszéltünk arról, hogy a különböző szintű ütemezők különböző gyakorisággal lépnek működésbe. Leggyakrabban a diszpécser, legritkábban a magas szintű ütemező (főütemező) aktivizálódik. Várható, hogy a közbenső helyet elfoglaló közbenső szintű ütemezők (így az SRM) működési gyakorisága valahol a kettő között foglal helyet. Jogos kérdés, hogy miért. Mint említettük, az SRM a globális erőforrás-kezelési helyzetet szeretné áttekinteni, ezért nem léphet működésbe túl gyakran, mert ilyen rövid idő alatt nem láthatók a tendenciák. Túl hosszú SRM--ütemezési periódus alatt viszont túlzottan kiátlagolódnának az értékek, és az SRM "lekésne" a közbeavatkozási lehetőségekről. Ez még nem magyarázza meg, hogy az ütemezési periódus miért rövidebb, mint a főütemező periódusa. A főütemező azonban bizonyos mértékig játszhatja ugyanazt a szerepet, mint az SRM. Szabályozási lehetősége abban áll, hogy beengedi-e azonnal a beolvasott JOB-ot a multikörnyezetbe vagy sem. Visszahívni azonban nem tudja a már elindított munkát, szemben az SRMel, amely azután is be tud avatkozni. Végeredményben ez a magyarázata annak, hogy az SRM ütemezési periódusát a főütemező ütemezési idejének töredékére, de a diszpécser átlagos ütemezési idejénél egy-két nagyságrenddel nagyobbra kell választani. A konkrét érték kiválasztása ugyanúgy heurisztikus mozzanat, mint a szolgáltatás egységének a definiálása. Nem meglepő, hogy a szolgáltatás egységét és az SRM ütemezési időt rendszeresen felül kell bírálnia a rendszerprogramozónak. Ennek több oka van. Egyrészt üzembeállításkor minden számítógépes rendszer az alulterheltség problémáival küszködik, míg az idő haladtával egyre inkább túlterhelési tünetek jelentkeznek. Ezek aztán elmúlnak, amikor a gépet elkezdik kiváltani újabb, párhuzamosan üzemeltetett hardverrel. Ezenkívül vannak szezonális hatások is. A nyári szabadságok (oktatási intézményekben a tanítási szünetek) idején jelentősen lecsökkenhet vagy jellegében erősen átalakulhat a rendszerterhelés. Ezekre a rendszerprogramozónak reagálnia kell, különben az SRM-ben a korábbi terhelésre beállított heurisztika elkezd anomális viselkedési módokat generálni. A mérési adatok gyűjtése nem az SRM feladata, de kiértékelése az SRM ütemezési periodicitásával történik. A mért naturális adatokat az SRM átszámítja szolgáltatási-egység mértékegységekre, és így tudja meghatározni a multiprogramozott környezetben folyamatonként elfogyasztott erőforrásokat. Ez jelenti a folyamatok előrehaladási sebességét, ami alapján az SRM dönteni tud a következő ütemezési periódus tartamára.
13.3. Terhelési szintek Ha a számítógépes rendszerben éppen futó folyamatok szolgáltatási egységekben mért fogyasztásait összeadjuk, és ezt viszonyítjuk a számítógépes rendszer maximális kapacitásához, akkor olyan arányt kapunk, amely a számítógépes rendszer pillanatnyi terhelési állapotát jellemzi. Arányértékek megadásával terhelési szinteket határozhatunk meg. A legegyszerűbb esetben például három szintet tűzhetünk ki: (1) alacsony- (mondjuk 0.2 alatt), (2) közepes- (0.5-ig) és (3) magas (0.75 felett) terhelés. A terhelési szinteket az SRM üzembeállításakor lehet beállítani, s ez is heurisztikus módon történik.
13.4. Terhelési sablonok és végrehajtási csoportok A munkákat csoportosíthatjuk várható erőforrásigény--tulajdonságaik (profil) alapján. Így például lehetnek rövid, sürgős, CPU-igényes, B/K-igényes munkák stb. Ezek a működésoptimalizálás eszközeivel eltérően kezelhetők. A kevésbé sürgős vagy a hosszú, B/K
igényes munkákat például nem nagyon sújtja, ha időnként egy kicsit visszafogjuk haladásukat. E szituációk megfogására az SRM végrehajtási csoportok és terhelési sablonok definiálásával ad lehetőséget. Egy terhelési sablonban azt lehet megadni, hogy az előző pontban említett terhelési szinteken mennyi kiszolgálási egységet kaphatnak azok a folyamatok, amelyek az adott terhelési sablon szerint kezelendők. Ha van egy koncepciónk arra, hogy milyen csoportokat alkotunk a munkákból, akkor ezekhez a csoportokhoz hozzá kell rendelni egy-egy terhelési sablont. Ezt mutatja a 13.2. ábra. Az ábrából kitűnik, hogy a terhelési sablonok azt adják meg terhelési szintenként, hogy az adott munkacsoport folyamatainak -- SRM ütemezési időegységenként -- mennyi szolgáltatási egységet kell kapniuk. A sürgős munkák előrehaladását például feltétlen minden terhelési szituációban segíteni kell, ezért rájuk általában csak olyan terhelési sablon alkalmazható, amely minden terhelési szinten azonos (és elég nagy) szolgáltatási egységet biztosít a csoport folyamatainak. A lassú munkák a magasabb terhelési szinteken egyre kevesebb szolgáltatási egységet kaphatnak, ami akár nulla is lehet. A terhelési sablon az SRM-nek csak egy javaslat az egyes ütemezési periódusokban hozandó döntésekhez. A folyamatok ténylegesen haladhatnak az előírtnál lassabban és gyorsabban is. A gyorsabb haladás azonban nem feltétlen probléma, ha például közben hirtelen leesik a rendszerterhelés. Az SRM-nek tehát teljes dinamikájában kell figyelnie a hardver/szoftver rendszert, és úgy kell döntést hoznia a folyamatok továbbhaladásáról. Az érdekesség az, hogy ezt a dinamikus döntési mechanizmust ezekre a meglehetősen statikusnak tűnő terhelésisablon táblázatokra lehet alapozni. 1. Végrehajtási csoport +-----------+ | A program | | B program | | C program | | D program | +-----------+ Sürgős munkák 2. Végrehajtási csoport +-----------+ | E program | először | F program | a | G program | szin+-----------+ megB/K igényes hogy Munkák idő-
1. Terhelési sablon
+-------------+ | | +---------+--------------+ | SRM | |Terhelési|Szolgáltatási | | | | szint | egység | +------+------+ +---------+--------------+ | | 1 | 500 | v | 2* | 500* |<-+ o=============o | 3 | 500 | | |Aktuális ter-| +---------+--------------+ +--Xhelési szint | | | = 2 | 2. Terhelési sablon | o=============o | +---------+--------------+ | |Terhelési|Szolgáltatási | | Az SRM |
szint
|
egység
|
|
kiszámítja
+---------+--------------+
|
terhelési
|
1
|
400
|
|
tet,
|
2*
|
200*
|<-+
vizsgálja,
|
3
|
100
|
az
|
majd
utolsó
+---------+--------------+
|
szakban
.
lően
.
az egyes
.
tok
|
megfelelően
|
toztatja
+---------+--------------+
|
munkák
|Terhelési|Szolgáltatási |
|
--foglalási
|
|
|
tőségeit
+---------+--------------+
|
vetkező
megfelehaladtak-
e csopormunkái.Ennek n. Végrehajtási válcsoport a +-----------+ erőforrás | X program | lehe| Y program | kö| Z program | inter+-----------+ Lassú munkák
13.2. ábra.
n. Terhelési sablon
szint
|
egység
| 1 | 200 | | | 2* | 100* |<-+ | 3 | 0 | +---------+--------------+
meg
a
vallum idejére.
Terhelési szintek, terhelési sablonok és végrehajtási csoportok az SRM-ben
13.5. Végrehajtási periódusok A munkák nem minden fázisa viselkedik egyformán az erőforrásigény szempontjából. Ezért a munkák és terhelési sablonok összerendelése nem korlátozható csak a végrehajtási csoportokra. Adott esetben végrehajtási periódusokat is ki lehet jelölni. Ezekhez szintén hozzá kell rendelni egy-egy terhelési sablont. A végrehajtási periódus az az időszak, amelyen belül a folyamat ugyanolyan terhelési sablon szerint kezelendő. Az SRM a munkát áthelyezheti más végrehajtási periódusba, ha megítélése szerint nagyon eltérően halad az előírt terhelési sablontól. Ezzel próbálja korrigálni azt a hibát, amit a folyamat kezdeti besorolásakor követtünk el. Tipikus alkalmazása e lehetőségnek, hogy a rövid terminálparancsokat egy nagyon gyors kiszolgálást biztosító terhelési sablonú végrehajtási periódusba soroljuk. Ha azonban a parancs végrehajtása környezeti okokból lelassul (például azért, mert egy kezdő felhasználó ül a terminálnál, aki folyton téveszt), akkor az SRM a felhasználóval kapcsolatot tartó folyamatot átsorolja egy másik végrehajtási csoportba, amely például csak a lassú folyamatokra érvényes terhelési sablon szerinti kiszolgálást engedi meg.
13.6. Intervallumokra bontott kiszolgálás Az SRM további érdekes működésoptimalizálási finomításokat tartalmaz. Egyik ilyen lehetősége lényegében az időszeletelt CPU-ütemezés analógiája. Itt azonban a folyamatok szolgáltatáskérésekből kapnak szeleteket. Intervallumonként kérhetnek valamennyi kiszolgálási egységet (angolul: ISV = Interval Service Value). A megadott ISV értéket kérő folyamat addig nem szorítható ki a tárból (swappinggal), amíg meg nem kapja a kért szolgáltatási egységnyi kiszolgálást. A kifejezésben található intervallum szó tehát nem egy határozott időtartamra utal, hanem a kért szolgáltatás teljesítéséhez szükséges időtartamot jelenti. Az ISV típusú SRM--vezérlési lehetőség szerepe érezhetően az, hogy csökkenti azt a rendszeradminisztrációs többletidőt (overhead), ami a normál ütemezési algoritmus meghagyása esetén túl sűrű swapping miatt lépne fel. Az SRM-nek ez a szolgáltatása még egy "óvatossági" rendszabályt is alkalmaz. Előfordulhat ugyanis, hogy egy folyamat bejelent egy ISV-t, de saját hibája miatt nem halad elég gyorsan. Az SRM ilyenkor a tárban tartja ugyan a kérelmező kódját (kivéve, ha a helyzet végképp tarthatatlanná válik), de átsorolja a folyamatot valamilyen lassabban kiszolgált csoportba. (Újabb ízelítő abból, milyen trükkös optimalizálási lehetőségekre képes az SRM.)
13.7. Tartományok Még egy optimalizálási eszközt említünk meg az SRM lehetőségei közül. Ezek a tartományok, amelyek -- a munkacsoportok mintájára -- felhasználói csoportok megkülönböztetésére szolgálnak. Elmondható ugyanis, hogy a felhasználók szokásait összefüggésbe lehet hozni az általuk üzemeltetett munkák tulajdonságaival. Egy tartomány az SRM-mel önállóan ütemezhető, adott felhasználói csoporthoz tartozó munkatípus halmaz. Minden tartományra elő lehet például írni egy minimális és maximális multiprogramozhatósági szintet. Az SRM a multiprogramozás fokát az adott tartományból a tárban lévő munkák számával veszi egyenlőnek. Ezt az értéket igyekszik az előírt korlátok között tartani. A tartományok emellett eltérő súllyal vehetnek részt az erőforrásokért vívott versengésben. Az ezt szabályozó tényezőt versengési indexnek nevezzük, és értékét minden tartományra a rendszer üzembeállításakor kell megadni. Amikor az SRM arról dönt, hogy melyik tartományból hozzon be az aktív sorba egy folyamatot, akkor előnyben fogja részesíteni a nagyobb versengési indexű, illetve a minimálishoz közelebb eső multifaktorú tartományok folyamatait. Megfordítva, amikor ki kell szorítani egy folyamatot a túl nagy rendszerterhelés miatt, akkor az SRM az áldozatot a legalacsonyabb versengési indexű vagy a maximális multifaktorhoz közelebb eső multifaktorú tartományokból választja. Ennyi legyen elég az SRM emberi heurisztikát utánzó képességeinek bemutatásából, de megemlítjük, hogy az algoritmus tökéletesítésén talán még mindig dolgoznak.
13.8. Rendszercélok és taktikák, rendszerhangolás Az SRM lehetővé teszi, hogy a rendszergeneráláskor megtervezett végrehajtási csoportokkal,
terhelési szintekkel, terhelési sablonokkal, végrehajtási periódusokkal, ISV-kel és tartományokkal igen tág határok között változtathassuk a számítógépes rendszerünkben elérendő célokat. Például, dönthetünk úgy, hogy úgyis nagyon erős CPU-nk van, ezért a CPU-időt kihagyhatjuk az optimalizálásból. Nagy teljesítményű, drága, "pénzkereső" hardver-arzenál esetében viszont jól felfogott érdekünk minden erőforrás optimális kihasználása. Az SRM--szoftver birtokában a stratégiai és taktikai célok kitűzése az említett táblázatok megadásával lehetséges. Lényeges momentum, hogy az alkalmazónak nem kell emiatt kifejezett programozásba bonyolódnia. Igen bonyolult politikák definiálása is megúszható egy alkalmas paramétersereg megadásával. Az persze nem várható el, hogy a paraméterek beállítását egyből eltaláljuk. Már említettük azt is, hogy a számítógépes rendszerek többé-kevésbé jellegzetes időbeli terhelési diagramot futnak be. Belátható, hogy a kialakított politikát időről időre felül kell bírálni, és ennek megfelelően az SRM paramétertábláit át kell definiálni. Ezt a munkát nevezzük rendszerhangolásnak. Itt jegyezzük meg, hogy más hardvereken és más operációs rendszerekben is alkalmaznak működésoptimalizálási eszközöket, amelyek heurisztikus jellegű döntési algoritmusokat szimulálnak. Ilyen eszköz van például a UNIX-ban, a VAX/VMS-ben és az OS/2-ben, amelyek egyes verzióiban feladattípusonként alkalmasan választandó prioritásintervallumokat lehet meghatározni, és a prioritások automatikus, ideiglenes megnövelése segíti a lassan haladó folyamatok előrejutását, de ennél "trükkösebb" algoritmusokat is használnak.
13.9. Gyakorlatok 13.9.1.
Mi a rendszerhatásfok-vezérlők szerepe?
13.9.2.
Mi az IBM OS/MVS SRM?
13.9.3.
Mit nevezünk heurisztikus algoritmusnak?
13.9.4.
Mi alapján dönt az SRM?
13.9.5.
Mi a szolgáltatás egysége és hogyan definiáljuk?
13.9.6.
Mi a terhelési szint, a végrehajtási csoport, a terhelési sablon és a végrehajtási periódus szerepe az SRM optimalizálási tevékenységében?
13.9.7.
Mi az intervallumokra bontott kiszolgálás szerepe?
13.9.8.
Mit nevezünk tartományoknak az SRM szempontjából, és mit lehet velük elérni?
13.9.9.
Hogyan lehet kialakítani az SRM-mel egy rendszerstratégiát és taktikát?
13. Mi a szerepe a rendszerhangolásnak, és hogyan végezhető el?
OS14V08.RTF,ZSP,2001-04-23
14. VIRTUÁLIS GÉPEK
{Nos, ez a fejezet már nem úszhatta meg alaposabb átírás nélkül így 2001. táján! – ZSP} A virtuális gépek koncepciója annak kapcsán született, hogy a gépek üzemeltetésekor kellemetlen több operációs rendszer használata. Az egyes operációs rendszerek betöltögetése sok időt rabol el (különösen, ha naponta elég gyakran kell váltogatni őket). Ebből az egyik szokásos kiút az, hogy a számítóközpont gépidőbeosztást készít, amelyben előírja, hogy mikor, melyik operációs rendszert lehet használni. Ez sérti ugyan a végfelhasználók érdekeit, de a hajdan nagyhatalmú számítógépüzemeltetők jellemző "attitűdje" volt. Végül azonban egyes nagygépes felhasználók érdekeltté váltak abban, hogy több operációs rendszert lehessen egyidejűleg üzemeltetni ugyanazon a hardveren. Maguk az operációs rendszerek fejlesztői is szenvedtek egy ilyen lehetőség hiányától. Számukra különösen kedvező lett volna, ha a fejlesztés alatt álló operációs rendszer régi és új változatát egymás mellett használhatták volna. A virtuális gépeket olyan szoftver valósítja meg, amely a hardver erőforrásokat több operációs rendszer között osztja szét. Az egyes operációs rendszerek úgy viselkednek, mintha mindegyikük külön gépet birtokolna. Így akár egyazon operációs rendszer különböző verziói is egymás mellett futhatnak ugyanazon a hardveren egy-egy virtuális gépen. {Tulajdonképpen egy “multioperációsrendszeri” esettel állunk szemben. Több felhasználó, folyamat, szál helyett több operációs rendszer multizik. -- 2001} Történeti érdekesség, hogy a témakört tulajdonképpen elég korán, az IBM 7044X-7044M projekt kapcsán kezdték el vizsgálni. Az IBM a szerzett tapasztalatokat a VM/370-es rendszerben hasznosította.
14.1. Több operációs rendszer egy gépen A virtuális gépek koncepcióját sematikusan a 14.1. ábra mutatja be. Mi a témakört az IBM VM/370es rendszere, mint legszélesebb körben elterjedt ilyen típusú nagygépi szoftver, kapcsán elemezzük. Az IBM a VM/370-es rendszert azért hozta létre, hogy a korábban 360-as sorozatú hardvert használó alkalmazói az új, 370-es sorozatú hardveren lehetőséget kapjanak a régebbi operációs rendszerekre kidolgozott programok zökkenőmentes használatára. Ezt a szisztémát az IBM már korábban is alkalmazta. A 360-as gépeken is voltak olyan emulátor programok, amelyek az IBM régebbi gépein futó programok futtatását tették lehetővé. Ezekkel az emulátorokkal futtatható programok azonban korábban monoprogramozható gépeken futottak, így az emulátor programok könnyen tudták utánozni a programhoz szükséges futásideji környezetet akár az új hardveren futó multiprogramozott környezetben is. Ehhez képest komplett operációs rendszerek számára már nem
ilyen egyszerű két szinten multiprogramozott környezetet biztosító emulátort írni, hiszen most operációs rendszermagokat kell multiban futtatni, amelyek maguk is multizni akarnak. Az utóbb mondottakból talán rögtön kitűnhet, hogy a virtuális gépet megvalósító szoftvernek szintén operációsrendszeri funkciókat kell megvalósítania. A szokásos operációs rendszeri környezethez képest persze vannak speciális sajátosságai. Jellegzetessége például, hogy lényegében csak rendszermagból áll. Ezt a rendszermagot mi a megkülönböztetés kedvéért hypervisornak hívjuk. A virtuális gépeken futó operációs rendszerek, korábbi "eszmefuttatásainknak" megfelelően (l. 5.7. Alrendszerek), a hypervisor alrendszereiként futnak. Méghozzá individuális alrendszerként, tehát nem támaszkodnak semmiféle hypervisor támogatásra, különben a virtuális gépen futó operációs rendszerbe is bele kellene nyúlni, s ez esetünkben lehetetlen igény. P P P P P P P P P P P 1 1 1 2 2 3 3 3 3 4 4 1 2 3 1 2 1 2 3 4 1 2 <-><-><--> <--><-> <--><-><--><---> <--><-> +-----------+ +---------+ +----------------+ +---------+ | OPR1 | | OPR2 | | OPR3 | | OPR4 | +-----------+ +---------+ +----------------+ +---------+ +-----------+ +---------+ +----------------+ +---------+ | VG1 | | VG2 | | VG3 | | VG4 | +-----------+ +---------+ +----------------+ +---------+ +------------------------------------------------------+ | "Virtuális gépek"-et emuláló operációs rendszer | | (HYPERVISOR) | +------------------------------------------------------+ +------------------------------------------------------+ | | | HARDVERBÁZIS | | | +------------------------------------------------------+ A hardverbázison a hypervisor működik, amely virtuális gépeket emulál. Esetünkben négy virtuális gép (VG1,VG2,VG3,VG4) működik a hardveren, amelyeken négy operációs rendszer (OPR1,OPR2,OPR3,OPR4) fut. Az operációs rendszerek felügyelete alatt különböző számú program (Pij) fut, többé-kevésbé elfoglalva a virtuális gépek erőforrásait. 14.1. ábra. Több operációs rendszer egy gépen Az IBM VM/370-es rendszer ilyen hypervisor szolgáltatásokat tud nyújtani az összes megelőző verziójú, 360/370-es sorozatú hardveren futó operációs rendszer számára, így felügyelete alatt működhet DOS, OS/MFT, OS/MVT, DOS/VS, DOS/VSE, OS/VS1, OS/SVS és OS/MVS operációs rendszerek (kis túlzással) akármilyen keveréke. Ezt már említettük korábban a 2. fejezetben, de a hypervisor szolgáltatásokat ott csak előre jeleztük.
14.2. Megvalósítási kérdések 14.2.1. A hardver emuláció problémái Processzorkezelés Minden hypervisorral emulált virtuális gép -- a hypervisorral együtt -- osztozkodik a CPU erőforrás(ok)on (multiprocesszoros hardveren is futhat a hypervisor!). A hypervisor diszpécserének kell szétosztania a CPU-idő(ke)t valamilyen ütemezési politika szerint, amely azonban a hatásfokcsökkenés megelőzésére csak nagyon egyszerű algoritmusú lehet, többnyire időszeletelést jelent. A nagy teljesítményű hardverek persze már közbenső szintű ütemezővel is felszerelt, működésoptimalizálást biztosító hypervisort is elbírhatnak (a VM/370 továbbfejlesztéseiben például van ilyen). Megszakításkezelés A hypervisor nem túl egyszerű feladatai közé tartozik a megszakítások emulálása. Lehetővé kell tenni, hogy a virtuális gépen futó rendszermagok megszakítás-kezelői el tudjanak indulni, és működőképesek legyenek a megfelelő hardverállapot birtokában. Ugyanakkor nem szabad elveszítenie a vezérlést a megszakításokon, ezért mindig a hypervisor úgymond nulladik szintű megszakítás-kezelő rutinjainak kell működésbe lépni minden megszakításkor. Privilegizált működés A processzor privilegizált működési állapotait (a korábban mondottak szerint) az operációs rendszernek kell fenntartania a védelmi rendszer igényei miatt. Mi a helyzet egy ilyen kétszintű operációs rendszer esetében? Ha a hardvernek több privilegizált állapota lenne, amelyek hierarchikus védelmet biztosítanak, akkor lehetne szó a hypervisor és a virtuális gépeken futó operációs rendszerek közötti esetleges osztozkodásról. Persze, ennek is útját állhatja, hogy a virtuális gépen futó operációs rendszerek már maguk is felosztották saját védelmi rendszerük megszervezése során a hardvervédelmi szinteket. A helyzet ilyenkor súlyosbodik, mert akkor a hypervisorral ezt a szétosztott vezérlő-állapothalmazt kell még tovább osztani. Ha el akarjuk érni, hogy a hypervisor akarata érvényesüljön, akkor funkcióinak zömében erősebb privilégiumokkal kell rendelkeznie, mint a virtuális gépen éppen kiszolgált rendszermag védelmiszint igénye. Ami a VM/370-et illeti, a helyzet egyszerű. A 360/370-es gépsorozat csak egyetlen vezérlő állapotot ismer. Ennek az a következménye, hogy a VM/370 többnyire uralja ezt a védelmi szintet, és csak a legszükségesebb esetekben adja át a virtuális gépeken futó rendszermagoknak. A PC-s számítógép-szigetek hálózatba kötését forradalmi módon megoldó NOVELL ANW/286, IBM AT gépekre kidolgozott, lokálishálózat-vezérlő operációs rendszernek -- amelynek szintén hypervisor funkciókat kellett ellátnia, olykor multiprocesszoros, elosztott erőforrású környezetben -- az OS/2-t megelőző időszakban szintén nem voltak gondjai. Az MS--DOS operációs rendszer ugyanis nem használta ki az INTEL 80286-os hardver virtuális védett üzemmódját. Továbbá, lényegében monoprogramozott hardvert kellett emulálni. Így nem volt nehéz biztosítani az MS--DOS tökéletes emulációját. {Innen más! – 2001.} A privilegizált állapotokat is használó OS/2 és a későbbi Windows NT összeházasítása a NetWare-rel azonban végül lehetetlenné vált. Ezért a NetWare alkalmazásszerveri funkcióit nem erőltették tovább, megmaradt csak állomány és nyomtatószerveri funkcióban, amit azután hálózati operációs rendszer címszó alatt reklámoztak. Mivel pedig később ezek a Novell funkciók már minden piacképes operációs rendszernek a részét képezték, a NetWare alól elkezdett kicsúszni a talaj. Továbbélése csak a meghódított alkalmazói tábor hűségén, és néhány technikai előnyén múlik (stabilitás, ami az alkalmazók szemében egyre fontosabb szempont!). [Az olcsó hálózati technológiát megalapozó
Novellnek végül más piaci területeket kellett megcélozni: munkacsoport technológia, menedzsment. Ez sikerült is!]
hálózat-
Tárkezelés Nemcsak a CPU-t, hanem más erőforrásokat is szét kell osztani a virtuális gépek között. A hypervisornak tehát szét kell osztania az általában egyetlen valódi tárat a hypervisor és a virtuális gépek között. Az operatív tár rendszermagok szempontjából kritikus tármezőit természetesen a hypervisornak kell elfoglalnia. Csak így biztosítható például megszakítási vektorok útján a már említett nulladik szintű megszakítás-kezelők indítása. Természetesen a virtuális gépeken futó operációs rendszerek szintén ezeket a tárhelyeket birtokolják olyankor, amikor egyedül futnak a gépen. A virtuális gépen futó operációs rendszereknek szimulálni kell, hogy az általuk megkövetelt tárcímmezőben érezzék magukat. Ez csak virtuális tárkezelést támogató hardverek segítségével érhető el. Nyugodtan kimondhatjuk, hogy tökéletes hypervisor szolgáltatásokat csak virtuális tárkezelésű hardverrel lehet elérni. Az IBM 370-es hardver e követelménynek többé-kevésbé megfelel, ezért jöhetett létre a VM/370. A virtuális gépeken a valós tármező értékét többnyire korlátozhatjuk, de a hypervisorral a virtuális tárcímek tartományát a hardverrel támogatott teljes címtartományra biztosítani kell. Különben korlátoznunk kellene a virtuális gépeken futó környezeteket, ami kritikus esetben gondot okozhat. A fenti összes feltételnek jelenleg egyetlen, hypervisor funkciókat is ellátó, ismert operációs rendszer tud megfelelni, az INTEL 80386-os mikroprocesszorokra kidolgozott XENIX/386. Ez kihasználja a mikroprocesszor privilegizált állapotain túl a 8-szintű virtuális gépi támogatását is. Ezért a XENIX/386 alatt futhatnak virtuális MS-DOS gépek, virtuális XENIX/286 gépek és a virtuális OS/2 gépek emulálása is valószínűleg megoldható lesz. A XENIX/386 ehhez minden virtuális gépen biztosítani tudja a megfelelő operatív tárakat és a szükséges privilégiumokat. (Ez nem ment minden nehézség nélkül, mert a mikroprocesszorban hibák vannak, amelyeket az INTEL már csak a majdani 80486-ban ígért kijavítani.) {2001: A processzorok, mint általában a műszaki alkotások, ma sem mentesek a hibáktól. Egyre több olyan processzor születik azonban, amelyek kiválóan támogathatnak virtuális gépi hypervisor funkciókat. Ezeket a legújabb operációs rendszerek, UNIX-ok, Linux-ok, Windows NT családfa, Be-OS, Mac OS X., stb., ki is tudják használni.} B/K--vezérlő szolgáltatások A virtuális tármezőbe helyezett, virtuális gépen futó rendszermagok természetesen nem tudják közvetlenül lebonyolítani a B/K--átviteleket. Ezeket szimulálni kell számukra. A hypervisor B/K-vezérlőjének épp ez a feladata. A hypervisor teljes mértékben átveszi a vezérlő állapotot igénylő algoritmusok szerepkörét úgy, hogy a rendszermagok eredeti FLIH kezelői elé közbeillesztett (appended) rutinokat aktivizál. Az előtét programok, amint lehet, átadják a vezérlést a támogatott rendszermag eredeti rutinjainak. 14.2.2. Hypervisor funkciók Rendszeradminisztráció A hypervisorok -- szűkített szolgáltatásokkal -- az operációs rendszerek azon rendszeradminisztrációs szolgáltatásait valósítják meg, amelyeket a 2. fejezetben tárgyaltunk. A szolgáltatásszűkítés oka, hogy túl bonyolult algoritmusok a virtuális gépeken futó operációs rendszerek
rendszeradminisztrációs idejével összeadódva nagyon lecsökkentenék a teljes számítógépes rendszer hatásfokát. A hatásfok-csökkenés egyébként elkerülhetetlen, azt csak enyhíteni lehet néhány módszerrel. Programfejlesztési támogatás A szűkített szolgáltatáshalmaz egyik legjellemzőbb tünete, hogy a hypervisor mellett nem használnak programfejlesztési funkciókat biztosító szoftver-eszközöket. A példaként emlegetett VM/370-ben sincs ilyen szolgáltatás. A VM/370 alatt használható CMS interaktív fejlesztőrendszer nem közvetlenül a hypervisor szolgáltatásait használja. A CMS maga egy külön, on-line programfejlesztésre specializált operációs rendszer, amely a VM/370 egy virtuális gépén fut, tehát nem része a VM/370-nek. A 2. fejezetben részletesen tárgyalt programfejlesztési támogatások közül a hypervisorban talán egyedül a hardver-nyomkövetési támogatás maradt meg. A helyzet ugyanis az, hogy ezt a funkciót is emulálni kell a virtuális gépek számára, így például biztosítani kell a virtuális CPU konzolhoz való hozzáférést. Alkalmazói támogatás A virtuális gép szoftver üzemeltetése a szokásos operációs rendszeri üzemeltetési problémákon -- a hypervisor operátori kezelésén -- túl egyéb funkciókat is igényel. Az operátori interfész ezt operátori kezelőnyelvvel biztosítja. Az operátori interfésznek -- a hypervisor üzemállapotainak befolyásán túl -- eszközei vannak virtuális gépek indításához, ami egyrészt egy virtuális konzol hozzárendelését jelenti, másrészt tárgazdálkodással kapcsolatos döntéseket igényel. Ezt a funkciót a VM/370-ben a VM vezérlőprogram (CP = Control Program) látja el. Ezzel lehet virtuális konzolokat kijelölni egy valódi terminálra, és erőforrásokat hozzárendelni a virtuális géphez a valós gépi erőforrások szétosztásával. A CP-vel azután be lehet töltetni a használni kívánt operációs rendszert az újonnan definiált virtuális gépbe. 14.2.3. Működésoptimalizálás A hypervisor és a normál rendszermagok funkciói elkerülhetetlenül párhuzamosságokat okoznak, illetve, "ütik egymást". Legkritikusabb példaként említhető a virtuális tár lapozása. A probléma aligha oldható meg nagyobb hatásfokveszteség nélkül. Kétféle kiút van: * A hypervisor teljesen átveszi a lapozást, és ezzel magába integrálja a virtuális gépeken futó operációs rendszerek vonatkozó funkcióit. Ez bonyolítja a hypervisor funkciókat, és egyben megszünteti a támogatott normál operációs rendszerek individuális alrendszer voltát (mellesleg, a több változatban lehetséges virtuális lapméretek, szegmensméretek miatt a hypervisorban minden variációra fel kell készülni); * A hypervisor működését speciális hardverutasításokkal vagy más hardvereszközökkel (az INTEL 80386-ban például taszkvezérlő utasításokkal és speciális regiszterekkel) támogatják, ami pedig azt igényli, hogy a hypervisort a hardver egy módosított változatán futtassák. A VM/370 változatai mindkét említett megoldásra adnak módot, de ez opcionális lehetőség. Az újabb 370-es hardverekhez mindenesetre vásárolható lapozásgyorsító hardver-utasításkészlet is.
14.3. Kapcsolat az elosztott rendszerekkel Az 5.7.-ben, az alrendszerek kapcsán elemeztük, hogy a számítástechnikai történelemben hogyan fejlődött az alrendszeri elv. Az alrendszerek az egygépes operációs rendszerek kapcsán jelentek meg. Az operációs rendszerek azonban működhetnek akár multiprocesszoros gépen is. Ilyenkor tulajdonképpen több gép erőforrásait osztjuk szét több alrendszer között. Ez a modell egy fokozattal általánosabbá válik a virtuális gép megjelenésével. A legáltalánosabb eset persze az, amikor a hardver erőforrások több CPU-t jelentenek, amelyek mindegyikén más operációs rendszer fut, de valamilyen hálózatvezérlő programmal ezek működését összekapcsoljuk többé-kevésbé egységes számítógépes rendszerré. Erről a 3. fejezetben volt már szó. Ott megemlítettük, hogy alapvetően kétféle konfigurációt lehet megkülönböztetni: * a helyi (lokális) és távoli számítógép-hálózatokat és * az elosztott intelligenciájú rendszereket. A két konfigurációtípus közötti alapvető különbség a csatolás erősségében keresendő. Míg a hálózatok (még a szorosabb csatolást biztosító helyi hálózatok is) csak kevéssé koordinált, funkcionálisan nem specializált számítógépes rendszereket jelentenek, addig az elosztott intelligenciájú rendszerek csatolása szoros, részei meghatározott funkciókra specializálódnak (például adatbázisgép). A két igény meglehetősen eltérő, hypervisor jellegű vezérlőfunkciókkal támogatható. A hálózatok esetében még az is előfordul, hogy nincs a rendszerben hypervisor funkciót biztosító szoftver, hanem az együttműködő operációs rendszerek maguk szervezik meg kapcsolataikat a hálózat más tagjaival. Olyan ez, mint a 6. fejezetben tárgyalt, három programra korlátozott autonóm Round-Robin ütemezés esete (l. 6.2.ábra). Jól működő, biztonságos védelmi rendszerrel felszerelt, hálózati és elosztott rendszerek csak hypervisor funkciót megvalósító szoftver alkalmazásától várhatók el. Ilyen például a már emlegetett NOVELL NetWare LAN vezérlőprogram. {2001: Azóta ezek a funkciók lényegében mind beépültek a mai operációs rendszerek hálózati alrendszereibe, és legfontosabb elemeik a címtárak: NDS, LDAP, MS-DS, UDS stb.} {2001:} A mai IBM nagygépi hardvereken futó virtuálisgépi lehetőségekre jellemző, hogy már olyan, a régi IBM hardver-szoftver koncepcióktól is távol eső, operációsrendszeri támogatások is léteznek, mint például a legújabb, UNIX-98 szabványoknak is megfelelő, UNIX-felület és Linux emuláció megléte.
14.4. Mintapéldák 14.4.1. Az IBM VM/CMS interaktív fejlesztő rendszer A CMS (Conversational Monitor System = párbeszédes felügyelő rendszer) éppen abból a meggondolásból született, hogy a VM/370 csak hypervisor szolgáltatásokat nyújt. Egy ilyen hypervisor környezet azonban önmagában "kegyetlenül sivár". A felhasználó az égvilágon semmi mást nem tud vele kezdeni, mint virtuális gépeket definiálni és azokba operációs rendszereket betölteni. Hamar felmerült, hogy egy kisebb operációs rendszert is adjanak mellé. Egyébként is szükséges egy mintapélda ahhoz, hogy ki lehessen próbálni a VM/370 működőképességét. A VM/370-el ezért együtt adják a CMS-t, amelyet interaktív programfejlesztő rendszeri célokra specializáltak. A CMS tehát egy mini operációs rendszer, amely a VM/370 alatt fut egy virtuális gépen. A CMS-nek van egy parancsértelmezője (mivel interaktív rendszer), amelynek szolgáltatásait a
CMS által birtokolt virtuális géphez tartozó terminálokon lehet igénybe venni. A parancsnyelvhez egy sereg segédprogram (utility), szövegszerkesztő és a VM/370 alatt futó más operációs rendszerek programozási nyelveit támogató nyelvorientált fejlesztő programok (FORTRAN, PL/I, PLIOPT stb. DOS és OS változataihoz) csatlakoznak. A CMS természetesen időosztásos üzemmódban dolgozik, ami a megcélzott munkahalmaz szempontjából ideális. Érdekessége, hogy kapcsolatot tud tartani a 360/370-es hardvereken futó más operációs rendszerek adatállomány-szerkezeteivel, sőt alkalmas a köztük felmerülő kommunikáció és konverzió lebonyolítására, de használ az összes többitől eltérő adatkezelési módszert is. A speciális CMS adatkezelés azt jelenti, hogy bizonyos állományköteteket egészen a CMS-nek kell áldoznunk. A CMS kötetek logikai szerkezete teljesen eltérő, és automatikus dinamikus területfoglalási módszert alkalmaz. A módszer lehetővé teszi, hogy a felhasználónak ne kelljen külső elaprózódási problémákkal bajlódnia, amint az az IBM más operációs rendszereiben használatos adatszervezési módszerek esetében előfordul. A cél természetesen az, hogy az interaktív felhasználóknak lehetőleg minél problémamentesebb környezetet lehessen teremteni. A CMS környezet a programfejlesztésen túl használható más, interaktivitást igénylő feladatok megoldására is. Ilyen alkalmazási példa az ellenőrzött adatrögzítő rendszerek üzemeltetése. Az adatgyűjtő rendszerben felhalmozott adatokat egyszerűen át lehet küldeni egy másik virtuális gépre az ottani operációs rendszer felügyelete alatt működő program bemeneteként. Minthogy az IBM operációs rendszerek elég sokáig szűkölködtek az interaktív támogatás terén, a CMS igen nagy sikert aratott az IBM felhasználók körében, s egyben sikert hozott a VM/370 hypervisornak is. Megemlíthető, hogy a VM/370 programcsomag a CMS mellett másik két mini operációs rendszert is tartalmazhat opcionálisan. Ezek egyike az RSCS (Remote Spooling Communication System), amelynek célja a VM/370 távoli (remote) termináljai és virtuális gépei közötti adatátvitel vezérlése. Segítségével kapcsolat létesíthető a virtuális gépeken futó operációs rendszerek munkabeviteli alrendszerei (RJE, CRJE, HASP, JES stb.) és a terminálok között, továbbá terminál-terminál összeköttetések is létrehozhatók. A másik mini operációs rendszer az IPCS (Interactive Problem Control System), amely a hardveresek munkáját támogatja. Segítségével a távoli eszközöket is a számítóközpontból lehet tesztelni. 14.4.2. Osztott hálózatok, mint virtuális gépek Az elosztott rendszerek kapcsán -- a könyv eredeti kiadásában -- az IBM PC család személyi számítógépeire alapított, "futótűzként" terjedő, lokális hálózatok (LAN = Local Area Networks) kulcsszoftverét, a NetWare hálózatvezérlő programot elemeztük a hypervisor tulajdonságokat mutató hálózati operációs rendszer példáján. A NetWare ma már kevésbé időszerű, ezért -- külön alpontocskában -- más megoldásokra is kitérünk: a DOS-Windows emulációkra és a Java virtuális gépre. {2001!} A PC-kre alapított lokális hálózatok célja -- eredetileg -- a drágább, egy-egy géphez kötött erőforrások (Winchester-tárak, nyomtatók) decentralizált, megosztott, gazdaságosabb használatának biztosítása, lehetőleg a hálózatba kötött összes gépről. Ugyanakkor a hálózatban működő egyedi gépek monoprogramozott üzemmódra vannak felkészítve. Hálózatba kapcsolva végeredményben egy multiprogramozott környezet jön létre (jóllehet minden CPU-n különkülön diszpécser működik). Ez, az ilyen környezetekben nélkülözhetetlen elosztott védelmi rendszer igényét veti fel. A felhasználók, ha csak jóakaratukra bízzuk a dolgot, nem fognak egymással szemben tisztességesen viselkedni {2001: wormok, crackerek! -- szemben a régi jó szép időkkel: UNIX people are friendly guise -- a UNIX-osok jó barátok -- még jelszavakat sem használtunk!}. Olykor fel sem tűnik nekik, hogy éppen hibát követnek el, hiszen a másik felhasználó "valami drót másik végén lóg", és ezért nem is igazán észlelhető.
{2001:} A Novell NetWare ezeket a célokat oldotta meg, annak idején a kor színvonalát messze meghaladó szinten. Azóta azonban a tulajdonképpen a UNIX-okban született Internetes hálózati technológia lényegében minden mai operációs rendszerbe beépült, hálózati alrendszerként. Még a Novell is kénytelen volt áttérni a NetWare későbbi változataiban a saját, lokális hálózatokban optimális IPX/SPX saját protokolljáról alapértelmezésként a TCP/IP protokollra. A NetWare védelmi rendszere mindenesetre már kezdetben túllépett a UNIX-os "rwx" védelmeken, majd a 4es változatban bevezetett Novell Directory Services (NDS) révén az igazi elosztottrendszeri támogatások terén is messzire előre lépett a korábbi sima login bejelentkezési jelszavas diliházhoz képest (az alkalmazóknak ezernyi jelszót kellett volna fejben tartani, de ezt általában lelazsálták, kiváló alapot adva a betörőknek stb.). A NetWare érdemeit a hardverárak drámai csökkenése jelentősen megtépázta (diszk és nyomtatóárak a padlón!), a védelmi rendszerek pedig más operációs rendszerekben is javulni kezdtek. A PC-tömegpiacot a Microsoft SMB (Server Message Block, UNIX: SAMBA)-protokoll alapú, és a Windows for Workgroupsban bevezetett egyszerű erőforrás-elosztási, később CIFS-nek (Common Internet File System -- általános Internet állományrendszernek) is elnevezett, DOS-os NET parancsokkal is támogatott megoldás alapozta meg. Ez sokáig konkurált a UNIX-osok Sun Microsystems által kidolgozott NFS (Network File System -- hálózatos állományrendszer) elosztott hálózati megoldásával, de a Windows 2000 idejére a Microsoft is elkezdett beállni az Interneten uralkodó szélirányba, a címtárakon keresztül (LDAP, Active Directory) támogatva a mai legkorszerűbb osztottrendszeri megoldásokat. A történeti hitelesség kedvéért meg kell említeni, hogy nem a Novell használta először az OSI X.500 alapú címtári technológiákat, hanem a Banyan cég a VINES nevű, UNIX-alapú LAN-hálózati szoftverében (Street Talk), kevés sikerrel. 14.4.3. Emulátorok -- a gépszimulátorok {2001!}
Sokan kérdezik, mi köze a Java Virtual Machine (JVM) kifejezésnek a virtuális gépekhez. Nos, nem a hagyományos, fentebb tárgyalt virtuális gépről van szó, hanem egy emulátorról. Miközben a Sun egyik fejlesztő csapata, mérhetetlen mennyiségű Java kávé elfogyasztása közben, megalkotta a Java nyelvet és a kapcsolódó bájtkódot, lényegében olyan nem létező (tehát ilyen értelemben virtuális) gépre készített megoldást, amihez soha nem létezett korábban "natív" hardver. Azóta a Sun tervezett három chip-et is a támogatására (pico-, micro- és super-Java), de csak a legkisebb készült el, ami például mobiltelefonokba építhető Java megoldásokat támogathat. Ehhez készült egy JavaOS mini-operációsrendszer is. Fontos emulátor megoldás az Intel 386-os korszakban bevezetett VM86 üzemmód, aminek
segítségével a 32/64-bites Intel operációs rendszereke alatt emulálhatók a 16-bites korszak szoftverei. Így működik az OS/2 DOS-compatibility box, minden NT 16-bites taszk, és a UNIX/Linux DOS/WIN emulációja.
14.5. Gyakorlatok 14.5.1.
Mit nevezünk virtuális gépnek, és mire használható?
14.5.2.
Hogyan lehet egyidejűleg hardverbázison?
14.5.3.
Mi volt az IBM célja a VM/370-es szoftver kidolgozásával?
14.5.4.
Milyen típusú alrendszerként futnak az operációs rendszerek a hypervisor felügyelete alatt? Miért?
14.5.5.
Milyen problémákat vet fel a virtuális gépek hardverének emulációja?
14.5.6.
Lehet-e a hypervisornak bonyolult ütemezési politikája? Milyen esetben?
14.5.7.
Mi a nulladik szintű megszakításkezelés szerepe?
14.5.8.
Mi a helyzet a privilegizált üzemmód szimulálásával?
14.5.9.
Miért csak virtuális tárkezeléssel felszerelt hardveren lehet igazi hypervisort megvalósítani?
12.9.3.
Mi a kapcsolat a számítógép-hálózatok vezérlőprogramjai és a hypervisor között?
12.9.4.
Virtuális gép-e a JVM, amely olykor böngészők kiegészítőjeként működik? {2001!}
12.9.5.
Vajon miért könnyebb emulálni egy PC-s operációs rendszert VM86 üzemmódban, mint valamely más architektúrájú processzoron? {2001!}
több
operációs
rendszert
futtatni
ugyanazon
a