KURZUS: Számítógépes folyamatirányítás

MODUL: A számítógép

3.4. lecke: Kiemelkedő jelentőségű programozástechnikai elemek 2.

Cél: A lecke célja, hogy a tananyag felhasználója

  • megismerje a megszakítás fogalmát és kiemelt fontosságát a folyamatirányító számítógépes rendszerekben;
  • megismerje a megszakításrendszer és -kezelés különböző szervezési formáit;
  • meglássa, hogy a közönséges szubrutinhívás és a megszakítás - mechanizmusuk formai azonossága mellett - elvileg és funkcionálisan milyen mélyen különböznek egymástól;
  • megismerje az adatkörnyezet fogalmát és a megszakítási rutinra háruló context-mentési kötelezettséget;
  • megismerje az újrahívási szituációt, az újrahívható rutin fogalmát és az újrahívhatóság feltételeit;
  • megismerje az I/O kezelés fogalmát, belássa az I/O kiemelt fontosságát;
  • megismerje a perifériák portjait és azok használatát;
  • megismerje a különböző I/O-kezelési formákat, alkalmazási javallataikat és ellenjavalltaikat.

Követelmények: Ön akkor sajátította el megfelelően a tananyagot, ha

  • el tudja mondani, mit értünk megszakítás és megszakítási rutin alatt;
  • ismertetni tudja a megszakításkezelés különböző fajtáit;
  • meg tudja fogalmazni a szubrutinhívás és a megszakításkezelés közti formai azonosságot és egyben a mély elvi különbséget;
  • meg tudja fogalmazni a context és az újrahívhatóság fogalmát;
  • fel tudja sorolni és jellemezni tudja az I/O portok fajtáit;
  • fel tudja sorolni és egyenként elemezni tudja az I/O-kezelés típusait.

Időszükséglet: 2 óra

Kulcsfogalmak:

  • megszakítás,
  • megszakítási rutin,
  • pollingos (megszakítás),
  • vektoros (megszakítás),
  • adatkörnyezet (context),
  • újrahívható(ság),
  • input/output kezelés,
  • port (és a portok fajtái egyenként),
  • készültség-bit (READY),
  • programozott I/O,
  • megszakításos I/O,
  • DMA.
1. A megszakítás (interrupt)

Ha van valami, ami a folyamatirányító számítógépekkel kapcsolatban a legfontosabb jellemzőnek, illetve követelménynek mondható, akkor az a megszakítás, illetve a megszakításrendszer megléte.

Jegyezze meg, hogy mit értünk megszakítás és megszakítási rutin alatt;

A megszakítás azt jelenti, hogy a számítógép egy tőle független, külső eseményre azonnal és úgy reagál, hogy az éppen futó programot felfüggeszti és egy olyan programot hajt végre, amely az eseményre vonatkozó válaszreakció leírását tartalmazza. Ezt a programot megszakításirutinnak (IT-rutin) szokás nevezni. A megszakítási rutin lefutása után a számítógép visszatérhet eredeti tevékenységéhez, azaz folytathatja a korábban felfüggesztett program végrehajtását.

Egy folyamatirányító számítógépnek legalább egy megszakítást, az óra-interrutot feltétlenül kezelnie kell. Az óra-interrupt egy periodikusan jelentkező impulzus, amely gép működését a külső, valós időhöz szinkronizálja. Az erre adandó válaszreakció - sok egyéb mellett - az, hogy a számítógép aktualizálja a belső, un. szoftver-órát. Erről és egyebekről a 6. modulban még bőven lesz szó.

Az egyes megszakítási okok fontossági sorrendbe állíthatók, vagyis minden okhoz prioritás rendelhető. Egy magasabb prioritású megszakítási ok megszakíthat egy alacsonyabb szinten futó (kisebb prioritású okhoz tartozó) megszakítási rutint is (1. ábra).

A megszakítási folyamat
1. ábra

Vannak olyan processzorok, amelyek eleve prioritásos megszakításrendszerrel rendelkeznek, vannak olyanok, amelyekhez megfelelő külső hardver-eszközt kell illeszteni a prioritásos kezelés megvalósításához, és vannak olyan esetek, melyeknél a prioritást az operációs rendszer (tehát a szoftver) rendeli az egyes okokhoz. A megszakításrendszerek általános vizsgálatakor sokszor igen nehéz megtalálni azt a határt, ameddig a hardver, és ahonnan a szoftver (az operációs rendszer) szabja meg a működést, ezért itt is konkrét megoldások tanulmányozása ajánlatos.

A legegyszerűbb eset az, amikor egy megszakítás-vezeték van és csak egy megszakítási ok. Ilyenkor a megszakítási folyamat pontosan úgy zajlik le, mint egy szubrutinhívás, csak a hívó utasítás nincs beírva a programba (nem is lehet!), ugyanis itt a hívást nem utasítás, hanem a megszakításjel megjelenése váltja ki. A processzor automatikusan a stackbe menti a megszakított program PC-jét, majd átadja a vezérlést egy adott címre (itt kell kezdődnie a megszakítási rutinnak). A rutin lefut, majd egy RET utasítással a stackből elővett cím alapján visszatér a megszakított programba. Ez a folyamat teljes egészében processzor-szinten zajlik le, sem kiegészítő hardver eszközt, sem az operációs rendszer közreműködését nem igényli.

Ha egy megszakítás-vezeték van, de azon több, különböző okból eredő megszakításkérés jöhet be, akkor azonosítani kell az okot, mert ettől függ a válaszreakció. A processzor itt is elmenti a megszakított program PC-jét és átadja a vezérlést egy címre. Ez a cím azonban most nem a megszakítási rutin kezdőcíme (nem is lehet az, hiszen még nem tudni, melyik rutinnak kell lefutnia), hanem az operációs rendszer (egyik) belépési pontja. Az ok azonosítása az operációs rendszer feladata. Erre két megoldás van: a lekérdezéses (polling) és a vektoros módszer.

  • A pollingos módszernél az operációs rendszer végigkérdezi az összes potenciális megszakítás-generáló külső eszközt. Amelyiknél kiderül, hogy ő okozta az interruptot, a rendszer az ahhoz rendelt megszakítási rutinnak adja át a vezérlést. A rutin, lefutása után - a szoftver szervezésétől függően - vagy az operációs rendszerbe, vagy közvetlenül a megszakított programba tér vissza. Az első esetben az operációs rendszernek kell gondoskodnia a megszakított program folytatásáról, a második esetben ez automatikusan megtörténik.
  • A vektoros megoldásnál a megszakítást okozó külső eszköz a megszakításjellel egy időben egy egyedi, azonosító kódot (mondhatjuk: a névjegykártyáját) helyez az adatbuszra. Ilyenkor nincs szükség lekérdező ciklusra, mert az eszköz maga felfedi kilétét. Az azonosító kód az un. megszakításvektor, ez célszerűen egy olyan címtáblázat indexe, mely az egyes okokhoz (eszközökhöz) rendelt megszakítási rutinok kezdőcímeit tartalmazza. Az index alapján az operációs rendszer kiválasztja a megfelelő címet, és átadja a vezérlést a megfelelő rutinnak. A rutinból való visszatérés az előző pontban leírtak szerint zajlik le.

Olyan - az előzőnél direktebb - vektoros megszakítás is van, ahol a megszakításvektor egy CALL-jellegű rövid utasítás kódja, a kódban foglalt implicit címmel. Beérkezésekor a processzor ezt azonnal végrehajtja, mint egy közönséges szubrutinhívást. A visszatérés közvetlenül a megszakított programba történik. Ez a folyamat is teljes egészében processzor-szinten zajlik le, nincs szükség az operációs rendszer közbeékelődésére.

Próbálja meg - ismeretei teljes bevetésével - a lehető legrészletesebben átgondolni a fentebb említett megszakítási folyamatok lejátszódását! Felváltva képzelje magát a processzor, az operációs rendszer, a főprogram és a megszakítási rutin helyébe! Ki, mikor mit csinál? Akkor gondolta át helyesen az eseményeket, ha valóban belátta, ha biztosan meggyőződött arról, hogy a folyamat végén a vezérlés visszakerült a főprogramhoz és az zavartalanul folytatja futását. (Nyugalmas, csendes helyre lesz szüksége...)

A prioritásos megszakításrendszereknek biztosítaniuk kell, hogy egy megszakítás bekövetkeztekor (annak kiszolgálása közben) nála alacsonyabb szintű megszakítások ne juthassanak érvényre. Ez a megszakítások szelektív tiltását jelenti, amely részben hardver-, részben szoftver-eszközökkel valósítható meg. Ennek részleteire itt nem térünk ki.

A megszakítási rutinok formailag közönséges szubrutinok. A szubrutinhívás és a megszakítás között van azonban egy nagyon lényeges, elvi különbség. Az ugyanis, hogy a szubrutinhívás programozott, a megszakítás viszont nem. A programozó a program írásakor pontosan tudja, hogy melyik szubrutint, hol akarja aktivizálni, és azt és ott fogja meghívni. A megszakítást viszont a külvilág aszinkron módon és véletlenszerűen generálja. A programozó erre nem készülhet fel, mert nem láthatja előre, hogy a programját majdan, futás közben mikor, illetve mely ponton fogja egy külső esemény megszakítani. A programozó tehát nem írhatja elő a programban, hogy mi a teendő akkor, ha azt megszakítják. (Ezért nagyon rossz, a lényeget elködösítő kifejezés a "programozott megszakítás".)

Van egy kérlelhetetlenül szigorú elv: okozza bármi a megszakítást, legyen bármilyen a megszakításrendszer, a megszakított programnak nem szabad észrevennie, hogy megszakították. A megszakítás alatt a program ájultan hever, és amikor magához tér, mindent úgy kell találnia, ahogyan ájulata előtt volt, ellenkező esetben a továbbiakban hibásan fog működni. Kevésbé plasztikusan, de pontosabban fogalmazva ez a következőket jelenti. Minden program felépít maga körül egy adatkörnyezetet context), amely a program futása közben, annak hatására változik. A megszakítási rutin ettől idegen, tehát működésével nem szabad, hogy befolyásolja a megszakított program contextjét. Ezért azt megszakításkor el kell menteni és a vezérlés visszaadása előtt vissza kell állítani. A megszakításrendszer kialakításától függően ez vagy az operációs rendszer, vagy a megszakítási rutin feladata, sőt kötelessége. Csak az a kérdés, mi alkotja a contextet, mit kell elmenteni, mert nyilván az egész memóriát nem lehet. A válasz elég egyszerű: minden olyan regiszter tartalmát, amelyet az operációs rendszer és/vagy a megszakítási rutin használ. A kettő együtt valószínűleg mindet használja, úgyhogy legjobb minden regisztert elmenteni. A stack-tartalmakat nem kell, mert az újabb adatok a régiek fölé rétegződnek, így a régiek megmaradnak (nem íródnak felül). Viszont a stack szintjét a megszakítás előtti állapotba kell hozni, tehát a stack-pointer tartalma nem különbözhet a megszakítás előtti értéktől. Végül, a megszakítási rutin nem használhat (pontosabban: nem írhat) olyan memóriaterületet, melyet a program is használ. Ez nem jelentős megszorítás, a mai számítógépekben elég nagy a memória és a megszakítási rutinoknak rendszerint nincs is szükségük nagy munkaterületekre.

2. Az újrahívhatóság (reentrant code)

Jegyezze meg a context és az újrahívhatóság fogalmát;

Ez a fogalom (ha eltekintünk a rekurzív szubrutinhívástól) csak olyan számítógépes rendszerek kapcsán merül fel, ahol virtuálisan párhuzamos módon több program fut egy időben. A számítógépes folyamatirányító rendszerek pontosan ilyenek.

A problémát egy példa kapcsán elemezzük. Tegyük fel, hogy van két program, A és B, valamint egy S szubrutin. A szubrutin olyan műveleteket végez, melyekre mind a két programnak szüksége van, vagyis mindkét program valahol meghívja. Tegyük fel, hogy éppen az A program fut és éppen meghívta a szubrutint, vagyis S most A adataival A-nak dolgozik. Még nem fejezte be a tevékenységét, amikor az operációs rendszer felfüggeszti A futását és B-t engedi futni. B szintén meghívja S-et, akinek a contextje A félig kész adataival van tele. S elkezd B adataival B-nek dolgozni, eközben az A számára korábban készült adatok felülíródnak. Mondjuk S befejezi a munkát B-nek, így B, aki újrahívta S-et, jó eredményeket kap. Most az operációs rendszer visszaadja a vezérlést A-nak, aki előzőleg S-ben futott és természetesen ott is folytatódik a futása. De S contextje most már B adatait tartalmazza, így A számára hibás eredményeket fog előállítani. Azt mondjuk, hogy S ebben az esetben nem volt újrahívható.

Ha S contextje csak a regiszterekre (és a stackre) korlátozódna, vagyis munkaterületként csak ezeket használná, akkor az újrahívás nem járna a fent bemutatott mellékhatással, mert az operációs rendszer két program közti átkapcsoláskor elmenti a felfüggesztett program regisztertartalmait, visszakapcsoláskor pedig visszaállítja. Így amikor S A-nak folytatja a munkát, azokkal az adatokkal folytathatná, amelyekkel abbahagyta, és nem lehetne észrevenni, hogy közben B-nek is dolgozott. Példánkban S contextjének nyilván olyan elemei is voltak, amelyeket átkapcsoláskor nem mentett el az operációs rendszer. Ez pedig csak S által saját célra, munkaterületként lefoglalt fix memóriaterület lehet.

A fentiekből levonható az általános következtetés: ha egy szubrutin munkaterületként csak a regisztereket és a stacket használja, akkor újrahívható, ha fix helyen lévő memóriát is használ, akkor nem. Ha a szubrutinnak szüksége van memóriaterületre, akkor az ne állandó helyen legyen, hanem azt a mindenkori hívó program jelölje ki számára, mert akkor nyilván különböző hívók különböző területeket fognak kijelölni és így nem következhet be ütközés (adat-felülírás).

Megemlítjük még, hogy egy szubrutint akkor is használhat több program, ha nem újrahívható, de akkor szigorúan csak időben egymás után és nem közvetlen hívással, hanem egy - a kölcsönös kizárást biztosító - másfajta mechanizmus segítségével, amiről majd a 6. modulban lesz szó.

3. Az input-output kezelés (I/O)

A leckerész áttanulmányozása után:

  • sorolja fel és jellemezze az I/O portok fajtáit;
  • sorolja fel és egyenként elemezze az I/O-kezelés típusait.

Az input-outputkezelés alatt a számítógép és a perifériák közötti kapcsolat szervezésének módjait értjük.

A számítógépes folyamatirányításban az I/O kezelés fokozott jelentőségre tesz szert azáltal, hogy itt általában lényegesen több perifériát kell kezelni, mint másutt, és az I/O folyamatoknak az egyéb tevékenységekhez viszonyított relatív súlya lényegesen nagyobb, mint más rendszerekben.

A számítógép és a perifériák közötti adatáramlás un. portokon keresztül valósul meg. A portok címezhető logikai elemek, melyek fizikailag a perifériavezérlő egységek regiszterei formájában jelennek meg. Funkcionális szempontból háromféle port van:

  • az állapotport (STATUS),
  • a vezérlőport (CONTROL) és
  • az adatport (DATA).

Állapot- és adatport minden perifériához tartozik, vezérlőportja viszont csak a többfunkciós, változtatható üzemmódú, programozható (un. intelligens) perifériáknak van.

Az állapotporton a periféria aktuális állapotával kapcsolatos információ jelenik meg. Ennek egyes bitjei diagnosztikai jelentőségűek, bizonyos periféria-specifikus hibaokokhoz vannak rendelve (pl. nincs papír a nyomtatóban, nincs festék a nyomtatóban, stb.). Mindig van azonban köztük egy - a periféria fajtájától független - általános, univerzális készültség-bit (READY), melynek 1-es értéke a periféria adatátvitelre való alkalmasságát, 0-értéke pedig alkalmatlanságát jelenti. READY=1 esetén a diagnosztikai biteknek nincs jelentőségük. A READY állapot input perifériánál egyben arra is utal, hogy van érvényes adata, amit be lehet olvasni róla, output perifériánál pedig arra, hogy képes fogadni a kiküldött adatot. A állapotport a processzor szempontjából mindig input-jellegű.

A vezérlőporton a periféria számára az aktuális üzemmódot kijelölő és annak paramétereit beállító parancsok küldhetők ki. Például egy mágneslemezes háttértároló vezérlőegységével közölni kell, hogy a processzor írni, vagy olvasni akar, valamint meg kell adni az adat lemezen értelmezett fizikai címeit. A vezérlőport a processzor szempontjából mindig output-jellegű.

Maga az adatforgalom az adatportokon zajlik le. Az adatportok a periféria jellegétől függően lehetnek input- vagy output-portok.

A ki-/bevitel szervezésének három különböző módja van:

  • a programozott I/O,
  • a megszakításos I/O és
  • a közvetlen memória-hozzáférés (Direct Memory Access, DMA).

A programozott I/O esetén az átvitelt kezdeményező program leolvassa a kiválasztott periféria állapot-portját és megvizsgálja, hogy a periféria READY-állapotban van-e. Ha igen, végrehajtja az adatátvitelt: bevitel esetén beolvassa az adatport tartalmát, kivitelkor pedig kiküldi az adatot az adatportra.. Ha a periféria nem "kész", a program potenciálisan végtelen várakozási hurokba kerül, egészen addig, amíg a READY-bit 1-es nem lesz. A várakozás ideje alatt a program folyamatosan olvassa az állapotportot és vizsgálja a READY-bitet. Ez az aktív várakozás kitölti a processzor teljes idejét, így az semmilyen hasznos tevékenységet nem tud végezni (holott futtathatna olyan programokat, melyeknek pillanatnyilag nincs szükségük az adott perifériára). Ezért az input/output ilyen szervezése több-felhasználós rendszerekben (és ilyen a folyamatirányító rendszer is) szigorúan tilos.

A megszakításos I/O szervezésnél a program nem várakozhat aktívan a nem-kész perifériára. Az operációs rendszer felfüggeszti a futását és a processzor használatát más programnak engedélyezi. Ha közben a felfüggesztett program által igényelt periféria READY-állapotba kerül, azt megszakítással jelzi. Ekkor az operációs rendszer visszaadja a vezérlést a  felfüggesztett programnak, amely most már késedelem nélkül lebonyolíthatja az I/O-műveletet.

A DMA során a processzor már egyáltalán nem vesz részt az adatátvitelben. Egy buszvezérlésre alkalmas (un. intelligens) perifériavezérlő egységet annak vezérlő portján keresztül ellát a szükséges információkkal (az érintett memóriaterület kezdőcíme, az átviendő szavak darabszáma, az átvitel iránya, a periférián értelmezett fizikai címek). Ezek alapján a perifériavezérlő a processzor működésével virtuálisan párhuzamosan (un. cikluslopásokkal),  vagy ténylegesen párhuzamosan (olyankor, amikor a processzor éppen belső műveleteket végez és nem igényli a buszt) önállóan lebonyolítja az adatátvitelt. A folyamat befejeződését egy megszakítással jelzi a processzornak. A DMA megvalósíthatóságának három feltétele van: UNIBUS-struktúra, megszakításrendszer megléte, intelligens perifériavezérlő. (A perifériavezérlő intelligenciája a buszvezérlés, valamint az átvitt adatmennyiség nyilvántartásának képességét jelenti.)

Fel szokott merülni a kérdés: melyik jobb: a megszakításos I/O, vagy a DMA? Azt lehet válaszolni, hogy a két szervezési mód nem ugyanarra való. Ha csak néhány szó (bájt) átviteléről van szó, akkor a megszakításos szervezés a jobb, mert a feldolgozó program közvetlenebbül jut az adatokhoz. (Egy-két, vagy tíz-húsz bájtot DMA-val átvinni nevetséges és roppant körülményes lenne.) És arról se feledkezzünk meg, hogy a legtöbb periféria eleve nem alkalmas a DMA-ra. Ugyanakkor, ha nagy adatmennyiség mozgatására van szükség (pl. képernyőfrissítés, lemezműveletek), akkor a DMA jobb, mert sokszorosan gyorsabb.

Lépjen ki a tananyagból!  Gondolja át a lecke tartalmát, rekonstruálja a szerkezetét! Vegyen elő egy lapot és írja le a lecke vázlatát! Ne sajnálja az erre fordított időt! Ha gondosan megcsinálja, már majdnem tudja is az anyagot.

Önellenőrző kérdések

1. Mondja el saját szavaival a megszakítás és a megszakítási ok és a megszakítási rutin fogalmát!

2. Sorolja fel a megszakításkezelés különböző fajtáit és mondja el a megszakítási folyamat lezajlását! (Minden esetben a gyanútlanul futó főprogramból induljon ki, tapasztalja, hogy becsap a villám, járja végig az ok azonosítási folyamatát, jusson el az okhoz rendelt válaszreakciót realizáló megszakítási rutinhoz, futtassa le a rutint, majd végül kövesse nyomon a főprogramba való visszatérést és legyen tanúja a főprogram felébredésének -továbbfutásának!)

3. Jelölje meg a helyes válaszokat!
A polling ciklus a megszakítási ok azonosítására és az okhoz rendelt megszakítási rutin kiválasztására szolgál.
Minden megszakításrendszerben szükség van a megszakítási ok azonosítására.
Minden megszakításrendszerben szükség van polling ciklusra.
A vektoros megszakításnál a megszakítási ok önmagát azonosítja (bemutatkozik).
A vektoros megszakításnál is szükség van polling ciklusra.
A megszakításvektort (azonosítót) a megszakításkérő eszköz a címbuszon küldi be.
A megszakításvektor azért 'vektor', mert iránya van.
A vektoros megszakítás akkor a leghatékonyabb, ha a megszakításvektor maga a rutin címe, vagy legalább egy rutin-cím tábla indexe.
A pollingos megszakításrendszer hatékonyabb, mert a megszakításrutin gyorsabban aktiválható.
Egy futó megszakítási rutint egy magasabb priorítású  megszakítás megszakíthat.
Egy futó megszakítási rutint egy újabb megszakítás mindig megszakíthat.
A megszakítási ok azonosítása a priorítás megállapítását is magában foglalja.
A priorításos megszakításkezelést általában kiegészítő hardver eszköz segítségével oldják meg, de tisztán szoftver eszközökkel is megoldható.

4. Mondja el saját szavaival a context fogalmát és magyarázza meg, miért rendkívül fontos ez a fogalom a megszakítással kapcsolatban!

5. Mondja el saját szavaival egy szubrutin újrahívhatóságának fogalmát, és fogalmazza meg az újrahívhatóság feltételét. (Három társával el is játszhat egy újrahívási szituációt, demonstrálva annak mindkét lehetséges kimenetelét. Szereposztás: Ön a szubrutin (S), egyik társa az A, a másik a B program, a harmadik az operációs rendszer, aki A és B futását vezérli.)

6. Mondja el az I/O port fogalmát, sorolja fel a portok fajtáit és ismertesse funkcióikat.

7. Sorolja fel az I/O kezelés fajtáit és azok alkalmazási területeit

8. Jelölje meg a helyes állításokat!
Minden perifériának van állapot- és vezérlőportja is.
Az input perifériáknak csak adatportja van.
Az állapotport legfontosabb információját a READY-bit hordozza.
A programozott I/O-szervezés rendkívül egyszerű és minden esetben jól alkalmazható.
Több-felhasználós rendszerekben csak a megszakításos I/O-szervezés használható.
A megszakításos I/O és a DMA minden esetben egyenértékű.
A megszakításos I/O és a DMA funkcionálisan kiegészítik egymást.
A DMA megszakításrendszer nélkül is megvalósítható.
A folyamatirányító rendszerekben a megszakításos I/O-szervezés gyakoribb a DMA-nál.
DMA folyamat lebonyolítására - az egyéb feltételek teljesülése esetén - bármely perifériavezérlő alkalmas.