6. praktikum - Signaalid

Allikas: Lambda
Süsteemprogrammeerimine keeles C

Praktikumid

Laborid

Vaatleme signaale. Signaalid on tarkvarakatkestustele sarnased, kuid neid hallatakse operatsioonisüsteemi tasemel ilma juurkasutaja õiguseid vajamata. Eri signaale eristavad täisarvukonstandid nagu näiteks SIGINT. Igal signaalil on oma number, SIGALRM taimerile, SIGINT katkestussignaalile jne.

Signaalide haldamine POSIX süsteemis toimub kas signal() või sicaction() funktsioonidega. Esimene neist on ebasoovitatav kuid meie õppeotstarbel algul veidi mugavam kogeda. Mõlemad võimaldavad konkreetse signaali jaoks handler funktsiooni registreerimist.

Signaalid klaviatuurilt

Protsessile signaali saatmiseks kasuta kill() süsteemikäsku. Signaali saab käsurealt saata utiliidi 'kill' abil, kui talle anda argumentideks protsessinumber ja signaalinumber. Kuigi seda on hea teada on see seekordse praktikumi mõttes ebamugavam.

Mõningaid signaale saad saata ka klaviatuurilt:

  1. Ctrl-C saadab signaali INT (SIGINT), mis vaikimisi protsessi lõpetab
  2. Ctrl-\ saadab signaali QUIT (SIGQUIT), mis lõpetab protsessi (seadistamisel antakse ka coredump).
  3. Ctrl-Z saadab signaali TSTP (SIGTSTP), mis seiskab programmi ja viib meid käsureale tagasi. Kui soovite programmi taaskäivitada, kirjutage käsureal kas 'fg' (foreground) või 'bg' (background) utiliidi nimi.
  4. Ctrl-S saadab TSTP signaali, kuid käsurida ei anna. Programmi töö jätkamiseks vajuta CTRL+Q. See juhtub mõnikord kogemata kui olete CTRL+S abil salvestama harjunud.

Ülesanne

  1. Kirjuta väike programm mis on lõputus tsüklis ja trükib iga 1/2 sekundi järel punkti (.) (kasuta usleep() ja printf() käske. Lisa reavahetus, sest line-buffering segab muidu punktide ilmumisele vahele. Vaata mis CTRL+C vajutamisel juhtub.
  2. Täienda programmi nii, et ta ^C kinni püüaks. (Väljumine käib CTRL+\ abil (kontrolli kas see töötab; alternatiiv oleks vajutada ^Z ning protsess selle käsu peale väljastatava numbri (PID) abil peatada.
  3. Täienda programmi nii, et ^C vajutamised oleks loetud ning trüki iga vajutamise peale see arv välja.
  4. Kui kirjutasid naiivse programmi (millele loodan), on olemas teoreetiline olukord, milles printf() põhitsüklis parajasti sel hetkel kirjutab kui handler samuti kirjutada soovib. Kuna printf() ei ole re-entrant), võib see põhjustada vea. Selle vea põhjustamine antud programmis pole seni küll kellelgi õnnestunud, aga targemad raamatud on väitnud et see viga on seal olemas. Peame neid usaldama ja harjutusega edasi minema.
  5. Paranda viga signaale printf() ajal blokeerides. Kasuta funktsiooni sigprocmask(), mis maskeerib signaalid. Võib-olla on huvitav vaadata funktsiooni sigemptyset() manuaalilehele. Ära unusta algset signaalikomplekti pärast blokeeringu lõppu taastada. Seda nimetatakse kriitilise lõigu critical section kaitsmiseks. Näita siin tulemust õppejõule ja või salvesta programmist eraldi koopia
  6. Päris programmide puhul ei ole signaalide iga printf() käsu eel blokeerimine otstarbekas. Kirjuta programm ümber nii, et handler määrab globaalmuutuja, millesse signaali saabumisel kirjutatakse 1 ning 0 kui see veel saabunud ei ole. Trüki signaali saabudes saabunud signaalide arv; muul juhul toosama punkt. Ära unusta globaalmuutujat nullida.
Sealjuures tuleb märkida, et ka see lahendus ei ole päris korrektne ning signaale tuleb siiski blokeerida, kuid seekord globaalmuutuja kontrollimise ajaks selleks puhuks kui signaali töötlemise eel kohe järgmine signaal saabuma peaks (st enne, kui muutuja ennistatakse on võimalus, et signaal ära märgib, et ta just saabus ning siis toimuks ennistamine enne kui signaali saabumist märgataks; püüdke seda ette kujutada või nõudke selgitust). See tähendab, et signaalikontrolli hetk on kriitiline lõik ning sel ajal signaali vastu võtta ei saa. Kasuta andmetüübiks 'sig_atomic_t' ning ütle, et muutuja on 'volatile'. Näita tulemust

Sealjuures peab tõe huvides mainima, et reaalselt on signaalide haldamine veelgi keerulisem, sest signaal võib saabuda signaali haldamise hetkel (ja haldusfunktsiooni töö katkestada). Selle parandamiseks tuleb kõik (või osad) signaalid handleri jooksmise ajal samuti blokeerida. Sellest lähtub ka komme handler teha nii lühike kui võimalik ning nende (asünkroonset) saabumist sobival hetkel ise jälgida nagu viimases punktis tegite.

Jõudu tööle; loodetavasti oli huvitav harjutus.