Vyšlo v týdeníku Computerworld č. 17/93 v roce 1993
Vytištěno z adresy: http://www.earchiv.cz/a93/a317c120.php3

Trap

Mechanismus přerušení, kterým jsme se začali zabývat v minulém příspěvku této rubriky, je velmi obecným mechanismem, který je využíván k mnoha různým účelům.

Reakce na vnější podněty (hlavně na význačné stavy vstupně-výstupních zařízení, stavy čítačů, zásahy uživatele, poruchy hardwaru apod. - viz minule) jsou jen několika příklady, které mají jednoho společného jmenovatele: vznik příčiny takového přerušení bezprostředně nesouvisí s právě prováděným programem a je vůči němu asynchronní (v tom smyslu, že právě probíhající program nemá přímý vliv na to, kdy k žádosti o přerušení dojde). Nejčastěji má příčina takovéhoto přerušení svůj původ vně počítače, či alespoň vně jeho procesoru, a proto se přerušení tohoto typu označují také jako vnější. Určitá příčinná souvislost mezi programem a vnějším přerušením však samozřejmě může existovat: například když si určitý program (proces, úloha) spustí nějakou vstupně-výstupní operaci, po určité době vyvolá tato operace přerušení (ať již z důvodu signalizace svého řádného ukončení, nebo pro indikaci poruchy atd.). Vznik žádosti o přerušení již není ovlivněn tím, co procesor v daném okamžiku dělá - zda ještě provádí te ntýž program, který vstupně-výstupní operaci spustil, nebo zda mezitím přešel na provádění jiného programu.

Další účel, ke kterému se mechanismus přerušení používá, je ošetření různých nestandardních situací při provádění jednotlivých strojových instrukcí. Tedy situací, které již mají přímou a bezprostřední souvislost s právě probíhajícím programem. Jednu možnost jsme si již naznačili při popisu mechanismů segmentace a stránkování: v okamžiku, kdy nějaká strojová instrukce chce číst či zapisovat do stránky (resp. segmentu), která se nenachází v operační paměti, dochází k tzv. výpadku stránky (resp. výpadku segmentu). V provádění dané instrukce však není možné pokračovat, dokud není příslušná stránka (segment) přenesena do paměti. Místo toho je třeba spustit jiný podprogram, který načtení stránky (segmentu) zajistí a pak zase vrátí řízení takovým způsobem, aby se mohla dokončit rozpracovaná, ale nedokončená strojová instrukce, která výpadek způsobila. A to je jak šité na míru mechanismu přerušení.

Výpadek stránky či segmentu je tedy ošetřován pomocí přerušení a toto přerušení je příkladem tzv. vnitřního přerušení, které bezprostředně souvisí s právě prováděným programem a je jím přímo způsobeno. Dalšími příklady mohou být přerušení vyvolaná neznámým operačním znakem (tj. pokusem o provedení neexistující strojové instrukce), chybou v adresování (překročením délky segmentu, použitím nepřípustné kombinace adresovacích registrů apod.), porušením ochranných mechanismů (pokusem o provedení privilegované instrukce v neprivilegovaném stavu, pokusem o přístup do segmentu, ke kterému nemá právě probíhající úloha přístupová práva) apod. Dále sem patří také různá přetečení a podtečení (tedy stavy, kdy výsledek operace nelze umístit do takového počtu bitů, který je k tomu určen). V angličtině se takováto vnitřní přerušení, způsobená právě probíhajícím programem, označují také jako trap (doslova: past, léčka).

Vnitřní a vnější přerušení se ovšem liší i v jiných aspektech, než jen v tom, kde se nachází příčina přerušení (zda "uvnitř" procesoru, nebo "vně"). Významným rozdílem je například to, zda má smysl za určitých okolností ignorovat žádost o přerušení a akceptovat ji až později, nebo zda takováto možnost nepřipadá vůbec v úvahu. Důvody pro dočasné ignorování žádostí o přerušení mohou být různé - například právě probíhající program může v daném okamžiku provádět takové akce, které by neumožnily korektně provést obsluhu přijatého přerušení. Jiným pádným důvodem může být časový skluz, který by nastal přerušením právě probíhajícího programu a obsluhou přerušení. A co v případě, kdy během obsluhy jedné žádosti o přerušení přijde další žádost o přerušení? Má být pozdržena až do doby, kdy skončí právě probíhající obsluha, nebo může být obslužný program sám přerušen, a jednotlivá přerušení tedy dynamicky vnořována do sebe?

V případě vnějších přerušení má smysl, aby existovala možnost dočasně zabránit uplatnění žádostí o přerušení - tedy tzv. maskování žádostí o přerušení. V principu je možné maskovat všechny žádosti bez rozdílu nebo jednotlivé žádosti individuálně. Odlišný může být také účinek maskování - zamaskovaná žádost může být jednoduše ignorována, a je pak na žadateli, aby svou žádost uplatňoval tak dlouho, dokud nebude tzv. odmaskována a skutečně přijata. Alternativou je takový způsob maskování, při kterém jsou momentálně zamaskované žádosti zaznamenávány a automaticky uplatňovány (nyní již bez přímé účasti původního žadatele) v okamžiku, kdy dojde k jejich odmaskování.

V případě vnitřních přerušení však maskování nemá smysl. Co kdyby například právě probíhající úloha způsobila výpadek stránky a příslušné přerušení bylo zamaskováno? Jak by se měl zachovat procesor v případě, kdy narazí na neznámou strojovou instrukci, ale příslušné přerušení by bylo zamaskováno? Takovéto otázky bychom si mohli klást dlouho, ale jsou vlastně bezpředmětné, neboť vnitřní přerušení obvykle není možné maskovat.

Dalším rozdílem mezi vnějším a vnitřním přerušením je i přesný časový okamžik, kdy dochází k jejich přijetí, a tím i ke spuštění příslušného obslužného programu. Zde je dobré si uvědomit, a to hlavně u vnějších přerušení, že obslužný program nemusí nijak souviset s tím programem, který právě probíhá v okamžiku uplatnění žádosti, a který je tudíž přerušen. Z pohledu tohoto programu musí být veškerá obsluha přerušení plně transparentní - program by neměl vůbec poznat, že byl přerušen. To ovšem znamená, že obslužný program přerušení musí bezprostředně před svým skončením uvést procesor přesně do takového stavu, v jakém jej nalezl při svém spuštění, resp. v jakém jej zanechal přerušený program. To se týká především obsahu těch registrů a nastavení jednotlivých příznaků, které obslužný program sám mění, a které tudíž musí sám vhodně uschovat a před svým ukončením zase obnovit. K tomu je ovšem nezbytně nutné, aby obsah těchto registrů a příznaků byl v okamžiku přijetí přerušení jednoznačně definován. Z to hoto důvodu jsou všechny žádosti o vnější přerušení přijímány zásadně jen mezi dvěma strojovými instrukcemi - přesněji ihned po dokončení jedné strojové instrukce, dříve než je zahájeno provádění instrukce následující.

V případě některých vnitřních přerušení však takováto strategie není dost dobře možná - jestliže nějaká instrukce způsobí výpadek stránky, není možné ji nejprve dokončit a teprve pak výpadek stránky ošetřit. Procesor naopak musí co možná nejrychleji rozpoznat situaci, která vyžaduje přerušení, právě prováděnou instrukci přerušit "uprostřed" a po dokončení obsluhy ji provést celou znovu. K tomu je ovšem nutné ještě to, aby k přerušení došlo dříve, než instrukce stačí udělat takovou akci, kterou již nelze opakovat, případně vrátit zpátky.

Pro jiné druhy vnitřního přerušení však tato úvaha nemusí platit. Například když strojová instrukce způsobí přetečení (při ukládání výsledku) a na tuto skutečnost má být reagováno přerušením. V takovém případě je možné uložit výsledek vhodně zaokrouhlený (či "ořezaný") a s přerušením počkat až na dokončení instrukce. Samostatnou kapitolou jsou z tohoto pohledu takové instrukce, které příčinu k vnitřnímu přerušení zavdávají nikoli "nechtěně", jak jsme až doposud uvažovali, ale naopak zcela záměrně. Ale o tom až příště.