Korutiny, obsluha přerušení od časovače

Úkolem tohoto cvičení je:

Korutiny

Korutiny (coroutines) nebo také kooperující podprogramy je způsob strukturování programu, kde si podprogramy předávají řízení, ale nevolají se navzájem klasickým způsobem.

V klasické struktuře programu existuje asymetrický vztah mezi volajícím programem a jeho podprogramem. Provádění podprogramu začíná vždy na stejném místě (vstupním bodě).

Naproti tomu korutiny se sice navzájem mohou volat, ale jejich vzájemný vztah je symetrický. Při opuštění korutiny se uchová její stav (konkrétně stav jejích proměnných a místo, kde skončilo její provádění). Při příštím spuštění korutiny tato pokračuje přesně v místě, kde bylo provádění ukončeno při předchozím volání.

Před prvním voláním korutiny musí být její stav inicializován. Obvykle tato inicializace vyhradí úsek paměti pro zásobník a připraví ho tak, aby se korutina při prvním spuštění začala provádět od svého začátku.

Každá korutina má svůj soukromý zásobník a přepínání mezi korutinami je prováděno pomocí nastavení nového ukazatele zásobníku. Při přepnutí korutiny jsou uloženy všechny registry do jejího zásobníku, nastaví se nový ukazatel zásobníku a provede se "návrat" do nové korutiny.

Mechanismus korutin se používá například pro simulaci nebo implementaci pseudoparalelních procesů. Pro nás budou korutiny základem, ze kterého budeme při implementaci procesů vycházet.

Poznámka: Pokud si korutina uchovává svůj stav (proměnné) jinde než na zásobníku, můžeme implementovat korutiny i jednodušeji. To má význam zejména tehdy, je-li korutin více (několik set).

Úloha 1: Ověření funkčnosti dodaného modulu

Nejprve prostudujte modul, implementující podporu korutin: krTPU.pas.

Pak napište vlastní program, testující funkčnost modulu podpory korutin.

Poznámka: Tento modul nebylo možné implementovat bez použití částí napsaných v jazyce symbolických adres. Proto zde uvedu význam instrukcí jazyka symbolických adres, které byly při implementaci modulu použity:

MOV cíl, zdroj
Existuje několik variant instrukce MOV, lišících se typem operadů. Přenos může probíhat mezi dvěma 16bitovými nebo 8bitovými registry, nebo mezi pamětí a registrem.

Příklady:

           MOV AX,SLOVO    přesun obsahu 16bitové proměnné slovo do AX
           MOV AL,BAJT     přesun obsahu bytu BAJT do registru AL
           MOV SS,BX       nastavení segmentového registru SS
CLI
Vynulováním příznaku IF zablokuje (zakáže) maskovatelná přerušení.
STI
Nastaví příznak přerušení IF, čímž odblokuje (povolí) přerušení. Nejbližší přerušení může nastat po provedení následující instrukce.
CALL FAR adresa
Volá podprogram na adrese adresa. Instrukce CALL nejprve uloží obsah registru CS a adresu následující instrukce do zásobníku. Poté předá řízení volané proceduře (načte první slovo adresy do registru IP, druhé slovo do registru CS a začne vykonávat první instrukci volané procedury).
RET FAR
Vybere obsah čítače instrukcí IP a registru kódového segmentu CS ze zásobníku. Tím se program vrátí do místa, odkud byla procedura volána.
IRET
Vybere obsah IP a CS podobně jako v intrukci RET. Poté se ze zásobníku načte obsah příznakového registru F (ten byl uložen na zásobník automaticky při přerušení, nebo námi instrukcí PUSHF). Tím se program vrátí do místa, kde byl přerušen.
PUSH reg16
Uloží 16bitový registr na vrcholek zásobníku, a to takto: Obsah ukazatele zásobníku SP je snížen o dvě a obsah určeného registru reg16 je uložen na adresu SS:SP (na adresu SP v rámci segmentu, určeného registrem SS).
POP reg16
Vybere hodnotu z vrcholku zásobníku do zadaného registru. Pak zvýší ukazatel zásobníku SP o dvě.
PUSHF, POPF
Pracují podobně jako instrukce PUSH a POP, ale ukládají/vybírají obsah 16bitového registru příznaků F.

Přerušení od časovače

Většina operačních systémů potřebuje získávat informaci o čase pomocí přerušení, poskytovaných v pravidelných intervalech časovačem. Víceúlohové operační systémy toto přerušení užívají pro odvození časového kvanta po které může běžet proces. Většina systémů z tohoto přerušení odvozuje také informaci o aktuálním čase - systém při každém přerušení časovače zvýší hodnotu proměnné, která udržuje informaci o čase.

V případě počítačů PC je časovačem čítač 0 již popisovaného obvodu 8253, který generuje přibližně 18.2 přerušení za sekundu. Obslužný podprogram přerušení poskytuje BIOS a provádí zvýšení hodnoty čítače času a čítání doby běhu disketové jednotky. Poté volá INT 1CH, které je obslouženo prázdnou obslužnou procedurou přerušení.

Úloha 2: Obsluha přerušení od časovače

(Tato úloha je základem pro to, abychom z korutin vyrobili "procesy" - procedury běžící pseudoparalelně.)

Napište program, který bude provádět obsaluhu přerušení od časovače (přerušení č. 8). Váš program může tikat - při každém desátém přerušení zapnete generování tónu voláním procedury sound a při následujícím přerušení ho vypnete procedurou nosound.

Příkladové řešení úloh


Lukáš Petrlík
luki@kiv.zcu.cz