OPERÁCIÓS RENDSZEREK Eseménykezelés, szignálozás A mai program Alapfogalmak: esemény, jelződés, kezelés Megszakítások és kivételek Szignálozás Rendelkezés szignálról (SVID, POSIX) Postázás Esettanulmányok Vadász 2 Hiba és eseménykezelés. Alapfogalmak. Esemény: folyamatok (taszk, processz, fonál, rutin, utasítás, instrukció) futását befolyásoló, váratlan időpontban bekövetkező történés, amire reagálni kell (le kell kezelni). Feltétel állapot: egy állapottér állapotvektora. Jelzés keletkezik, ha a feltétel - az esemény - bekövetkezik. Jelződik az esemény. A jelződés az alapja a lekezelhetőségnek: ami kapja a jelzést, az lekezelheti az eseményt. Vadász 3 1
Az esemény jelződik: lekezelhető A lekezelés megváltoztatja a futás menetét: a normális futás mentét abba kell hagyni (Instrukciót? Utasítást? Rutint? Fonalat? Processzt? Taszkot?) Lekezelni instrukciófolyammal, rutinnal, fonállal, processzel. Dönteni, visszaadható-e a vezérlés (instrukcióra, utasításra, rutinba/fonálba/processzbe; [elejére, végére], vagy utánuk?), vagy az OS-nek adjuk a vezérlést? Vadász 4 Az események osztályai Egy processz szemszögéből belső esemény, külső esemény. Előállítója szerint HW által generált és detektált (IT, errors), SW által generált és detektált: SWIT, SW által generált kivétel, felhasználói akciók). Lekezelési szintjük szerint megszakítások (interrupts, IT), kivételek (exeptions), alkalmazás által kezelt események (felhasználói akciók). Vadász 5 Megszakítások A legalacsonyabb szintű események. Aszinkron. Külső. Előállítója rendszerint a HW, de lehet SW is. Lekezelői: az OS kernel IT handlerei. Kezelés módja: aktuális instrukció befejeződik, a lekezelő fut, soron következő instrukcióra tér vissza. IT prioritási szintek vannak. Le nem kezelt megszakítások HW-es sorokon várakoznak (pending ITs). Vadász 6 2
Kivételek, hibaesemények (exeptions) Abnormális helyzetet, gondot jelentenek. Szinkron jellegűek, de váratlanok. Lehetnek alacsony szintűek: túlcsordulás, Lehetnek magas szintűek: pl. laphiba. Az alacsony, magas szint megmondja minek szól a jelzés (instrukciónak,... processznek), a kezelés szintjét is. A klasszikus kivételnél: az entitás nem fejezhető be! Ha hatásosan lekezelhető, az entitás futását meg kell ismételni. Az OS-ekben vannak alapértelmezési kezelők. A programozó is lekezelhet egyes kivételeket (értelmet nyer a magasabb jelző, veszít a hiba jelző) Vadász 7 Alkalmazás által kezelt események Bekövetkezésüket a programozó eleve várja (de váratlanok időben). Tipikus példa: X11 vagy más GUI-is. Alkalmazás eseményvezérelt programozása. Magas szintűek: Fejlesztő eszközök kellenek (RTL rutinok), programozó maszkolhatja őket, lekezelő rutinjait ő írja meg, az eseménysorokat figyelheti. Kezelésükhöz használhatja az IT- és kivétel-kezelési technikákat. Vadász 8 Megszakítások versus kivételek Az IT aszinkron. Két instrukció között kiszolgálódnak. A kivétel váratlan, de szinkron (az adott instrukcióhoz tartozik). Tipikus a laphiba. Az IT nem kapcsolódik a futó processzhez (kiszolgálása nem a futó processz javára). A kivétel kiszolgálása kiegészítése a processz instrukciófolyamának. Vadász 9 3
Megszakítások - kivételek Az IT kiszolgálásnál prioritási szintek. Maszkolás. Kiszolgálásuk is megszakítható. HW-es a sorképzés. A kivételek kiszolgálását más kivétel nem szakíthatja meg. IT kiszolgálásra lehet közös rendszer verem. A kivétel kiszolgálására rendszerint processzenkénti kernel verem. Vadász 10 A jelzés fogalom Jelzés (signal) keletkezik feltétel állapot kialakulásakor (esemény bekövetkezésekor): a jelződés a fontos. A tárgyalás ekkor: van egy jelzés készlet; jelzés keletkezik HW vagy SW eredetből. A jelzés kikézbesítődik (CPU-nak, processznek). A kikézbesített jelzések sorokban várhatnak lekezelésre. A kikézbesített jelzéseket e megfelelő kezelő (handler) lekezeli. Ez a szignál fogalom tágabb értelmezése. Vadász 11 Szignálozás: szűkebb értelem Bizonyos szignálokat az OS küld és kezel le; de mi is küldhetünk, mi is kezelhetünk: szignálozással megszakításokat küldhetünk processzeknek. (A küldött szignál a processzeknek, az IT a CPU-nak szól.) A szignálozás kapcsolódik a processz állapotokhoz, állapotátmenetekhez. Blokkolt egy processz egy eseményen: szignál billenti futásra kész állapotba (pl. bufferre vár, lehet, hogy az IT kezelő küldi a szignált). Hogy értesül egy processz a szignálról? Hogy kezeli le azt? A vezérlés reakciója? Vadász 12 4
A szignál: jelzése egy eseménynek Generálódik (mikor az esemény bekövetkezik), elküldik egy processznek. A szignál diszpozíció fogalom (egy processz specifikálhatja, milyen rendszerakció menjen végbe a neki küldött szignálokra). Lehet: alapértelmezési akció, ignorálás (figyelmen kívül hagyás), saját kezelő kezelje. Kikézbesített szignál fogalom (amikor az akció beindul. Generálódás és kikézbesítés között idő telhet el). Függő szignál (pending signal) (generálódott, de még nem kézbesült ki. Külön érdekes a blokkolt függő szignál!) Vadász 13 Szignálozás SVID Unixban A kernel a szignál kézbesítéséhez A PCB egy mezejét beállítja. A processz a kernel módból való visszatéréskor ellenőrzi a mezőket: lekezel, ha van mit. A szignálkezelő alapértelmezésben: Legtöbbször terminálja a processzt, néha core dump-ot ad. Adhat hibajelzést a stderr-en, és utána terminál. Hatásosan lekezeli a szignált és folytatódhat a futás. Bizonyos szignálok kezelését a felhasználó programozó átveheti. Bizonyos szignálokat a programozó küldhet. Vadász 14 A felhasználó szignálkezelési lehetőségei Kérheti, hogy ignorálódjon (ekkor is kézbesül!) Kérheti, fusson saját kezelő függvény Kérheti, álljon vissza az alapértelmezés Postázhat bizonyos szignálokat (más processzeknek, de saját magának is) A lekezelhető és küldhető szignálkészlet majdnem egybeesik A szignálozást használhatja: szinkronizációra, kommunikációra. Vadász 15 5
Szignálozással kapcsolatos API 1 Nézd a /usr/include/sys/signal.h header fájlt! Ebben: Makrók, system call prototype-ok. # define SIGHUP 1 # define SIGINT 2... # define SIGALRM 14 # define SIG_IGN (void(*)()) 0 # define SIG_DFL (void(*)()) 1 stb. Vadász 16 Linux man 7 signal részlet Signal Value Action Comment ------------------------------------------------------------------------- SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling process SIGINT 2 Term Interrupt from keyboard SIGQUIT 3 Core Quit from keyboard SIGILL 4 Core Illegal Instruction SIGABRT 6 Core Abort signal from abort(3) SIGFPE 8 Core Floating point exception SIGKILL 9 Term Kill signal SIGSEGV 11 Core Invalid memory reference SIGPIPE 13 Term Broken pipe: write to pipe with no readers SIGALRM 14 Term Timer signal from alarm(2) SIGTERM 15 Term Termination signal SIGUSR1 30,10,16 Term User-defined signal 1 SIGUSR2 31,12,17 Term User-defined signal 2 SIGCHLD 20,17,18 Ign Child stopped or terminated SIGCONT 19,18,25 Continue if stopped SIGSTOP 17,19,23 Stop Stop process SIGTSTP 18,20,24 Stop Stop typed at tty SIGTTIN 21,21,26 Stop tty input for background process SIGTTOU 22,22,27 Stop tty output Vadász for background process 17 Szignálozással kapcsolatos API 2 A signal() rendszerhívás [POSIX: sigaction()] void (*signal( )) ( ); A signal egy függvény, ami egy függvényre mutató pointerrel tér vissza. Ennek visszatérése pedig void. A szignál diszpozíció precízebben : void (*signal(int sig, void (*func)(int,..)))(int,..); A sig szignált a func függvény kezelje le. Siker esetén az előző lekezelő függvény címével, hiba esetén SIG_ERR értékkel tér vissza. Mind a func-nak, mind a visszatérési függvénynek lehetnek int argumentumai. Fontos! Saját kezelőre diszponált szignál bekövetkezése (és kezelése) után sok rendszerben visszaáll az alapértelmezett diszpozíció! Vadász 18 6
Szignálozással kapcsolatos API 3 A sigaction( ) rendszerhívás is dispozíció! POSIX stílusú. int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact); Ahol a struct sigaction-nak van void (*sa_handler) (int); tagja. Ez a tag veheti fel az új és a régi kezelő címét. Vadász 19 Szignálozással kapcsolatos API 4 A kill() rendszerhívás [POSIX: sigsend()] int kill(pid_t pid, int sig); Küldjön sig szignált a pid processznek. Siker esetén 0-val, sikertelenség esetén -1-gyel tér vissza. Hasznos még a raise(), a pause(), az alarm(), a sigprocmask(), a sigsuspend(), a sigsetjmp() és a siglongjmp() rendszerhívás is. Vadász 20 Esettanulmányok, gyakorlatok Nézzék az www.iit.uni-miskolc.hu/iitweb/opencms/users/dvadasz helyen /signals/alarmra-var1.c és /signals/alarmra-var2.c példaprogramokat! Nézzék az /signals/alarm-ado1.c és /signals/alarm-ado2.c példaprogramokat! Vadász 21 7
#include <signal.h> void handler(int); /* one handler for both signals */ main(void) { if(signal(sigusr1,handler)==sig_err) exit(0); if(signal(sigusr2,handler)==sig_err) exit(1); for ( ; ; ) pause(); void handler(int signo) { /* arg is signal no */ if (signo==sigusr1) printf("received SIGUSR1\n"); else if (signo==sigusr2) printf("received SIGUSR2\n"); else exit(2); return; 1 kezelő 2 szignálhoz Vadász 22 Tanulmányozandó még... A sigprocmask()-hoz: létezik globális szignál maszk, ez definiálja, mely szignálok blokkoltak. A sigsetjmp() és siglongjmp() érdekességek: int sigsetjmp(sigjmp_buf env[, int savemask]); void siglongjmp(sigjmp_buf env[, int val]); A sigsetjmp lementi a C-stack-et és a regisztereket az env-be. Kétszer tér vissza! Először 0-val (direkt hívásakor), másodszor - a siglongjmp hívásával történő visszavétel miatt a val értékkel (ha az 0, akkor 1- gyel) A siglongjmp() visszaveszi a regisztereket, a stack-et, és a val értékkel tér vissza (amit nem 0-ra állítunk). Vadász 23 Példa #include <setjmp.h> jmp_buf env; int i = 0; main ( ) { if (setjmp(env)!= 0) { (void) printf("2nd from setjmp: i=%d\n", i); exit(0); (void) printf("1st from setjmp: i=%d\n", i); i = 1; g( ); /*NOTREACHED*/ g( ) { longjmp(env, 1); /*NOTREACHED*/ Vadász 24 8
A példa eredménye The program's output is: 1st from setjmp:i=0 2nd from setjmp:i=1 Vadász 25 További esetek.. Stevens példája a /signals/abort.c Írtunk saját abort() függvényt. Azt nem lehet ignorálni, nem lehet kezelését átvenni, és nem lehet blokkolni sem. Elemezzük. Vadász 26 OPERÁCIÓS RENDSZEREK Eseménykezelés, szignálozás Vége 9